mirror of
https://github.com/nax1800/Athena.git
synced 2026-08-26 19:43:33 +00:00
378 lines
15 KiB
C++
378 lines
15 KiB
C++
#pragma once
|
|
#include "framework.h"
|
|
|
|
namespace PlayerController
|
|
{
|
|
static void* (*ApplyCharacterCustomization)(void* a1, void* a2) = decltype(ApplyCharacterCustomization)(Memory::GetAddress(0x1348d00));
|
|
void hkServerAcknowledgePossession(AFortPlayerControllerAthena* PlayerController, APawn* Pawn)
|
|
{
|
|
if (!PlayerController)
|
|
return;
|
|
|
|
auto PlayerState = static_cast<AFortPlayerStateAthena*>(PlayerController->PlayerState);
|
|
auto FortPawn = static_cast<APlayerPawn_Athena_C*>(Pawn);
|
|
|
|
if (!PlayerState || !FortPawn)
|
|
return;
|
|
|
|
PlayerController->AcknowledgedPawn = FortPawn;
|
|
|
|
if (Globals::bNoMCP || PlayerState->bIsABot)
|
|
{
|
|
static auto HeadPart = StaticFindObject<UCustomCharacterPart>(L"/Game/Characters/CharacterParts/Female/Medium/Heads/F_Med_Head1.F_Med_Head1");
|
|
static auto BodyPart = StaticFindObject<UCustomCharacterPart>(L"/Game/Characters/CharacterParts/Female/Medium/Bodies/F_Med_Soldier_01.F_Med_Soldier_01");
|
|
|
|
PlayerState->CharacterParts.Parts[0] = HeadPart;
|
|
PlayerState->CharacterParts.Parts[1] = BodyPart;
|
|
|
|
PlayerState->OnRep_CharacterParts();
|
|
return;
|
|
}
|
|
|
|
auto& CustomizationLoadout = PlayerController->CustomizationLoadout;
|
|
|
|
if (!CustomizationLoadout.Character || !CustomizationLoadout.Character->HeroDefinition)
|
|
return;
|
|
|
|
FortPawn->CustomizationLoadout = CustomizationLoadout;
|
|
FortPawn->OnRep_CustomizationLoadout();
|
|
|
|
PlayerState->HeroType = CustomizationLoadout.Character->HeroDefinition;
|
|
PlayerState->OnRep_HeroType();
|
|
|
|
ApplyCharacterCustomization(PlayerState, FortPawn);
|
|
}
|
|
|
|
void (*oServerReadyToStartMatch)(AFortPlayerControllerAthena* PlayerController);
|
|
void hkServerReadyToStartMatch(AFortPlayerControllerAthena* PlayerController)
|
|
{
|
|
if (!PlayerController)
|
|
return oServerReadyToStartMatch(PlayerController);
|
|
|
|
auto PlayerState = static_cast<AFortPlayerStateAthena*>(PlayerController->PlayerState);
|
|
if (!PlayerState)
|
|
return oServerReadyToStartMatch(PlayerController);
|
|
|
|
AbilitiesHandler::ApplyAbilities(PlayerState);
|
|
|
|
PlayerState->SquadId = (int)PlayerState->TeamIndex - 2;
|
|
PlayerState->OnRep_PlayerTeam();
|
|
PlayerState->OnRep_SquadId();
|
|
|
|
if (!Globals::bIsFloorLootSpawned)
|
|
{
|
|
Globals::bIsFloorLootSpawned = true;
|
|
// Looting::SpawnFloorLoot();
|
|
auto PlayerStarts = Utils::GetActorsOfClass(APlayerStart::StaticClass());
|
|
if (PlayerStarts.IsValid())
|
|
{
|
|
for (int i = 0; i < Globals::BotsToSpawn;)
|
|
{
|
|
auto PlayerStart = PlayerStarts[rand() % PlayerStarts.Num()];
|
|
if (PlayerStart)
|
|
{
|
|
auto hero = StaticLoadObject<UFortHeroType>(L"/Game/Athena/Heroes/HID_080_Athena_Commando_M_Space.HID_080_Athena_Commando_M_Space");
|
|
auto bot = AI::AthenaBot(PlayerStart->K2_GetActorLocation(), AI::GetRandomBotName(), hero);
|
|
AI::Bots.push_back(bot);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return oServerReadyToStartMatch(PlayerController);
|
|
}
|
|
|
|
void (*oServerLoadingScreenDropped)(AFortPlayerControllerAthena* PlayerController);
|
|
void hkServerLoadingScreenDropped(AFortPlayerControllerAthena* PlayerController)
|
|
{
|
|
if (!reinterpret_cast<AFortPlayerStateAthena*>(PlayerController->PlayerState)->bIsABot)
|
|
InventoryHandler::Setup(PlayerController);
|
|
|
|
return oServerLoadingScreenDropped(PlayerController);
|
|
}
|
|
|
|
void hkServerExecuteInventoryItem(AFortPlayerControllerAthena* PlayerController, FGuid ItemGuid)
|
|
{
|
|
if (!PlayerController)
|
|
return;
|
|
|
|
auto Pawn = static_cast<AFortPlayerPawn*>(PlayerController->Pawn);
|
|
if (!Pawn)
|
|
return;
|
|
|
|
FFortItemEntry* FoundItemEntry = InventoryHandler::FindItem(PlayerController, ItemGuid);
|
|
if (!FoundItemEntry)
|
|
return;
|
|
|
|
auto ItemDefinition = static_cast<UFortWeaponItemDefinition*>(FoundItemEntry->ItemDefinition);
|
|
if (!ItemDefinition->IsA(UFortTrapItemDefinition::StaticClass()))
|
|
{
|
|
Pawn->EquipWeaponDefinition(ItemDefinition, ItemGuid);
|
|
return;
|
|
}
|
|
|
|
auto DecoDefinition = static_cast<UFortDecoItemDefinition*>(ItemDefinition);
|
|
Pawn->PickUpActor(Pawn, DecoDefinition);
|
|
Pawn->CurrentWeapon->ItemEntryGuid = ItemGuid;
|
|
|
|
if (auto ContextTrapTool = reinterpret_cast<AFortDecoTool_ContextTrap*>(Pawn->CurrentWeapon))
|
|
ContextTrapTool->ContextTrapItemDefinition = static_cast<UFortContextTrapItemDefinition*>(ItemDefinition);
|
|
}
|
|
|
|
void (*oEnterAircraft)(AFortPlayerControllerAthena* PlayerController, unsigned __int64 a2);
|
|
void hkEnterAircraft(AFortPlayerControllerAthena* PlayerController, unsigned __int64 a2)
|
|
{
|
|
if (!PlayerController || reinterpret_cast<AFortPlayerStateAthena*>(PlayerController->PlayerState)->bIsABot)
|
|
return oEnterAircraft(PlayerController, a2);
|
|
|
|
TArray<FFortItemEntry>& ReplicatedEntries = PlayerController->WorldInventory->Inventory.ReplicatedEntries;
|
|
for (int i = 0; i < ReplicatedEntries.Num(); i++)
|
|
{
|
|
if (static_cast<UFortWorldItemDefinition*>(ReplicatedEntries[i].ItemDefinition)->bCanBeDropped)
|
|
InventoryHandler::RemoveItem(PlayerController, ReplicatedEntries[i].ItemGuid);
|
|
}
|
|
|
|
return oEnterAircraft(PlayerController, a2);
|
|
}
|
|
|
|
bool(__fastcall* CantBuild)(UWorld*, UObject*, FVector, FRotator, char, void*, char*) = decltype(CantBuild)(Memory::GetAddress(0xf9c0a0));
|
|
void hkServerCreateBuildingActor(AFortPlayerControllerAthena* PlayerController, FBuildingClassData& BuildingClassData, FVector_NetQuantize10& BuildLoc, FRotator& BuildRot, bool bMirrored)
|
|
{
|
|
if (!PlayerController)
|
|
return;
|
|
|
|
auto PlayerState = reinterpret_cast<AFortPlayerStateAthena*>(PlayerController->PlayerState);
|
|
if (!PlayerState)
|
|
return;
|
|
|
|
auto Class = BuildingClassData.BuildingClass.Get();
|
|
TArray<AActor*> BuildingActorsToDestroy;
|
|
char Result;
|
|
|
|
if (CantBuild(Globals::GetWorld(), Class, BuildLoc, BuildRot, bMirrored, &BuildingActorsToDestroy, &Result))
|
|
{
|
|
BuildingActorsToDestroy.Free();
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < BuildingActorsToDestroy.Num(); i++)
|
|
{
|
|
BuildingActorsToDestroy[i]->K2_DestroyActor();
|
|
}
|
|
|
|
auto NewBuilding = Spawner::SpawnActor<ABuildingSMActor>(Class, BuildLoc, BuildRot);
|
|
if (!NewBuilding)
|
|
return;
|
|
|
|
NewBuilding->InitializeKismetSpawnedBuildingActor(NewBuilding, PlayerController, true);
|
|
NewBuilding->bPlayerPlaced = true;
|
|
NewBuilding->Team = PlayerState->TeamIndex;
|
|
NewBuilding->OnRep_Team();
|
|
|
|
if (!PlayerController->bBuildFree)
|
|
InventoryHandler::RemoveItem(PlayerController, UFortKismetLibrary::K2_GetResourceItemDefinition(NewBuilding->ResourceType), 10);
|
|
}
|
|
|
|
void hkServerBeginEditingBuildingActor(AFortPlayerController* PlayerController, ABuildingSMActor* BuildingActorToEdit)
|
|
{
|
|
if (!PlayerController || !BuildingActorToEdit)
|
|
return;
|
|
|
|
auto Pawn = static_cast<AFortPlayerPawnAthena*>(PlayerController->Pawn);
|
|
if (!Pawn)
|
|
return;
|
|
|
|
static auto EditToolDef = StaticFindObject<UFortItemDefinition>(L"/Game/Items/Weapons/BuildingTools/EditTool.EditTool");
|
|
if (Pawn->CurrentWeapon->WeaponData != EditToolDef)
|
|
{
|
|
FFortItemEntry* Entry = InventoryHandler::FindItem(PlayerController, EditToolDef);
|
|
PlayerController->ServerExecuteInventoryItem(Entry->ItemGuid);
|
|
}
|
|
|
|
auto EditTool = reinterpret_cast<AFortWeap_EditingTool*>(Pawn->CurrentWeapon);
|
|
EditTool->EditActor = BuildingActorToEdit;
|
|
EditTool->OnRep_EditActor();
|
|
BuildingActorToEdit->EditingPlayer = static_cast<AFortPlayerStateAthena*>(PlayerController->PlayerState);
|
|
BuildingActorToEdit->OnRep_EditingPlayer();
|
|
}
|
|
|
|
static ABuildingSMActor* (*oBuildingSMActorReplaceBuildingActor)(ABuildingSMActor*, __int64, UClass*, int, int, uint8_t, AFortPlayerController*) = decltype(oBuildingSMActorReplaceBuildingActor)(Memory::GetAddress(0xdad4c0));
|
|
void (*oServerEditBuildingActor)(AFortPlayerController* PlayerController, ABuildingSMActor* BuildingActorToEdit, UClass* NewBuildingClass, uint8 RotationIterations, bool bMirrored);
|
|
void hkServerEditBuildingActor(AFortPlayerController* PlayerController, ABuildingSMActor* BuildingActorToEdit, UClass* NewBuildingClass, uint8 RotationIterations, bool bMirrored)
|
|
{
|
|
if (!PlayerController)
|
|
return oServerEditBuildingActor(PlayerController, BuildingActorToEdit, NewBuildingClass, RotationIterations, bMirrored);
|
|
|
|
auto PlayerState = static_cast<AFortPlayerStateAthena*>(PlayerController->PlayerState);
|
|
if (!PlayerState)
|
|
return oServerEditBuildingActor(PlayerController, BuildingActorToEdit, NewBuildingClass, RotationIterations, bMirrored);
|
|
|
|
if (BuildingActorToEdit && NewBuildingClass)
|
|
{
|
|
FVector BuildLocation = BuildingActorToEdit->K2_GetActorLocation();
|
|
|
|
float HealthPercent = BuildingActorToEdit->GetHealthPercent();
|
|
if (auto BuildingActor = oBuildingSMActorReplaceBuildingActor(BuildingActorToEdit, 1, NewBuildingClass, BuildingActorToEdit->GetCurrentBuildingLevel(), RotationIterations, bMirrored, PlayerController))
|
|
{
|
|
BuildingActor->bPlayerPlaced = true;
|
|
}
|
|
}
|
|
|
|
return oServerEditBuildingActor(PlayerController, BuildingActorToEdit, NewBuildingClass, RotationIterations, bMirrored);
|
|
}
|
|
|
|
void hkServerEndEditingBuildingActor(AFortPlayerController* PlayerController, ABuildingSMActor* BuildingActorToStopEditing)
|
|
{
|
|
if (!PlayerController || !BuildingActorToStopEditing)
|
|
return;
|
|
|
|
auto Pawn = static_cast<APlayerPawn_Athena_C*>(PlayerController->Pawn);
|
|
if (!Pawn)
|
|
return;
|
|
|
|
BuildingActorToStopEditing->EditingPlayer = nullptr;
|
|
BuildingActorToStopEditing->OnRep_EditingPlayer();
|
|
|
|
AFortWeap_EditingTool* EditTool = static_cast<AFortWeap_EditingTool*>(Pawn->CurrentWeapon);
|
|
if (!EditTool)
|
|
return;
|
|
|
|
EditTool->bEditConfirmed = true;
|
|
EditTool->EditActor = nullptr;
|
|
EditTool->OnRep_EditActor();
|
|
}
|
|
|
|
void hkServerPlayEmoteItem(AFortPlayerController* PlayerController, UFortMontageItemDefinitionBase* EmoteAsset)
|
|
{
|
|
if (!PlayerController || !EmoteAsset)
|
|
return;
|
|
|
|
auto PlayerState = static_cast<AFortPlayerStateAthena*>(PlayerController->PlayerState);
|
|
auto Pawn = static_cast<APlayerPawn_Athena_C*>(PlayerController->Pawn);
|
|
|
|
if (!PlayerState || !Pawn)
|
|
return;
|
|
|
|
UFortAbilitySystemComponent* AbilitySystemComponent = PlayerState->AbilitySystemComponent;
|
|
|
|
static UObject* AbilityToUse = UGAB_Emote_Generic_C::StaticClass()->DefaultObject;
|
|
bool bShouldBeAbilityToUse = false;
|
|
|
|
FGameplayAbilitySpec Spec{};
|
|
AbilitiesHandler::SpecConstructor(&Spec, AbilityToUse, 1, -1, EmoteAsset);
|
|
AbilitiesHandler::oGiveAbilityAndActivateOnce(AbilitySystemComponent, &Spec.Handle, Spec);
|
|
}
|
|
|
|
static void (*RemoveFromAlivePlayers)(AFortGameModeAthena* GameMode, AFortPlayerController* PlayerController, APlayerState* PlayerState, APawn* FinisherPawn, UFortWeaponItemDefinition* FinishingWeapon, uint8_t DeathCause, char a7) = decltype(RemoveFromAlivePlayers)(Memory::GetAddress(0xcb5360));
|
|
void (*oClientOnPawnDied)(AFortPlayerControllerZone*, FFortPlayerDeathReport);
|
|
void hkClientOnPawnDied(AFortPlayerControllerAthena* PlayerController, FFortPlayerDeathReport DeathReport)
|
|
{
|
|
if (!PlayerController)
|
|
return;
|
|
|
|
auto DeadPawn = static_cast<AFortPlayerPawnAthena*>(PlayerController->Pawn);
|
|
auto DeadPlayerState = static_cast<AFortPlayerStateAthena*>(PlayerController->PlayerState);
|
|
auto KillerPlayerState = static_cast<AFortPlayerStateAthena*>(DeathReport.KillerPlayerState);
|
|
auto KillerPawn = static_cast<AFortPlayerPawnAthena*>(DeathReport.KillerPawn);
|
|
if (!DeadPawn || !DeadPlayerState)
|
|
return oClientOnPawnDied(PlayerController, DeathReport);
|
|
|
|
if (KillerPawn && KillerPlayerState && KillerPlayerState != DeadPlayerState)
|
|
{
|
|
KillerPlayerState->KillScore++;
|
|
KillerPlayerState->ClientReportKill(DeadPlayerState);
|
|
KillerPlayerState->OnRep_Kills();
|
|
}
|
|
|
|
FDeathInfo DeathData;
|
|
DeathData.bDBNO = DeadPawn->IsDBNO();
|
|
DeathData.DeathLocation = DeadPawn->K2_GetActorLocation();
|
|
DeathData.Distance = DeathReport.KillerPawn ? DeathReport.KillerPawn->GetDistanceTo(DeadPawn) : 0;
|
|
DeathData.DeathCause = DeadPlayerState->ToDeathCause(DeathReport.Tags, false);
|
|
DeathData.FinisherOrDowner = KillerPlayerState ? KillerPlayerState : DeadPlayerState;
|
|
|
|
DeadPlayerState->DeathInfo = DeathData;
|
|
DeadPlayerState->OnRep_DeathInfo();
|
|
|
|
if (DeadPawn->IsDBNO())
|
|
return oClientOnPawnDied(PlayerController, DeathReport);
|
|
|
|
oClientOnPawnDied(PlayerController, DeathReport);
|
|
|
|
AActor* DamageCauser = DeathReport.DamageCauser;
|
|
UFortWeaponItemDefinition* KillerWeaponDef = nullptr;
|
|
|
|
AFortInventory* WorldInventory = PlayerController->WorldInventory;
|
|
if (WorldInventory)
|
|
{
|
|
auto& ReplicatedEntries = WorldInventory->Inventory.ReplicatedEntries;
|
|
if (ReplicatedEntries.IsValid())
|
|
{
|
|
for (int i = 0; i < ReplicatedEntries.Num(); i++)
|
|
{
|
|
if (ReplicatedEntries.IsValidIndex(i))
|
|
{
|
|
if (auto ItemDefinition = static_cast<UFortWorldItemDefinition*>(ReplicatedEntries[i].ItemDefinition))
|
|
{
|
|
if (ItemDefinition->bCanBeDropped)
|
|
Utils::SpawnPickup(ItemDefinition, ReplicatedEntries[i].Count, ReplicatedEntries[i].LoadedAmmo, DeadPawn->K2_GetActorLocation(), DeadPawn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (DeathData.DeathCause != EDeathCause::Unspecified && DeathData.DeathCause != EDeathCause::FallDamage && DeathData.DeathCause != EDeathCause::OutsideSafeZone && DamageCauser)
|
|
{
|
|
if (DamageCauser->IsA(AFortProjectileBase::StaticClass()))
|
|
{
|
|
auto ProjectileBase = static_cast<AFortProjectileBase*>(DamageCauser);
|
|
if (Utils::IsValidLowLevel(ProjectileBase->Owner))
|
|
{
|
|
auto Weapon = static_cast<AFortWeapon*>(ProjectileBase->Owner);
|
|
if (Weapon->WeaponData)
|
|
KillerWeaponDef = Weapon->WeaponData;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
if (auto Weapon = static_cast<AFortWeapon*>(DamageCauser))
|
|
{
|
|
KillerWeaponDef = Weapon->WeaponData;
|
|
}
|
|
}
|
|
}
|
|
|
|
RemoveFromAlivePlayers(Globals::GetGameMode(), PlayerController, KillerPlayerState == DeadPlayerState ? nullptr : KillerPlayerState, KillerPawn, KillerWeaponDef, (int)DeathData.DeathCause, 0);
|
|
PlayerController->bMarkedAlive = false;
|
|
}
|
|
|
|
|
|
void Initialize()
|
|
{
|
|
auto DefaultObject = AAthena_PlayerController_C::GetDefaultObj();
|
|
|
|
Memory::VirtualHook(DefaultObject, 0x104, hkServerAcknowledgePossession);
|
|
Memory::VirtualHook(DefaultObject, 0x241, hkServerReadyToStartMatch, (void**)&oServerReadyToStartMatch);
|
|
Memory::VirtualHook(DefaultObject, 0x243, hkServerLoadingScreenDropped, (void**)&oServerLoadingScreenDropped);
|
|
Memory::VirtualHook(DefaultObject, 0x1e5, hkServerExecuteInventoryItem);
|
|
Memory::VirtualHook(DefaultObject, 0x201, hkServerCreateBuildingActor);
|
|
Memory::VirtualHook(DefaultObject, 0x203, hkServerEditBuildingActor, (void**)&oServerEditBuildingActor);
|
|
Memory::VirtualHook(DefaultObject, 0x207, hkServerBeginEditingBuildingActor);
|
|
Memory::VirtualHook(DefaultObject, 0x205, hkServerEndEditingBuildingActor);
|
|
Memory::VirtualHook(DefaultObject, 0x1b3, hkServerPlayEmoteItem);
|
|
|
|
MH_STATUS StatusEnterAircraft = Memory::CreateHook(Memory::GetAddress(0xa26d10), hkEnterAircraft, (void**)&oEnterAircraft);
|
|
MH_STATUS StatusClientOnPawnDied = Memory::CreateHook(Memory::GetAddress(0x11ac700), hkClientOnPawnDied, (void**)&oClientOnPawnDied);
|
|
|
|
#ifdef LOG_HOOKSTATUS
|
|
Logging::Log(ELogEvent::Info, ELogType::Hook, "hkEnterAircraft Status: %s.", MH_StatusToString(StatusEnterAircraft));
|
|
Logging::Log(ELogEvent::Info, ELogType::Hook, "hkClientOnPawnDied Status: %s.", MH_StatusToString(StatusClientOnPawnDied));
|
|
#endif
|
|
|
|
|
|
Logging::Log(ELogEvent::Info, ELogType::Hook, "PlayerController hooks initialized.");
|
|
}
|
|
} |