DECLARE_HOOK(APrimalStructure_TakeDamage, float, APrimalStructure*, float, FDamageEvent*, AController*, AActor*);
(edited)void SuicideCMD(AShooterPlayerController* player, FString* message, int mode)
{
if (!player || !player->PlayerStateField() || !player->GetPlayerCharacter() || player->GetPlayerCharacter()->IsDead()) return;
if (!ArkApi::GetApiUtils().IsRidingDino(player)) player->Suicide();
}
(edited)void SuicideCMD(AShooterPlayerController* player, FString* message, int mode)
{
if (!player || !player->PlayerStateField() || !player->GetPlayerCharacter() || player->GetPlayerCharacter()->IsDead()) return;
if (!ArkApi::GetApiUtils().IsRidingDino(player)) player->GetPlayerCharacter()->Suicide();
}
(edited)if (_this && EventInstigator && !EventInstigator->IsLocalController() && EventInstigator->IsA(AShooterPlayerController::StaticClass()))
{
AShooterPlayerController* AttackerShooterController = static_cast<AShooterPlayerController*>(EventInstigator);
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
if (WeaponName.Contains(L"Flamethrower")) return 0;
}
}
AShooterPlayerController* AttackerShooterController = static_cast<AShooterPlayerController*>(EventInstigator);
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
if (WeaponName.Contains(L"Flamethrower")) return 0;
}
(edited) if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
if (WeaponName.Contains(L"Flamethrower")) return 0;
}
void MyCommand(AShooterPlayerController* AttackerShooterController, FString* message, int mode)
{
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
Log::GetLog()->warn("Weapon Name: {}", WeaponName.ToString());
}
}
(edited)ArkApi::GetCommands().AddChatCommand("/test", &MyCommand);
if (!AttackerShooterController || !AttackerShooterController->PlayerStateField() || !AttackerShooterController->GetPlayerCharacter() || AttackerShooterController->GetPlayerCharacter()->IsSitting(true)) return;
void SuicideCMD(AShooterPlayerController* AttackerShooterController, FString* message, int mode)
{
if (!AttackerShooterController || !AttackerShooterController->PlayerStateField() || !AttackerShooterController->GetPlayerCharacter() || AttackerShooterController->GetPlayerCharacter()->IsDead()) return;
if (!ArkApi::GetApiUtils().IsRidingDino(AttackerShooterController)) AttackerShooterController->GetPlayerCharacter()->Suicide();
if (!AttackerShooterController || !AttackerShooterController->PlayerStateField() || !AttackerShooterController->GetPlayerCharacter() || !AttackerShooterController->GetPlayerCharacter()->IsConscious()) return;
if (!AttackerShooterController || !AttackerShooterController->PlayerStateField() || !AttackerShooterController->GetPlayerCharacter() || AttackerShooterController->GetPlayerCharacter()->IsSitting(false)) return;
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
if (WeaponName.Contains(L"Flamethrower")) return;
Log::GetLog()->warn("Weapon Name: {}", WeaponName.ToString());
}
}
void SuicideCMD(AShooterPlayerController* AttackerShooterController, FString* message, int mode)
{
if (!AttackerShooterController || !AttackerShooterController->PlayerStateField() || !AttackerShooterController->GetPlayerCharacter() || AttackerShooterController->GetPlayerCharacter()->IsDead()) return;
if (!ArkApi::GetApiUtils().IsRidingDino(AttackerShooterController)) AttackerShooterController->GetPlayerCharacter()->Suicide();
if (!AttackerShooterController || !AttackerShooterController->PlayerStateField() || !AttackerShooterController->GetPlayerCharacter() || !AttackerShooterController->GetPlayerCharacter()->IsConscious()) return;
if (!AttackerShooterController || !AttackerShooterController->PlayerStateField() || !AttackerShooterController->GetPlayerCharacter() || AttackerShooterController->GetPlayerCharacter()->IsSitting(false)) return;
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
if (WeaponName.Contains(L"Flamethrower")) return;
Log::GetLog()->warn("Weapon Name: {}", WeaponName.ToString());
}
}
if (_this && EventInstigator && EventInstigator->IsA(AShooterPlayerController::StaticClass()))
{
AShooterPlayerController* AttackerShooterController = static_cast<AShooterPlayerController*>(EventInstigator);
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
if (WeaponName.Contains(L"Flamethrower")) return 0;
}
}
void SuicideCMD(AShooterPlayerController* AttackerShooterController, FString* message, int mode)
{
if (!AttackerShooterController || !AttackerShooterController->PlayerStateField() || !AttackerShooterController->GetPlayerCharacter() || AttackerShooterController->GetPlayerCharacter()->IsDead() || !AttackerShooterController->GetPlayerCharacter()->IsConscious() || AttackerShooterController->GetPlayerCharacter()->IsSitting(false)) return;
if (!ArkApi::GetApiUtils().IsRidingDino(AttackerShooterController)) AttackerShooterController->GetPlayerCharacter()->Suicide();
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
if (WeaponName.Contains(L"Handcuffs")) return;
}
}
dino->UpdateImprintingDetails_Implementation(FString *ImprinterName, steam_id);
FString ImprinterName = "some name";
dino->UpdateImprintingDetails_Implementation(&ImprinterName , steam_id);
void SetImprintToPlayer(RCONClientConnection* rcon_connection, RCONPacket* rcon_packet, UWorld*)
{
FString msg = rcon_packet->Body;
TArray<FString> parsed;
msg.ParseIntoArray(parsed, L" ", true);
if (parsed.IsValidIndex(4))
{
int dino_id1;
int dino_id2;
uint64 steam_id;
FString playerName;
try
{
dino_id1 = std::stoi(*parsed[1]);
dino_id2 = std::stoi(*parsed[2]);
steam_id = std::stoull(*parsed[3]);
playerName = parsed[4];
}
catch (const std::exception&)
{
SendRconReply(rcon_connection, rcon_packet->Id, "Request has failed");
Log::GetLog()->info("error.1");
return;
}
APrimalDinoCharacter* dino = APrimalDinoCharacter::FindDinoWithID(ArkApi::GetApiUtils().GetWorld(), dino_id1,
dino_id2);
if (!dino)
{
SendRconReply(rcon_connection, rcon_packet->Id, "Can't find dino");
Log::GetLog()->info("error.2");
return;
}
AShooterPlayerController* shooter_pc = ArkApi::GetApiUtils().FindPlayerFromSteamId(steam_id);
if (!shooter_pc)
{
SendRconReply(rcon_connection, rcon_packet->Id, "Can't find player from the given steam id");
Log::GetLog()->info("error.3");
return;
}
shooter_pc->GetPlayerCharacterName(&playerName);
Log::GetLog()->info("error.4");
dino->UpdateImprintingDetails(&playerName, shooter_pc->LinkedPlayerIDField());
SendRconReply(rcon_connection, rcon_packet->Id, "Successfully changed Imprint on dino");
Log::GetLog()->info("error.5");
}
else
{
SendRconReply(rcon_connection, rcon_packet->Id, "Not enough arguments");
}
}
{
int dino_id1;
int dino_id2;
uint64 steam_id;
- FString playerName;
try
{
void DestroyStructuresForTeam(RCONClientConnection* rcon_connection, RCONPacket* rcon_packet, UWorld*)
{
FString msg = rcon_packet->Body;
TArray<FString> parsed;
msg.ParseIntoArray(parsed, L" ", true);
if (parsed.IsValidIndex(1))
{
uint64 team_id;
try
{
team_id = std::stoi(*parsed[1]);
}
catch (const std::exception&)
{
SendRconReply(rcon_connection, rcon_packet->Id, "Request has failed");
return;
}
if (team_id < 999999999)
{
SendRconReply(rcon_connection, rcon_packet->Id, "You have enter the wrong TeamID");
return;
}
UWorld* world = ArkApi::GetApiUtils().GetWorld();
if (!world)
{
SendRconReply(rcon_connection, rcon_packet->Id, "Something must have gone terribly wrong?");
return;
}
TArray<AActor*>* FoundActors = new TArray<AActor*>();
UGameplayStatics::GetAllActorsOfClass(world, APrimalStructure::GetPrivateStaticClass(), FoundActors);
std::stringstream ss;
int num = 0;
for (uint32_t i = 0; i == FoundActors->Num(); i++)
{
AActor* actor = (*FoundActors)[i];
APrimalStructure* structure = static_cast<APrimalStructure*>(actor);
const int structure_team = structure->TargetingTeamField();
if (structure_team == team_id)
{
structure->Destroy(false, true);
num++;
}
}
ss << "Destroyed " << num << " structures belonging to team " << team_id;
delete FoundActors;
ArkApi::Tools::ConvertToWideStr(ss.str());
SendRconReply(rcon_connection, rcon_packet->Id, "Successfully Destroyed team structures!");
}
else
{
SendRconReply(rcon_connection, rcon_packet->Id, "Not enough arguments");
}
}
(edited) TArray<AActor*> AllStructures;
UGameplayStatics::GetAllActorsOfClass(reinterpret_cast<UObject*>(ArkApi::GetApiUtils().GetWorld()), APrimalStructure::GetPrivateStaticClass(), &AllStructures);
for (AActor* StructureActor : AllStructures)
{
if (StructureActor)
{
APrimalStructure* Structure = static_cast<APrimalStructure*>(StructureActor);
Structure->Suicide();
}
}
uint64 tribe_id = tribe_id_input;
TArray<AActor*> AllStructures;
UGameplayStatics::GetAllActorsOfClass(reinterpret_cast<UObject*>(ArkApi::GetApiUtils().GetWorld()), APrimalStructure::GetPrivateStaticClass(), &AllStructures);
TArray<APrimalStructure*> FoundStructures;
for (AActor* StructActor : AllStructures)
{
if (!StructActor || StructActor->TargetingTeamField() != tribe_id || !StructActor->IsA(APrimalStructure::GetPrivateStaticClass())) continue;
FoundStructures.Add(static_cast<APrimalStructure*>(StructActor));
}
for (APrimalStructure* st : FoundStructures)
{
//do something with found tribe structures
}
(edited)TArray<AActor*> AllStructures;
UGameplayStatics::GetAllActorsOfClass(reinterpret_cast<UObject*>(ArkApi::GetApiUtils().GetWorld()), APrimalStructure::GetPrivateStaticClass(), &AllStructures);
for (AActor* StructureActor : AllStructures)
{
if (StructureActor && StructureActor->TargetingTeamField() == team_id)
{
APrimalStructure* Structure = static_cast<APrimalStructure*>(StructureActor);
Structure->Suicide();
}
}
(edited)needs to be
(edited)Log::GetLog()->warn(someVar1);
too to check if your variables are correct too, unless there's an easier wayfor
loop will probably* give you better performance tooinline void ChatCommand(AShooterPlayerController* player, FString* message, int mode)
{
TArray<FString> parsed;
message->ParseIntoArray(parsed, L" ", true);
if (parsed.IsValidIndex(1))
{
FString input = parsed[1];
auto value = input.ToString();
if (value.compare("info") == 0)
{
Info(player, message, mode);
}
else if (value.compare("status") == 0)
{
Status(player, message, mode);
}
else if (value.compare("disable") == 0)
{
Disable(player, message, mode);
}
else
{
ArkApi::GetApiUtils().SendNotification(player, NewPlayerProtection::MessageColor, NewPlayerProtection::MessageTextSize, NewPlayerProtection::MessageDisplayDelay, nullptr,
*NewPlayerProtection::NPPInvalidCommand);
}
}
else
{
ArkApi::GetApiUtils().SendNotification(player, NewPlayerProtection::MessageColor, NewPlayerProtection::MessageTextSize, NewPlayerProtection::MessageDisplayDelay, nullptr,
*NewPlayerProtection::NPPInvalidCommand);
}
}
uint64 team_id;
try
{
team_id = std::stoi(*parsed[1]);
}
TO
uint64 team_id;
try
{
team_id = std::stoi(*parsed[0]);
}
It didn't work.ShooterGameServer.exe!UObjectSerializer::SerializeObject() (0x00007ff70e3f8283) + 41 bytes [f:\build\trunk\projects\shootergame\source\shootergame\private\objectserializer.cpp:60]
ShooterGameServer.exe!AShooterGameMode::SaveTribeData() (0x00007ff70e718e24) + 0 bytes [f:\build\trunk\projects\shootergame\source\shootergame\private\shootergamemode.cpp:3139]
ShooterGameServer.exe!AShooterGameMode::AddToTribeLog() (0x00007ff70e7367e0) + 28 bytes [f:\build\trunk\projects\shootergame\source\shootergame\private\shootergamemode.cpp:6671]
ShooterGameServer.exe!APrimalDinoCharacter::TryMultiUse() (0x00007ff70e4d2d00) + 0 bytes [f:\build\trunk\projects\shootergame\source\shootergame\private\primaldinocharacter.cpp:8717]
ShooterGameServer.exe!AShooterPlayerController::ServerMultiUse_Implementation() (0x00007ff70e7ad015) + 18 bytes [f:\build\trunk\projects\shootergame\source\shootergame\private\shooterplayercontroller.cpp:5635]
ShooterGameServer.exe!AShooterPlayerController::execServerMultiUse() (0x00007ff70ed9b345) + 325 bytes [f:\build\trunk\projects\shootergame\source\shootergame\classes\shooterplayercontroller.h:113]
std::ifstream file(ArkApi::Tools::GetCurrentDir() + "/ArkApi/Plugins/NewPlayerProtection/config.json");
FString NewPlayerDoingDamageMessage = FString(ArkApi::Tools::Utf8Decode(NewPlayerProtection::config["General"]["NewPlayerDoingDamageMessage"]).c_str());
(edited)Data = PermColours["Permission"];
Permission = ArkApi::Tools::Utf8Decode(Data).c_str();
Data = PermColours["Tag"];
Tag = ArkApi::Tools::Utf8Decode(Data).c_str();
Data = PermColours["ImagePath"];
ImagePath = ArkApi::Tools::Utf8Decode(Data).c_str();
(edited) int PlayerUpdateIntervalInMins;
bool AllowNewPlayersToDamageEnemyStructures;
bool AllowPlayersToDisableOwnedTribeProtection;
FString NPPCommandPrefix;
FString NewPlayerDoingDamageMessage;
FString NewPlayerStructureTakingDamageMessage;
FString NewPlayerStructureTakingDamageFromUnknownTribemateMessage;
FString NPPInvalidCommand;
FString NewPlayerProtectionDisableSuccess;
FString NotANewPlayerMessage;
FString NotTribeAdminMessage;
FString NPPRemainingMessage;
FString AdminNoTribeExistsMessage;
FString AdminTribeProtectionRemoved;
FString AdminTribeNotUnderProtection;
FString AdminResetTribeProtectionSuccess;
FString AdminResetTribeProtectionLvlFailure;
FString NPPInfoMessage;
int MessageIntervalInSecs;
float MessageTextSize;
float MessageDisplayDelay;
FLinearColor MessageColor;
int MaxLevel;
int HoursOfProtection;
(edited)inline void InitChatCommands()
{
FString cmd1 = NewPlayerProtection::NPPCommandPrefix;
cmd1 = cmd1.Append("npp");
ArkApi::GetCommands().AddChatCommand(cmd1, &ChatCommand);
}
std::string data = NewPlayerProtection::config["General"]["NewPlayerDoingDamageMessage"];
NewPlayerProtection::NewPlayerDoingDamageMessage = ArkApi::Tools::Utf8Decode(data).c_str();
"NewPlayerDoingDamageMessage": "ÕÕÕÕÕÕÕÕÕÕÕÕ"
FString NewPlayerDoingDamageMessage;
std::string data = NewPlayerProtection::config["General"]["NewPlayerDoingDamageMessage"];
NewPlayerProtection::NewPlayerDoingDamageMessage = ArkApi::Tools::Utf8Decode(data).c_str();
ArkApi::GetApiUtils().SendNotification(player, NewPlayerProtection::MessageColor, NewPlayerProtection::MessageTextSize, NewPlayerProtection::MessageDisplayDelay, nullptr, *NewPlayerProtection::NewPlayerDoingDamageMessage);
nlohmann::json config;
std::ifstream file(ArkApi::Tools::GetCurrentDir() + "/ArkApi/Plugins/NewPlayerProtection/config.json");
if (!file.is_open())
{
return;
}
file >> NewPlayerProtection::config;
file.close();
(edited)IDatabase* database;
auto connection_config = std::make_shared<mysql::connection_config>();
connection_config->host = config.value("MysqlHost", "");
connection_config->user = config.value("MysqlUser", "");
connection_config->password = config.value("MysqlPass", "");
connection_config->database = config.value("MysqlDB", "");
connection_config->port = port;
connection_config->debug = false;
connection_config->auto_reconnect = true;
database = new MySql(connection_config);
or sql lite:
database = new SqlLite(config.value("DbPathOverride", ""));
(edited)The WAL journaling mode uses a write-ahead log instead of a rollback journal to implement transactions. The WAL journaling mode is persistent; after being set it stays in effect across multiple database connections and after closing and reopening the database.
There are advantages and disadvantages to using WAL instead of a rollback journal. Advantages include:
WAL is significantly faster in most scenarios.
WAL provides more concurrency as readers do not block writers and a writer does not block readers. Reading and writing can proceed concurrently.
Disk I/O operations tends to be more sequential using WAL.
WAL uses many fewer fsync() operations and is thus less vulnerable to problems on systems where the fsync() system call is broken.
//check for enemy structures nearby
UWorld* world = ArkApi::GetApiUtils().GetWorld();
TArray<AActor*> new_actors;
TArray<AActor*> actors_ignore;
TArray<TEnumAsByte<enum EObjectTypeQuery>> types;
UKismetSystemLibrary::SphereOverlapActors_NEW(world, _this->RootComponentField()->RelativeLocationField(),
static_cast<float>((DinoPassiveProtection::MinimumEnemyStructureDistanceInFoundations * 300)), &types,
APrimalStructure::GetPrivateStaticClass(), &actors_ignore,
&new_actors);
for (const auto& actor : new_actors)
{
APrimalStructure* structure = static_cast<APrimalStructure*>(actor);
//Log::GetLog()->warn(FVector::Distance(_this->RootComponentField()->RelativeLocationField(), actor->RootComponentField()->RelativeLocationField()));
if (structure->TargetingTeamField() != _this->TargetingTeamField())
{
isNotNearEnemyStructures = false;
break;
}
else
{
isNotNearEnemyStructures = true;
}
}
(edited)UWorld* world = ArkApi::GetApiUtils().GetWorld();
TArray<AActor*> new_actors;
TArray<AActor*> actors_ignore;
TArray<TEnumAsByte<enum EObjectTypeQuery>> types;
UKismetSystemLibrary::SphereOverlapActors_NEW(world, ArkApi::IApiUtils::GetPosition(player_controller),
static_cast<float>(radius), &types,
APrimalStructure::GetPrivateStaticClass(), &actors_ignore,
&new_actors);
for (const auto& actor : new_actors)
{
APrimalStructure* structure = static_cast<APrimalStructure*>(actor);
if (structure->TargetingTeamField() != player_controller->TargetingTeamField())
return true;
}
return false;
(edited)FString damagedStructureDescription;
_this->GetHumanReadableName(&damagedStructureDescription);
You can then use StartsWith or Contains on it to see if it's a corrupted dino.
That's how I did it.mute <Mins> <Hours> <CharacterName> - Mute a Character for a certain amount of minutes and hours
ipban <Mins> <Hours> <CharacterName> - IP Ban a Character for a certain amount of minutes and hours and also kicks them from the server
unmute <CharacterName> - UnMute a Character
ipunban <CharacterName> - IP UnBan a Character
clearall - UnMute &IP UnBan Everybody
mreload - Reload Config
Features:
Mute Steam id or ip from global chat
FString PostUrl = "127.0.0.1/test.php";
FString type = "POST";
FString Content = "name=test";
if (ArkApi::Requests::Get().CreateRequest(PostUrl, type, &HttpPostReturnFunc, Content, true))
Log::GetLog()->info("Request success");
else
Log::GetLog()->info("Request fail");
FString PostUrl = "127.0.0.1/test.php";
to
FString PostUrl = "http://127.0.0.1/test.php";
makes it work (edited)if (DamageCauser)
{
FString descr;
DamageCauser->GetHumanReadableName(&descr);
Log::GetLog()->info(descr.ToString());
if (descr.Contains(L"Turret"))
{
return 0;
}
}
void Load()
{
std::cout << "Loaded a plugin";
}
void Unload()
{
std::cout << "Unloaded the plugin";
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Load();
break;
case DLL_PROCESS_DETACH:
Unload();
break;
}
return TRUE;
}
like thisArkApi::GetCommands().AddChatCommand("/newcommand", &Function);
Iceworm_Queen_Character_BP_C
from an AController. GetFullName
returns the name of the AI controllerAShooterGameMode.Killed
to monitor boss kills, counting them for a player and saving the last kill time to display a timer of next respawn on my website.FString NPCClassString;
FNPCSpawnLimit
, I can't find the connection of AController to itAPrimalDinoCharacter* dino = static_cast<APrimalDinoCharacter*>(KilledPlayer->CharacterField());
(edited)if (KilledPlayer->CharacterField() is APrimalDinoCharacter) {
ACharacter* character = EventInstigator->CharacterField();
ArkApi::GetApiUtils().GetIPAddress(player);
if (EventInstigator && EventInstigator->IsA(APlayerController::StaticClass()))
(edited)if (EventInstigator && EventInstigator->IsA(APlayerController::GetPrivateStaticClass()))
::GetPrivateStaticClass()
is causing messages to be sent to dinos now?if (EventInstigator != nullptr && EventInstigator->IsA(APlayerController::GetPrivateStaticClass()) && EventInstigator && EventInstigator->CharacterField())
->IsA(APlayerController::GetPrivateStaticClass())
is no longer enough to filter dinos from players->IsA(AShooterPlayerController::GetPrivateStaticClass())
works#include "stdafx.h"
#include "API\ARK\Ark.h"
#pragma comment(lib, "ArkApi.lib")
void TestCMD(AShooterPlayerController* shooter_controller, FString* message, int mode)
{
if (!shooter_controller->PlayerStateField()) return;
Log::GetLog()->warn("Test Chat Command Called: {}", message->ToString());
ArkApi::GetApiUtils().SendServerMessage(shooter_controller, FColorList::Pink, L"{}, you tried the test command", *ArkApi::GetApiUtils().GetCharacterName(shooter_controller));
}
void Load()
{
Log::Get().Init("Test Plugin");
ArkApi::GetCommands().AddChatCommand("/test", &TestCMD);
}
void Unload()
{
ArkApi::GetCommands().RemoveChatCommand("/test");
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Load();
break;
case DLL_PROCESS_DETACH:
Unload();
break;
}
return TRUE;
}
void Load()
{
Log::Get().Init("ProjectCCC");
Log::GetLog()->debug("Testing 123, please load the project for me ;)");
ArkApi::GetApiUtils().SendServerMessageToAll(FColorList::Green, L"Test Message: {}", L"Test arg");
ArkApi::GetCommands().AddChatCommand("/test", &TestCMD);
}
UPrimalItem::CrafterCharacterNameField
For each item in each inventory.. no matter if its of a structure / player Fatal error!
VERSION: 294.108
ProjectCCC.dll!FString::ToString() (0x00007ffae47d6d4a) + 0 bytes [d:\ark-server-api-master\version\core\public\api\ue\containers\fstring.h:1612]
ProjectCCC.dll!Hook_UPrimalInventoryComponent_AddItem() (0x00007ffae47d72a4) + 29 bytes [c:\users\dfouc\source\repos\projectccc\projectccc\projectccc.cpp:58]
ShooterGameServer.exe!UPrimalInventoryComponent::GiveInitialItems() (0x00007ff750522ffb) + 64 bytes [f:\build\trunk\projects\shootergame\source\shootergame\private\primalinventorycomponent.cpp:1362]
ShooterGameServer.exe!UPrimalInventoryComponent::InitializeInventory() (0x00007ff750523e8c) + 0 bytes [f:\build\trunk\projects\shootergame\source\shootergame\private\primalinventorycomponent.cpp:1535]
ShooterGameServer.exe!APrimalStructureItemContainer::BeginPlay() (0x00007ff7505e92eb) + 0 bytes [f:\build\trunk\projects\shootergame\source\shootergame\private\primalstructureitemcontainer.cpp:330]
ShooterGameServer.exe!APrimalStructureItemContainer_SupplyCrate::BeginPlay() (0x00007ff7505fff87) + 0 bytes
Log::Get().Init("ProjectCCC");
Log::GetLog()->info("Loading the project ............");
//Load Commands
ArkApi::GetCommands().AddChatCommand("/test", &TestCMD);
//Load Hooks
//ArkApi::GetHooks().SetHook("APrimalCharacter.ServerUploadCharacter", &Hook_APrimalCharacter_ServerUploadCharacter, &APrimalCharacter_ServerUploadCharacter_original);
ArkApi::GetHooks().SetHook("UPrimalInventoryComponent.AddItem", &Hook_UPrimalInventoryComponent_AddItem, &UPrimalInventoryComponent_AddItem_original);
if (OwnerPlayer != 0)
never executes
then tried
if(OwnerPlayer->PlayerStateField())
it crashes
then
if(reinterpret_cast<AShooterPlayerController*>(OwnerPlayer->PlayerStateField()))
crashes
then
if (OwnerPlayer)
never executes (edited)void Hook_UPrimalItem_AddToInventory(UPrimalItem* _this, UPrimalInventoryComponent* toInventory, bool bEquipItem, bool AddToSlotItems, FItemNetID* InventoryInsertAfterItemID, bool ShowHUDNotification, bool bDontRecalcSpoilingTime, bool bIgnoreAbsoluteMaxInventory)
{
if (toInventory->IsOwnedByPlayer()) {
const auto player_controller = toInventory->GetOwnerController();
const uint64 steam_id = ArkApi::IApiUtils::GetSteamIdFromController(player_controller);
if (toInventory->IsLocalToPlayer(player_controller)) {
FString ItemName;
_this->GetItemName(&ItemName, true, false, player_controller);
FString name;
toInventory->GetInventoryName(&name, false);
Log::GetLog()->warn("\"{}\" Added to {}[{}].", ItemName.ToString(), name.ToString(), steam_id);
}
}
UPrimalItem_AddToInventory_original(_this, toInventory, bEquipItem, AddToSlotItems, InventoryInsertAfterItemID, ShowHUDNotification, bDontRecalcSpoilingTime, bIgnoreAbsoluteMaxInventory);
}
UPrimalItem * Hook_UPrimalInventoryComponent_AddItem(UPrimalInventoryComponent* _this, FItemNetInfo* theItemInfo, bool bEquipItem, bool AddToSlot, bool bDontStack, FItemNetID* InventoryInsertAfterItemID, bool ShowHUDNotification, bool bDontRecalcSpoilingTime, bool bForceIncompleteStacking, AShooterCharacter* OwnerPlayer, bool bIgnoreAbsoluteMaxInventory)
{
//Log::GetLog()->warn("Hook_UPrimalInventoryComponent_AddItem-------------- {}", OwnerPlayer->PlayerStateField());
try
{
if (OwnerPlayer != nullptr) {
Log::GetLog()->critical("Inventory Hook Running for player ");
/*Log::GetLog()->warn("Inventory Hook Running for player : {}", OwnerPlayer->PlayerNameField().ToString());
ArkApi::GetApiUtils().SendServerMessage(reinterpret_cast<AShooterPlayerController*>(OwnerPlayer),
FColorList::Blue,
L"{}, You have added an item to your inventory", OwnerPlayer->PlayerNameField().ToString());
*/
}
}
catch (std::exception e)
{
Log::GetLog()->error("Shit Failed again for ........Hook_UPrimalInventoryComponent_AddItem--------");
}
return UPrimalInventoryComponent_AddItem_original(_this, theItemInfo, bEquipItem, AddToSlot, bDontStack, InventoryInsertAfterItemID, ShowHUDNotification, bDontRecalcSpoilingTime, bForceIncompleteStacking, OwnerPlayer, bIgnoreAbsoluteMaxInventory);
}
ArkApi::GetApiUtils().SendServerMessage(reinterpret_cast<AShooterPlayerController*>(Dragger), FColorList::Red, L"Some message to send");
AShooterCharacter* OwnerPlayer
ArkApi::GetApiUtils().SendServerMessage(reinterpret_cast<AShooterPlayerController*>(OwnerPlayer),
FColorList::Blue,
L"{}, You have added an item to your inventory", OwnerPlayer->PlayerNameField().ToString());
(edited){
"WeaponDamageCustomizer": {
"ToWild": [
{
"WeaponName": "AP",
"Multiplier": 5
}
],
"ToTamed": [
{
"WeaponName": "AP",
"Multiplier": 5
}
],
"ToPlayer": [
{
"WeaponName": "AP",
"Multiplier": 5
}
]
}
}
TArray<UPrimalItem*> out_items;
player_controller->GiveItem(&out_items, &fblueprint, default_amount, quality, force_blueprint,false, 0);
Is out_items an array of items the player has or an array of the items created?#pragma comment(lib, "LibName.lib")
, and you need to add path to .lib into project settings, of course.DECLARE_HOOK(AShooterPlayerController_ConsoleCommand, FString *, AShooterPlayerController*, FString *, FString *, bool);
if (Command->Contains("AddPoints"))
{
APlayerController->ConsoleCommand();
}
APlayerController* character = ConsoleCommand();
APlayerController* command = _this->ConsoleCommand();
FString * Hook_AShooterPlayerController_ConsoleCommand(AShooterPlayerController* _this, FString* result, FString* Command, bool bWriteToLog)
{
if (Command->Contains("AddPoints"))
{
FString result;
FString AddPoints;
Command = AddPoints;
((APlayerController*)_this)->ConsoleCommand(&result,&AddPoints,false);
return 0;
}
return AShooterPlayerController_ConsoleCommand_original(_this, result, Command, bWriteToLog);
}
FString * Hook_AShooterPlayerController_ConsoleCommand(AShooterPlayerController* _this, FString* result, FString* Command, bool bWriteToLog)
{
if (Command->Contains("AddPoints"))
{
FString result;
((APlayerController*)_this)->ConsoleCommand(&result,Command,false);
return 0;
}
return AShooterPlayerController_ConsoleCommand_original(_this, result, Command, bWriteToLog);
}
FString * Hook_AShooterPlayerController_ConsoleCommand(AShooterPlayerController* _this, FString* result, FString* Command, bool bWriteToLog)
{
if (Command->Contains("AddPoints"))
{
((APlayerController*)_this)->ConsoleCommand(result,Command,false);
return 0;
}
return AShooterPlayerController_ConsoleCommand_original(_this, result, Command, bWriteToLog);
}
FString * Hook_AShooterPlayerController_ConsoleCommand(AShooterPlayerController* _this, FString* result, FString* Command, bool bWriteToLog)
{
if (Command->Contains("AddPoints"))
{
((APlayerController*)_this)->ConsoleCommand(result,Command,false);
return result;
}
return AShooterPlayerController_ConsoleCommand_original(_this, result, Command, bWriteToLog);
}
auto shooter_controller = static_cast<AShooterPlayerController*>(theWorld->GetFirstPlayerController());
ArkApi::GetApiUtils().SendServerMessage(shooter_controller, FColorList::Green, L", you tried the test command");
I am the only player on this server, and I am wondering if that is why its working. If there are more player on line , will it still come to me or could it possible go to another player due to it being GetFirstPlayerController (edited)Hook_APrimalDinoCharacter_IsReadyToUpload(APrimalDinoCharacter* _this, UWorld* theWorld)
know that it found the correct controller as there is no reference to itif(true){
///do what ever i need
}
else {
execute original function
}
DECLARE_HOOK(AShooterGameMode_OnLogout, void, AShooterGameMode*, AController *);
void Hook_AShooterGameMode_OnLogout(AShooterGameMode* _this, AController* Exiting)
{
AShooterGameMode_OnLogout_original(_this, Exiting);
}
//load
ArkApi::GetHooks().SetHook("AShooterGameMode.OnLogout", &Hook_AShooterGameMode_OnLogout, &AShooterGameMode_OnLogout_original);
//unload
ArkApi::GetHooks().DisableHook("AShooterGameMode.OnLogout", &Hook_AShooterGameMode_OnLogout);
DownloadedDino->GetDinoDescriptiveName(&dino_name);
to get the dino , but no idea how I would achieve it with the above subclassFString dino_name;
TheDinoClass.uClass->CreateDefaultObject()->NameField().ToString(&dino_name);
(edited)FString& TamedNameField() { return *GetNativePointerField<FString*>(this, "APrimalDinoCharacter.TamedName"); }
"Name text NOT NULL DEFAULT '',"
db << "SELECT PlayerKills, PlayerDeaths, WildDinoKills, TamedDinoKills FROM Players WHERE SteamId = ?;" << steam_id
>> std::tie(player_kills, player_deaths, wild_dino_kills, tamed_dino_kills);
std::string GetPlayerStats(uint64 steam_id) override
{
std::string PlayerStats = "";
try
{
return db_.query("SELECT PlayerKills, PlayerDeaths, WildDinoKills, TamedDinoKills FROM Players WHERE SteamId = %I64u;", steam_id).get_value<std::string>();
}
catch (const std::exception& exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
}
return PlayerStats;
}
(edited) if (Stats::IsPlayerExists(steam_id))
{
database->GetPlayerStats>> std::tie(player_kills, player_deaths, wild_dino_kills, tamed_dino_kills);
}
bool TryAddNewPlayer(uint64 steam_id) override
{
try
{
return db_.query("INSERT INTO ShopRewards (SteamId) VALUES (%I64u);", steam_id);
}
catch (const std::exception& exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
return false;
}
}
inline
or place declarations and definitions to *.h and *.cpp file respectivelyinline bool AddPlayerDeath(uint64 ...) { ... }
bool AddPlayerDeath(uint64 ...) { ... }
std::string GetPlayerStats(const uint64 steam_id)
{
try
{
return db_.query("SELECT PlayerKills, PlayerDeaths, WildDinoKills, TamedDinoKills FROM Players WHERE SteamId = %I64u;", steam_id).get_value<std::string>();
}
catch (const std::exception& exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
}
return "";
}
const auto& mysql_conf = config["Mysql"];
{
ShopRewards::database = std::make_unique<MySql>(mysql_conf.value("MysqlHost", ""),
mysql_conf.value("MysqlUser", ""),
mysql_conf.value("MysqlPass", ""),
mysql_conf.value("MysqlDB", ""));
}
"Name TEXT NOT NULL DEFAULT '',"
if (_this->TargetingTeamField() < 50000)
{
if (ShopRewards::database->IsPlayerExists(steam_id))
{
Log::GetLog()->error("attempting to add player wild dino kill ", steam_id);
ShopRewards::database->AddWildDinoKill(steam_id);
}
else
{
Log::GetLog()->error("attempting to add player to mysql", steam_id);
ShopRewards::database->TryAddNewPlayer(steam_id);
return APrimalDinoCharacter_Die_original(_this, KillingDamage, DamageEvent, Killer, DamageCauser);
}
}
else
{
if (ShopRewards::database->IsPlayerExists(steam_id))
{
Log::GetLog()->error("attempting to add player tamed dino kill", steam_id);
ShopRewards::database->AddTamedDinoKill(steam_id);
}
else
{
Log::GetLog()->error("attempting to add player to mysql", steam_id);
ShopRewards::database->TryAddNewPlayer(steam_id);
return APrimalDinoCharacter_Die_original(_this, KillingDamage, DamageEvent, Killer, DamageCauser);
}
}
}
bool TryAddNewPlayer(uint64 steam_id) override
{
try
{
Log::GetLog()->error("TryAddNewPlayerCalled {}" ,steam_id);
return db_.query("INSERT INTO ShopRewards (SteamId) VALUES (%I64u);", steam_id);
}
catch (const std::exception& exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
return false;
}
}
{
Log::GetLog()->error("TryAddNewPlayerCalled {}" ,steam_id);
return db_.query("INSERT INTO ShopRewards (SteamId) VALUES (76561198082295768);", steam_id);
bool TryAddNewPlayer(uint64 steam_id) override
{
try
{
FString name = "";
AShooterPlayerController* controller = ArkApi::GetApiUtils().FindPlayerFromSteamId(steam_id);
if (controller && controller->GetPlayerCharacter())
name = controller->GetPlayerCharacter()->PlayerNameField();
Log::GetLog()->error("player name", name.ToString());
Log::GetLog()->error("TryAddNewPlayerCalled {}" ,steam_id);
return db_.query("INSERT INTO ShopRewards (SteamId , Name) VALUES (%I64u, %s);", steam_id,name.ToString());
}
catch (const std::exception& exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
return false;
}
}
FTribeData* tribe_data = static_cast<FTribeData*>(FMemory::Malloc(0x128 + 0x28));
RtlSecureZeroMemory(tribe_data, 0x128 + 0x28);
ArkApi::GetApiUtils().GetShooterGameMode()->GetOrLoadTribeData(teamId, tribe_data);
// Do smth
FMemory::Free(tribe_data);
it may look a bit weird void ShowMyStats(AShooterPlayerController* player_controller, FString*, EChatSendMode::Type)
{
const uint64 steam_id = ArkApi::IApiUtils::GetSteamIdFromController(player_controller);
int player_kills = 0;
int player_deaths = 0;
int wild_dino_kills = 0;
int tamed_dino_kills = 0;
if (ShopRewards::database->IsPlayerExists(steam_id))
{
ShopRewards::database->GetPlayerStats -> std::bind(player_kills, player_deaths, wild_dino_kills, tamed_dino_kills);
}
ArkApi::GetApiUtils().SendChatMessage(player_controller, GetText("Sender"), *GetText("MyStats"), player_kills,
player_deaths, wild_dino_kills, tamed_dino_kills);
}
std::string GetPlayerStats(const uint64 steam_id) override
{
try
{
return db_.query("SELECT `PlayerKills`, `PlayerDeaths`,`WildDinoKills`, `TamedDinoKills` FROM ShopRewards WHERE SteamId = %I64u;", steam_id).get_value<std::string>();
}
catch (const std::exception& exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
}
return "";
}
int id;
string name;
optional<double> weight;
auto res = my.query("select id, name, weight from person where id = %d", 3);
if (res) {
res.fetch(id, name, weight);
cout << "ID: " << id << ", name: " << name;
if (weight) cout << ", weight: " << *weight;
cout << endl;
}
from lib docsvoid ShowMyStats(AShooterPlayerController* player_controller, FString*, EChatSendMode::Type)
{
const uint64 steam_id = ArkApi::IApiUtils::GetSteamIdFromController(player_controller);
int player_kills = 0;
int player_deaths = 0;
int wild_dino_kills = 0;
int tamed_dino_kills = 0;
if (ShopRewards::database->IsPlayerExists(steam_id))
{
auto res = ShopRewards::database->GetPlayerStats;
if (res) {
res.fetch(player_kills, player_deaths, wild_dino_kills,tamed_dino_kills);
cout << "PlayerKills: " << player_kills << ", PlayerDeaths: " << player_deaths << ", WildDinoKills: " << wild_dino_kills << ", TamedDinoKills: " << tamed_dino_kills;
cout << endl;
}
}
ArkApi::GetApiUtils().SendChatMessage(player_controller, GetText("Sender"), *GetText("MyStats"), player_kills,
player_deaths, wild_dino_kills, tamed_dino_kills);
}
std::string GetPlayerStats(const uint64 steam_id) override
{
int player_kills = 0;
int player_deaths = 0;
int wild_dino_kills = 0;
int tamed_dino_kills = 0;
try
{
auto res = db_.query("SELECT `PlayerKills`, `PlayerDeaths`,`WildDinoKills`, `TamedDinoKills` FROM ShopRewards WHERE SteamId = %I64u;", steam_id).get_value<std::string>();
if (res) {
res.fetch(player_kills, player_deaths, wild_dino_kills, tamed_dino_kills);
cout << "PlayerKills: " << player_kills << ", PlayerDeaths: " << player_deaths << ", WildDinoKills: " << wild_dino_kills << ", TamedDinoKills: " << tamed_dino_kills;
cout << endl;
}
}
catch (const std::exception& exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
}
return "";
}
{
using namespace std;
auto res = db_.query("SELECT `PlayerKills`, `PlayerDeaths`,`WildDinoKills`, `TamedDinoKills` FROM ShopRewards WHERE SteamId = %I64u;", steam_id);
if (res) {
res.fetch(player_kills, player_deaths, wild_dino_kills, tamed_dino_kills);
cout << "PlayerKills: " << player_kills << ", PlayerDeaths: " << player_deaths << ", WildDinoKills: " << wild_dino_kills << ", TamedDinoKills: " << tamed_dino_kills;
cout << endl;
}
int GetPlayerStats(const uint64 steam_id) override
{
int player_kills = 0;
int player_deaths = 0;
int wild_dino_kills = 0;
int tamed_dino_kills = 0;
try
{
using namespace std;
auto res = db_.query("SELECT `PlayerKills`, `PlayerDeaths`,`WildDinoKills`, `TamedDinoKills` FROM ShopRewards WHERE SteamId = %I64u;", steam_id);
if (res) {
res.fetch(player_kills, player_deaths, wild_dino_kills, tamed_dino_kills);
cout << "PlayerKills: " << player_kills << ", PlayerDeaths: " << player_deaths << ", WildDinoKills: " << wild_dino_kills << ", TamedDinoKills: " << tamed_dino_kills;
cout << endl;
}
}
catch (const std::exception& exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
}
return player_kills,player_deaths,wild_dino_kills,tamed_dino_kills;
}
const auto the_class = new UClass();
const auto location = new FVector(1,1,1);
const auto rotation = new FRotator(0);
const auto params = new FActorSpawnParameters();
ArkApi::GetApiUtils().GetWorld()->SpawnActor(the_class, location, rotation, params);
(edited)int GetPlayerStats(const uint64 steam_id) override
{
int player_kills = 0;
int player_deaths = 0;
int wild_dino_kills = 0;
int tamed_dino_kills = 0;
try
{
using namespace std;
auto res = db_.query("SELECT `PlayerKills`, `PlayerDeaths`,`WildDinoKills`, `TamedDinoKills` FROM ShopRewards WHERE SteamId = %I64u;", steam_id);
if (res) {
res.fetch(player_kills, player_deaths, wild_dino_kills, tamed_dino_kills);
cout << "PlayerKills: " << player_kills << ", PlayerDeaths: " << player_deaths << ", WildDinoKills: " << wild_dino_kills << ", TamedDinoKills: " << tamed_dino_kills;
cout << endl;
}
}
catch (const std::exception& exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
}
std::tuple<int,int,int,int> playerStats(int player_kills, int player_deaths, int wild_dino_kills, int tamed_dino_kills);
{
return ( player_kills,player_deaths,wild_dino_kills,tamed_dino_kills );
}
}
{
void ShowMyStats(AShooterPlayerController* player_controller, FString*, EChatSendMode::Type)
{
const uint64 steam_id = ArkApi::IApiUtils::GetSteamIdFromController(player_controller);
int player_kills = 0;
int player_deaths = 0;
int wild_dino_kills = 0;
int tamed_dino_kills = 0;
if (ShopRewards::database->IsPlayerExists(steam_id))
{
std::tie(player_kills, player_deaths, wild_dino_kills, tamed_dino_kills) = ShopRewards::database->GetPlayerStats(steam_id);
}
ArkApi::GetApiUtils().SendChatMessage(player_controller, GetText("Sender"), *GetText("MyStats"), player_kills,
player_deaths, wild_dino_kills, tamed_dino_kills);
}
void Hook_UShooterCheatManager_BanPlayer(UShooterCheatManager* _this, FString PlayerSteamName)
void Hook_UShooterCheatManager_BanPlayer(UShooterCheatManager* _this, FString PlayerSteamName)
C:\Program Files (x86)\Steam\steamapps\common\ATLAS\ShooterGame\Binaries\Win64
and then copy my plugin files to C:\Program Files (x86)\Steam\steamapps\common\ATLAS\\ShooterGame\Binaries\Win64\AtlasApi\Plugins
and launch the single player game? (edited)UPrimalItem * Hook_UPrimalInventoryComponent_AddItem(UPrimalInventoryComponent* _this, FItemNetInfo* theItemInfo, bool bEquipItem, bool AddToSlot, bool bDontStack, FItemNetID* InventoryInsertAfterItemID, bool ShowHUDNotification, bool bDontRecalcSpoilingTime, bool bForceIncompleteStacking, AShooterCharacter* OwnerPlayer, bool bIgnoreAbsoluteMaxInventory)
{
auto Items_array = config["BannedItemsChecking"]["RemovedFromInventoryItems"];
//Log::GetLog()->warn("Hook Called");
UPrimalItem* item = UPrimalInventoryComponent_AddItem_original(_this, theItemInfo, bEquipItem, AddToSlot, bDontStack, InventoryInsertAfterItemID, ShowHUDNotification, bDontRecalcSpoilingTime, bForceIncompleteStacking, OwnerPlayer, bIgnoreAbsoluteMaxInventory);
if (item && !Items_array.empty())
{
FString FullName;
item->GetFullName(&FullName, nullptr);
//Log::GetLog()->warn("Item Is {}", FullName.ToString());
for (std::string Item : Items_array)
{
FString ItemName = Item.c_str();
if (FullName.Contains(ItemName))
{
FItemNetID itemID;
itemID = theItemInfo->ItemIDField();
_this->RemoveItem(&itemID, false, false, true, true);
}
}
}
return item;
}
for (TSubclassOf<UPrimalItem>& data : Globals::GEngine()
->GameSingletonField()->PrimalGameDataOverrideField()->
MasterItemListField())
{
if (!data.uClass)
continue;
UPrimalItem* item = (UPrimalItem*)data.uClass->GetDefaultObject(true);
if (!item)
continue;
item->MaxItemQuantityField() = 1000;
item->InventoryRefreshCheckItem();
item->UpdatedItem();
}
std::vector<std::string> headers;
headers.push_back("Content-Type:application/json");
headers.push_back("Accept-Charset:utf-8");
headers.push_back("Accept-Encoding:identity");
headers.push_back("Content-Encoding:identity");
try {
API::Requests::Get().CreatePostRequest(url_, callback, current_batch_.dump(-1, ' ', false, nlohmann::detail::error_handler_t::ignore), headers);
}
catch (std::exception& e) {
Log::GetLog()->error("{}", e.what());
}
thought I had this working but after a refactor/rebuild I'm getting the same issue again with Requests::Update... I have no idea what I'm doing wrong - I can try lowering batch count again but I was able to get batches of 100 entities working and now 25 is throwing an error >_< (edited) #include <Windows.h>
#include "API/Atlas/Atlas.h"
#pragma comment(lib, "ArkApi.lib")
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
ArkApi::GetApiUtils().SendServerMessageToAll(FColorList::Green, L"This is Welcome Message");
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
#include <Windows.h>
#include "API/Atlas/Atlas.h"
#pragma comment(lib, "ArkApi.lib")
#pragma comment(lib, "AtlasApi.lib")
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
// ArkApi::GetApiUtils().SendServerMessageToAll(FColorList::Green, L"This is Welcome Message");
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
FVector pos = ArkApi::IApiUtils::GetPosition(player_controller);
Log::GetLog()->warn("Player position X-{}, Y-{}, Z-{}", pos.X, pos.Y, pos.Z);//using this to debug
Is this not whats used for Atlas? iI dont see anything else and it seems to be whats used in Ark (edited)actor->RootComponentField()->RelativeLocationField()
FVector pos = player_controller->DefaultActorLocationField();
Thanks for the help!FString::Printf__VA
. I am attmepting to replace the data in the FString* but I am getting a crash, usually looking something like this[h:\livegamehotfixes\engine\source\runtime\core\public\hal\mallocbinned.h:1046]
FString* someHook(void* _this, FString* result)
{
result->Empty();
FString string1 = <some string from a field>
FString str = *FString("c string" + string1.ToString() + "another c string");
result->Append(str);
Log::GetLog()->log(spdlog::level::info, "Final String Is " + result->ToString());
return result;
}
void
void
crashes immediatelystruct UPrimalLocalProfile
{
void AddArkTributeDino(APrimalDinoCharacter dino) { NativeCall<void, APrimalDinoCharacter*>(this, "UPrimalLocalProfile.AddArkTributeDino", dino); }
};
_this->AddArkTributeDino(<some ptr>);
should be valid yeah?_this->AddArkTributeDino(<some ptr>)
= call this but use the hooks and `_this->AddArkTributeDino(<some ptr>, true)
= bypass hooks.AddArkTributeDino
have a branch to either call the hooked function, or the original based off the optional boolean.void SetItemStatValue(UPrimalItem* item, EPrimalItemStat::Type item_stat_type, const float new_value)
{
*(item->ItemStatValuesField()() + item_stat_type) = 0;
const float old_stat_modifier = item->GetItemStatModifier(item_stat_type);
*(item->ItemStatValuesField()() + item_stat_type) = 1;
*(item->ItemStatValuesField()() + item_stat_type) = (new_value - old_stat_modifier) / (item->GetItemStatModifier(item_stat_type) - old_stat_modifier);
switch (item_stat_type)
{
case EPrimalItemStat::MaxDurability:
if (item->bUseItemDurability()())
item->ItemDurabilityField() = item->GetItemStatModifier(item_stat_type);
break;
}
#ifdef Atlas
item->UpdatedItem();
#else
item->UpdatedItem(false);
#endif
}
_this->MyInventoryComponentField()->AddCustomFolder(*FString("some string")
ShooterGameServer.exe!FMallocBinned::Realloc() (0x00007ff60e1e4573) + 0 bytes [h:\trunk\engine\source\runtime\core\public\hal\mallocbinned.h:1026]
ShooterGameServer.exe!FHeapAllocator::ForAnyElementType::ResizeAllocation() (0x00007ff60d342125) + 43 bytes [h:\trunk\engine\source\runtime\core\public\containers\containerallocationpolicies.h:347]
ShooterGameServer.exe!UPrimalInventoryComponent::AddCustomFolder() (0x00007ff60d54e309) + 68 bytes [h:\trunk\projects\shootergame\source\shootergame\private\primalinventorycomponent.cpp:5541]
FString* test = new FString();
test->Append("test");
AddCustomFolderHook(_this->MyInventoryComponentField(), test, 768);
void AddCustomFolderHook(UPrimalInventoryComponent* _this, FString* CFolder, int InventoryCompType)
{
char buffer[1024];
sprintf_s(buffer, "Logged Data %s %i", CFolder->ToString(), InventoryCompType);
Log::GetLog()->log(spdlog::level::info, "[DEBUG] Add Custom Folder was called.");
Log::GetLog()->log(spdlog::level::info, buffer);
AddCustomFolder_original(_this, CFolder, InventoryCompType);
}
ShooterGameServer.exe!FMallocBinned::Realloc() (0x00007ff60e1e4573) + 0 bytes [h:\trunk\engine\source\runtime\core\public\hal\mallocbinned.h:1026]
ShooterGameServer.exe!FHeapAllocator::ForAnyElementType::ResizeAllocation() (0x00007ff60d342125) + 43 bytes [h:\trunk\engine\source\runtime\core\public\containers\containerallocationpolicies.h:347]
ShooterGameServer.exe!UPrimalInventoryComponent::AddCustomFolder() (0x00007ff60d54e309) + 68 bytes [h:\trunk\projects\shootergame\source\shootergame\private\primalinventorycomponent.cpp:5541]
&FString(TEXT("Test :)"))
void AddCustomFolderHook(UPrimalInventoryComponent* _this, FString* CFolder, int InventoryCompType)
{
CFolder->ReverseString();
AddCustomFolder_original(_this, CFolder, InventoryCompType);
}
This functions fine, and does as what is expected.void AddCustomFolderHook(UPrimalInventoryComponent* _this, FString* CFolder, int InventoryCompType)
{
AddCustomFolder_original(_this, CFolder, InventoryCompType);
CFolder->ReverseString();
AddCustomFolder_original(_this, CFolder, InventoryCompType);
}
This is crashing for me.ShooterGameServer.exe!TArray<FCustomVersion,FDefaultAllocator>::~TArray<FCustomVersion,FDefaultAllocator>() (0x00007ff6e4a969f6) + 13 bytes [h:\trunk\engine\source\runtime\core\public\containers\array.h:498]
ShooterGameServer.exe!FBitWriter::~FBitWriter() (0x00007ff6e3fd1022) + 0 bytes [UnknownFile:0]
ShooterGameServer.exe!UNetDriver::InternalProcessRemoteFunction() (0x00007ff6e5136206) + 0 bytes [h:\trunk\engine\source\runtime\engine\private\networkdriver.cpp:975]
void AddCustomFolderHook(UPrimalInventoryComponent* _this, FString* CFolder, int InventoryCompType)
{
FString text = TEXT("text literal");
AddCustomFolder_original(_this, &text, InventoryCompType);
}
is also crashing.IDataListProviderInterface::AddCustomFolder(IDataListProviderInterface *this, FString *CFolder, int InventoryCompType)
void AddCustomFolderHook(UPrimalInventoryComponent* _this, FString* CFolder, int InventoryCompType)
{
FString text = TEXT("text literal");
AddCustomFolder_original(_this, &text, InventoryCompType);
}
AddCustomFolderHook
in my plugin, I wrote it originally to log what the value of InventoryCompType
was FString* text = (FString*) FMemory::Malloc(sizeof(FString));
text->Empty();
text->Append("some text");
FString* text = (FString*) FMemory::Malloc(sizeof(FString));
text->Empty();
text->Append("some text");
AddCustomFolder_original(_this, text, InventoryCompType);
(edited)_this->MyInventoryComponentField()->AddCustomFolder()
?AddCustomFolder_original
from the DECLARE_HOOK
macrovoid AddCustomFolderHook(UPrimalInventoryComponent* _this, FString* CFolder, int InventoryCompType)
{
FString* text = (FString*) FMemory::Malloc(sizeof(FString));
text->Empty();
text->Append("some text");
AddCustomFolder_original(_this, text, InventoryCompType);
}
FString* text = (FString*) FMemory::Malloc(sizeof(FString));
be FString* text = (FString*) FMemory::Malloc(sizeof(void*));
? (edited)void AddCustomFolderHook(UPrimalInventoryComponent* _this, FString* CFolder, int InventoryCompType)
{
AddCustomFolder_original(_this, CFolder, InventoryCompType);
}
CFolder
such as FString->Append, works 100% fine.UProperty()
? I'm not sure how to add that if it does. I'm making a guess that it has UProperty()
internally as the FString of the input textbox would be a property. (edited)[2019.11.08-16.38.20:451][ 8]WinMain() __try _except guarded failure, no report?
[2019.11.08-16.38.20:451][ 8] - FPlatformMisc::RequestExit(1)
void Hook_APrimalDinoCharacter_TameDino(APrimalDinoCharacter* _this, AShooterPlayerController* ForPC, bool bIgnoreMaxTameLimit, int OverrideTamingTeamID, bool bPreventNameDialog, bool bSkipAddingTamedLevels)
{
APrimalDinoCharacter_TameDino_original(_this, ForPC, bIgnoreMaxTameLimit, OverrideTamingTeamID, bPreventNameDialog, bSkipAddingTamedLevels);
if (_this->MyInventoryComponentField())
{
ArkApi::GetApiUtils().SendChatMessageToAll("Server", "A Dino Was Tamed!");
_this->MyInventoryComponentField()->AddCustomFolder(<some text>, <some int>);
}
else {
Log::GetLog()->log(spdlog::level::info, "[DEBUG] NULL Inventory Comp!");
}
Log::GetLog()->log(spdlog::level::info, "[DEBUG] Tame Dino was called.");
}
_this->MyInventoryComponentField()->AddCustomFolder
has the same crash._this->MyInventoryComponentField()->AddCustomFolder
won't crash with my custom FString.InventoryCompType
so I could call the actual function with the correct value.AddCustomFolder
is called, it crashes with my supplied FStringVERSION: 300.7
ShooterGameServer.exe!FMallocBinned::Realloc() (0x00007ff6e4aa4573) + 0 bytes [h:\trunk\engine\source\runtime\core\public\hal\mallocbinned.h:1026]
ShooterGameServer.exe!FHeapAllocator::ForAnyElementType::ResizeAllocation() (0x00007ff6e3c02125) + 43 bytes [h:\trunk\engine\source\runtime\core\public\containers\containerallocationpolicies.h:347]
ShooterGameServer.exe!UPrimalInventoryComponent::AddCustomFolder() (0x00007ff6e3e0e309) + 68 bytes [h:\trunk\projects\shootergame\source\shootergame\private\primalinventorycomponent.cpp:5541]
ArkAdvert.dll!Hook_APrimalDinoCharacter_TameDino() (0x00007ff9e1336a41) + 208 bytes [C:\Users\Riley\source\repos\Ark-Server-Plugins-master\SomeHooks\ArkAdvert\ArkAdvert.cpp:78]
ShooterGameServer.exe!AShooterPlayerController::ForceTame() (0x00007ff6e40ae3f5) + 31 bytes [h:\trunk\projects\shootergame\source\shootergame\private\shooterplayercontroller.cpp:6064]
ShooterGameServer.exe!UFunction::Invoke() (0x00007ff6e4ae2ecf) + 6 bytes [h:\trunk\engine\source\runtime\coreuobject\private\uobject\class.cpp:3801]
void Hook_APrimalDinoCharacter_TameDino(APrimalDinoCharacter* _this, AShooterPlayerController* ForPC, bool bIgnoreMaxTameLimit, int OverrideTamingTeamID, bool bPreventNameDialog, bool bSkipAddingTamedLevels)
{
APrimalDinoCharacter_TameDino_original(_this, ForPC, bIgnoreMaxTameLimit, OverrideTamingTeamID, bPreventNameDialog, bSkipAddingTamedLevels);
if (_this->MyInventoryComponentField())
{
ArkApi::GetApiUtils().SendChatMessageToAll("Server", "A Dino Was Tamed!");
_this->MyInventoryComponentField()->AddCustomFolder(FString(TEXT("Test")), 768);
}
else {
Log::GetLog()->log(spdlog::level::info, "[DEBUG] NULL Inventory Comp!");
}
Log::GetLog()->log(spdlog::level::info, "[DEBUG] Tame Dino was called.");
}
FString* text = (FString*) FMemory::Malloc(sizeof(FString));
text->Empty();
text->Append("some text");
void __fastcall UPrimalInventoryComponent::AddCustomFolder(UPrimalInventoryComponent *this, FString *CFolder, int InventoryCompType)
AddCustomFolder_original
should suffice no?void AddArkTributeDino(APrimalDinoCharacter* dino) { NativeCall<void, APrimalDinoCharacter*>(this, "UPrimalLocalProfile.AddArkTributeDino", dino); }
(but for the function)_this->MyInventoryComponentField()->AddCustomFolder(FString(TEXT("Test")), 768);
crash ?_this->MyInventoryComponentField()->AddCustomFolder
this wasn't declared with FString*_this->MyInventoryComponentField()->AddCustomFolder
has always been byvalue_this->MyInventoryComponentField()->AddCustomFolder
and my AddCustomFolder_original
crash with my supplied FString_this->MyInventoryComponentField()->AddCustomFolder
= byvalueAddCustomFolder_original
= ptr_this->MyInventoryComponentField()->AddCustomFolder
bypass the hook?DECLARE_HOOK(AddCustomFolder, void, UPrimalInventoryComponent*, FString, int);
void AddCustomFolderHook(UPrimalInventoryComponent* _this, FString CFolder, int InventoryCompType)
which is never actually enabled (no EnableHook)_this->MyInventoryComponentField()->AddCustomFolder(FString(TEXT("Test")), 768);
Fatal error!
VERSION: 300.7
ShooterGameServer.exe!FMallocBinned::Realloc() (0x00007ff6e4aa4573) + 0 bytes [h:\trunk\engine\source\runtime\core\public\hal\mallocbinned.h:1026]
ShooterGameServer.exe!FHeapAllocator::ForAnyElementType::ResizeAllocation() (0x00007ff6e3c02125) + 43 bytes [h:\trunk\engine\source\runtime\core\public\containers\containerallocationpolicies.h:347]
ShooterGameServer.exe!UPrimalInventoryComponent::AddCustomFolder() (0x00007ff6e3e0e309) + 68 bytes [h:\trunk\projects\shootergame\source\shootergame\private\primalinventorycomponent.cpp:5541]
ArkAdvert.dll!Hook_APrimalDinoCharacter_TameDino() (0x00007ff9e47d6a51) + 208 bytes [C:\Users\Riley\source\repos\Ark-Server-Plugins-master\SomeHooks\ArkAdvert\ArkAdvert.cpp:90]
ShooterGameServer.exe!AShooterPlayerController::ForceTame() (0x00007ff6e40ae3f5) + 31 bytes [h:\trunk\projects\shootergame\source\shootergame\private\shooterplayercontroller.cpp:6064]
FString* text = (FString*) FMemory::Malloc(sizeof(FString));
text->Empty();
text->Append("some text");
auto text = new ("test") FString();
AddCustomFolder_original(_this, text, InventoryCompType);
auto text = (FString*)FMemory::Malloc(sizeof(void*));
new (text) FString();
auto text = (FString*)FMemory::Malloc(sizeof(FString));
new (text) FString();
AddCustomFolder_original(_this, text, InventoryCompType);
auto text = (FString*)FMemory::Malloc(sizeof(FString));
new (text) FString();
and never just use new
(for not malloc)? (edited)FString* test = new FString();
delete test
after the AddCustomFolder_original
callFString* test = new FString();
?new
is essentially the same as malloc
and new (var) <T>
auto text = (FString*)FMemory::Malloc(sizeof(FString));
new (text) FString();
auto text = (FString*)FMemory::Malloc(sizeof(FString));
new (text) FString();
text->Append("Happy");
AddCustomFolderHook(_this->MyInventoryComponentField(), text, 768);
AddCustomFolderHook
keeps crashing I might have to now auto text = (FString*)FMemory::Malloc(sizeof(FString));
new (text) FString();
text->Append("Happy");
_this->MyInventoryComponentField()->AddCustomFolder(text, 768);
ShooterGameServer.exe!FMallocBinned::Realloc() (0x00007ff6e4aa4573) + 0 bytes [h:\trunk\engine\source\runtime\core\public\hal\mallocbinned.h:1026]
ShooterGameServer.exe!FHeapAllocator::ForAnyElementType::ResizeAllocation() (0x00007ff6e3c02125) + 43 bytes [h:\trunk\engine\source\runtime\core\public\containers\containerallocationpolicies.h:347]
ShooterGameServer.exe!UPrimalInventoryComponent::AddCustomFolder() (0x00007ff6e3e0e309) + 68 bytes [h:\trunk\projects\shootergame\source\shootergame\private\primalinventorycomponent.cpp:5541]
void AddCustomFolder(FString* CFolder, int InventoryCompType) { NativeCall<void, FString*, int>(this, "UPrimalInventoryComponent.AddCustomFolder", CFolder, InventoryCompType); }
auto text = (FString*)FMemory::Malloc(sizeof(FString));
new (text) FString();
in the hookif ( this->vfptr[3].GetPerfObjectBulkDataPath((UObjectBase *)this, (FString *)(unsigned int)InventoryCompType) )
InventoryCompType
int InventoryCompType
InventoryCompType
is supposed to be set to. When I logged it, it had a value of 768 FHeapAllocator::ForAnyElementType::ResizeAllocation(
(TAlignedHeapAllocator<0>::ForAnyElementType *)&_this->DisplayDefaultItemInventoryCount,
v10,
v8,
v9)
void AddCustomFolderHook(UPrimalInventoryComponent* _this, FString* CFolder, int InventoryCompType)
{
char buffer[1024];
sprintf_s(buffer, "Logged Data %s %i", CFolder->ToString(), InventoryCompType);
Log::GetLog()->log(spdlog::level::info, "[DEBUG] Add Custom Folder was called.");
Log::GetLog()->log(spdlog::level::info, buffer);
if (CFolder->ToString() == "dbl")
{
auto text = (FString*)FMemory::Malloc(sizeof(FString));
new (text) FString();
text->Append("Happy");
AddCustomFolder_original(_this, text, InventoryCompType);
}
return AddCustomFolder_original(_this, CFolder, InventoryCompType);
}
UPrimalInventoryComponent
is invalid?APrimalDinoCharacter_TameDino_original(_this, ForPC, bIgnoreMaxTameLimit, OverrideTamingTeamID, bPreventNameDialog, bSkipAddingTamedLevels);
if (_this->MyInventoryComponentField() != nullptr)
{ //stuff }
MyInventoryComponentField
is a valid ptr, but isn't ready yet?void Hook_UPrimalInventoryComponent_RemoveCustomFolder(UPrimalInventoryComponent* _this, AShooterPlayerController* PC, FString FolderName, int InventoryCompType)
{
UPrimalInventoryComponent_RemoveCustomFolder_original(_this, PC, FolderName, InventoryCompType);
ArkApi::GetApiUtils().SendChatMessageToAll("Server", "A Dino Was Tamed!");
auto text = (FString*)FMemory::Malloc(sizeof(FString));
new (text) FString();
text->Append("Happy");
_this->AddCustomFolder(text, 768);
}
Timer(3000, true, &doFolder, _this);
VERSION: 301.2
ShooterGameServer.exe!FMallocBinned::Realloc() (0x00007ff728c422a3) + 0 bytes [f:\build\trunk\engine\source\runtime\core\public\hal\mallocbinned.h:1026]
ShooterGameServer.exe!FHeapAllocator::ForAnyElementType::ResizeAllocation() (0x00007ff727dea915) + 43 bytes [f:\build\trunk\engine\source\runtime\core\public\containers\containerallocationpolicies.h:347]
ShooterGameServer.exe!TArray<FString,FDefaultAllocator>::Emplace<FString const & __ptr64>() (0x00007ff727e79724) + 0 bytes [f:\build\trunk\engine\source\runtime\core\public\containers\array.h:1303]
ShooterGameServer.exe!UPrimalInventoryComponent::AddCustomFolder() (0x00007ff7280080a3) + 0 bytes [f:\build\trunk\projects\shootergame\source\shootergame\private\primalinventorycomponent.cpp:5542]
void doFolder(APrimalDinoCharacter* _this)
{
auto text = (FString*)FMemory::Malloc(sizeof(FString));
new (text) FString();
text->Append("Happy");
_this->MyInventoryComponentField()->AddCustomFolder(text, 768);
}
void Hook_APrimalDinoCharacter_TameDino(APrimalDinoCharacter* _this, AShooterPlayerController* ForPC, bool bIgnoreMaxTameLimit, int OverrideTamingTeamID, bool bPreventNameDialog, bool bSkipAddingTamedLevels)
{
APrimalDinoCharacter_TameDino_original(_this, ForPC, bIgnoreMaxTameLimit, OverrideTamingTeamID, bPreventNameDialog, bSkipAddingTamedLevels);
API::Timer::Get().DelayExecute(&doFolder, 5, _this);
if (_this->MyInventoryComponentField() != nullptr)
{
ArkApi::GetApiUtils().SendChatMessageToAll("Server", "A Dino Was Tamed!");
}
else {
Log::GetLog()->log(spdlog::level::info, "[DEBUG] NULL Inventory Comp!");
}
Log::GetLog()->log(spdlog::level::info, "[DEBUG] Tame Dino was called.");
}
*(double*)(((__int64(__fastcall*)(APrimalCharacter*))this->vfptr[6].RegisterDependencies)(this) + 2664)
Does anyone know ways to translate it (manually, of course) into readable representation? RegisterDependencies
is a member function of UStruct
but UStruct
doesn't related with APrimalCharacter
is I seen in the Api's codeIDataListEntryInterface::AddCustomFolder
does v3 = v2->Data.AllocatorInstance.Data;
where v3 is an FScriptContainerElement* and v2 is the FString*if ( v3 )
{
v4 = GMalloc;
if ( !GMalloc )
{
GCreateMalloc();
v4 = GMalloc;
}
((void (__fastcall *)(FMalloc *, FScriptContainerElement *))v4->vfptr[2].Exec)(v4, v3);
}
v3
isn't valid for the ((void (__fastcall *)(FMalloc *, FScriptContainerElement *))v4->vfptr[2].Exec)(v4, v3);
FString* fblueprint = (FString*)blueprint.c_str();
c_str()
is for getting a c string not an FString (edited).c_str()
could be returning the char[] directly instead of making a copy.APrimalDinoCharacter
?
For example, if I have a tame in-game the Awesome Spyglass shows the stats like HP of 29 points. How do I access that variable via the API?GetCharacterStatusComponent()
? Am I on the right track?ShooterGameMode* aShooterGameMode = ArkApi::GetApiUtils().GetShooterGameMode();
FString result;
aShooterGameMode->GetNetworkNumber(&result);
FString server_addr;
ArkApi::GetApiUtils().GetWorld()->GetAddressURL(&server_addr);
should give ip with portAPI::Requests::Get().CreateGetRequest("https://api.ipify.org?format=json", std::bind(&GetServerIP, std::placeholders::_1, std::placeholders::_2));
void GetServerIP(bool success, std::string response)
{
if (success)
{
if (response != "")
{
try
{
nlohmann::json parsedResponse = nlohmann::json::parse(response);
const std::string sIP = parsedResponse.value("ip", nlohmann::json::object());
}
catch (const std::exception& error)
{
Log::GetLog()->error(error.what());
}
}
}
}
(edited)In the context of servers, 0.0.0.0 can mean "all IPv4 addresses on the local machine". If a host has two IP addresses, 192.168.1.1 and 10.1.2.1, and a server running on the host is configured to listen on 0.0.0.0, it will be reachable at both of those IP addresses.
-serverip=
0
-serverip=
0.0.0.0
Hook_AShooterGameMode_AddNewTribe(AShooterGameMode* _this, AShooterPlayerState* PlayerOwner, FString* TribeName, FTribeGovernment* TribeGovernment)
const uint64 steamId = ArkApi::IApiUtils::GetSteamIdFromController(PlayerOwner->GetOwnerController());
auto playerId = _this->GetPlayerIDForSteamID(steamId);
auto tribeId = _this->GetTribeIDOfPlayerID(playerId);
(edited)GetOrLoadTribeData(...)
the server crashes, no log or stack, just closes.
AShooterGameMode* gameMode = ArkApi::GetApiUtils().GetShooterGameMode();
if (!gameMode) return;
FTribeData* ftribe;
if (gameMode->GetOrLoadTribeData(team.Key, ftribe)) {
if (!ftribe || ftribe == nullptr) Log::GetLog()->debug("GetOrLoadTribeData(...) returned null for team {}", team.Key);
else ownerID = ftribe->OwnerPlayerDataIDField();
}
// also with : LoadTribeData(...) // Crash
// : GetTribeData(...) // Crash
FTribeData* tribe_data = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(tribe_data, 0x200);
if (ArkApi::GetApiUtils().GetShooterGameMode()->GetOrLoadTribeData(
teamId, tribe_data))
{
//
}
FMemory::Free(tribe_data);
.arktributetribe
file?long double& LastNameChangeTimeField() ? >
#include <chrono>
using namespace std::chrono;
milliseconds ms = duration_cast< milliseconds >(
system_clock::now().time_since_epoch()
);
long time_stamp = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()
its converting from the return value of say LastNameChangeTimeField long double > long
where long ..
represents the unix epoch
i've thus far not been able to find a solution
I'm wondering how the game stores and uses its time values, are they consistent with real time, or some value based on the game "running" time where in game time stamps stop/pause while the server is offline and progress only while the server is operating.
If they are consistent with real time i could extrapolate a unix time stamp from time based fields, if they are not then i have no idea how, other than capturing events where times are needed and generating a time stamp, storing them for later calls/checks. (edited)for (TSubclassOf<UPrimalItem>& data : Globals::GEngine()
->GameSingletonField()->PrimalGameDataOverrideField()->
MasterItemListField())
{
if (!data.uClass)
continue;
UPrimalItem* item = (UPrimalItem*)data.uClass->GetDefaultObject(true);
if (!item)
continue;
item->MaxItemQuantityField() = 1000;
item->InventoryRefreshCheckItem();
item->UpdatedItem();
}
for (TSubclassOf<UPrimalItem>& data : Globals::GEngine()
->GameSingletonField()->PrimalGameDataOverrideField()->
MasterItemListField())
{
if (!data.uClass)
continue;
UPrimalItem* item = (UPrimalItem*)data.uClass->GetDefaultObject(true);
if (!item)
continue;
item->MaxItemQuantityField() = 1000;
item->InventoryRefreshCheckItem();
item->UpdatedItem();
}
But the 'PrimalGameDataOverrideField()' isnt there anymore ?Globals::GEngine()->GameSingletonField()->PrimalGameDataOverrideField()->MasterItemListField()
I tried
Globals::GEngine().Get()->GameSingletonField()->
but then theres no PrimalGameDataOverrideField anymore ?auto test = static_cast<UPrimalGlobals>Globals::GEngine().Get()->GameSingletonField();
(edited)static_cast<UPrimalGlobals*>(Globals::GEngine()()->GameSingletonField())->PrimalGameDataOverrideField()
struct __cppobj FFrame : FOutputDevice
{
UFunction *Node;
UObject *Object;
char *Code;
char *Locals;
UProperty *MostRecentProperty;
char *MostRecentPropertyAddress;
TArray<unsigned int,TInlineAllocator<8,FDefaultAllocator> > FlowStack;
FFrame *PreviousFrame;
FOutParmRec *OutParms;
UField *PropertyChainForCompiledIn;
UFunction *CurrentNativeFunction;
};
std::vector<std::string> configOverrideItemMaxQuantity;
for (TSubclassOf<UPrimalItem>& data : static_cast<UPrimalGlobals*>(Globals::GEngine()()->GameSingletonField())->PrimalGameDataOverrideField()->MasterItemListField())
{
if (!data.uClass)
continue;
UPrimalItem* n = (UPrimalItem*)data.uClass->GetDefaultObject(true);
if (!n)
continue;
if (n->IsUsableConsumable() || n->IsValidForCrafting() || n->IsInBlueprint())
{
FString fPathName;
n->GetPathName(&fPathName, NULL);
std::string pathName = fPathName.ToString();
pathName = pathName.substr(pathName.find("Default__") + 9);
int maxItemQuantityField = n->MaxItemQuantityField();
configOverrideItemMaxQuantity.push_back(fmt::format("ConfigOverrideItemMaxQuantity=(ItemClassString=\"{0}\",Quantity=(MaxItemQuantity={1},bIgnoreMultiplier=true))\n", pathName, maxItemQuantityField));
}
}
std::sort(configOverrideItemMaxQuantity.begin(), configOverrideItemMaxQuantity.end());
std::string output;
for (const auto& text : configOverrideItemMaxQuantity) output += text;
std::ofstream file("ConfigOverrideItemMaxQuantity.txt");
file << output;
file.flush();
file.close();
(edited)n->IsUsableConsumable() || n->IsValidForCrafting()
But maybe there's a 3rd option too ? It creates this:
ConfigOverrideItemMaxQuantity=(ItemClassString="PrimalItemAmmo_AdvancedBullet_C",Quantity=(MaxItemQuantity=100,bIgnoreMultiplier=true))
ConfigOverrideItemMaxQuantity=(ItemClassString="PrimalItemAmmo_AdvancedRifleBullet_C",Quantity=(MaxItemQuantity=100,bIgnoreMultiplier=true))
ConfigOverrideItemMaxQuantity=(ItemClassString="PrimalItemAmmo_ArrowStone_C",Quantity=(MaxItemQuantity=100,bIgnoreMultiplier=true))
[...]
Actor.h
void UploadCharacterPlayerDataToArk(
TArray<unsigned char>*
PlayerDataBytes,
FString PlayerName,
TArray<FString> PlayerStats,
unsigned __int64 PlayerDataId,
bool WithItems,
unsigned int ItemCount
) { NativeCall<
void,
TArray<unsigned char>*,
FString,
TArray<FString>,
unsigned __int64,
bool,
unsigned int
>
(
this,
"AShooterPlayerController.UploadCharacterPlayerDataToArk",
PlayerDataBytes,
PlayerName,
PlayerStats,
PlayerDataId,
WithItems,
ItemCount
);
}
From this i build.. (has errors and crashes)
DECLARE_HOOK(
AShooterPlayerController_UploadCharacterPlayerDataToArk,
void,
TArray<unsigned char>*,
FString,
TArray<FString>,
unsigned __int64,
bool,
unsigned int
);
void Hook_AShooterPlayerController_UploadCharacterPlayerDataToArk(
TArray<unsigned char>* PlayerDataBytes,
FString PlayerName,
TArray<FString> PlayerStats,
unsigned __int64 PlayerDataId,
bool WithItems,
unsigned int ItemCount
)
{ ...code...}
For some reason i get errors unless i add AShooterGameMode*
to the set of parameters, i'm wondering if this is the case for all hooks and if not why? i'm not experienced at all with this and i'm mostly learning from existing code provided by @Michidu & OwnProxGameMode
is null when the program runs:
DECLARE_HOOK(
AShooterPlayerController_UploadCharacterPlayerDataToArk,
AShooterGameMode*,
void,
TArray<unsigned char>*,
FString,
TArray<FString>,
unsigned __int64,
bool,
unsigned int
);
void Hook_AShooterPlayerController_UploadCharacterPlayerDataToArk(
AShooterGameMode* GameMode,
TArray<unsigned char>* PlayerDataBytes,
FString _PlayerName,
TArray<FString> PlayerStats,
unsigned __int64 PlayerDataId,
bool WithItems,
unsigned int ItemCount
)
{ ...code...}
Just looking for some clarification on whether this is the method i should use.player.beginplay()
the first parameter is always internally this
, thus for your hook you need to also pass this
for methods that are static methods
e.g.
player::somethingblahblah()
there is no this
parameterclass Hello
{
public:
void Hi();
static void Bye();
};
void Hi()
actually has a hidden parameter called this
that is inserted when the program is compiled.
but static void Bye()
does not FVector OutLoc;
FRotator OutRot;
PlayerController->GetPlayerViewPoint(&OutLoc, &OutRot);
FVector ForwardVector;
PlayerController->GetActorForwardVector(&ForwardVector);
FVector End = ForwardVector * 5000.0f + OutLoc;
TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes = { EObjectTypeQuery::ObjectTypeQuery9 };
TArray<AActor*> ActorsToIgnore = { PlayerController->GetPlayerCharacter() };
FHitResult HitResult;
if (UKismetSystemLibrary::LineTraceSingleForObjects(
ArkApi::GetApiUtils().GetWorld(),
OutLoc,
End,
&ObjectTypes,
false,
&ActorsToIgnore,
EDrawDebugTrace::None,
&HitResult,
true
))
{
auto actor = HitResult.ActorField().Get(false);
FString DisplayName;
UKismetSystemLibrary::GetDisplayName(&DisplayName, actor);
Log::GetLog()->warn("{}", DisplayName.ToString());
}
Would anyone have any idea why this crashes moments after it logs the desired output (what I am looking at)? It doesn't leave a crash stack, just immediately closes shootergameserver.exe BuyCommand
c++
auto game_mode = ArkApi::GetApiUtils().GetShooterGameMode();
auto player_id = game_mode->GetPlayerIDForSteamID(steam_id);
const uint64 tribe_id = game_mode->GetTribeIDOfPlayerID(player_id);
FString fcommand = fmt::format(command, fmt::arg("steamid", steam_id), fmt::arg("tribeid", tribe_id), fmt::arg("playerid", player_id)).c_str();
Log::GetLog()->info(fmt::format("[Buy cmd] steamid:{} tribeid:{} playerid:{} cmd:{}",steam_id,tribe_id,player_id, fcommand.ToString()));
FString result;
player_controller->ConsoleCommand(&result, &fcommand, true);
It works fine when I do it for myself, Ark-log:
02/21/20 20:47 [ArkShop][info] [Buy cmd] steamid:76561198170352161 tribeid:1662978856 playerid:152942838 cmd:NPP.AddProtection 1662978856 168
02/21/20 20:47 [NewPlayerProtection][info] Admin: 76561198170352161 added 168 hours of NPP Protection to Tribe: 1662978856.
But when players buy only one of the rows outputs and players dont get protection:
02/21/20 20:01 [ArkShop][info] [Buy cmd] steamid:76561198007030433 tribeid:1479612071 playerid:858649124 cmd:NPP.AddProtection 1479612071 168
Have only seen one player try this, but one error is disturbing enough.
Any clues? Big thanks to any clue!PC->TargetingTeamField()
player_controller->ConsoleCommand
and then change it back right after? Or are these events messaged somehow and happens in unknown order? (sry for not being a programming pro here). But since I might use the shop for any command in the future I think that's the way to go. (edited)PC->bIsAdmin() = true;
void UnlockEngrams_Cmd(AShooterPlayerController* PlayerController, FString* message, int mode)
{
auto Singleton = (UPrimalGlobals*)Globals::GEngine().Get()->GameSingletonField();
auto GameData = Singleton->PrimalGameDataOverrideField() ? Singleton->PrimalGameDataOverrideField() : Singleton->PrimalGameDataField();
auto EngramClasses = GameData->EngramBlueprintEntriesField();
for (auto&& Engram : EngramClasses)
((AShooterPlayerState*)PlayerController->PlayerStateField())->ServerUnlockEngram(Engram->BluePrintEntryField(), true, true);
}
If anyone is interested (edited)ArkApi::GetCommands().AddChatCommand("/unlockengrams", &UnlockEngrams_Cmd);
c++
//Lets make admin for a split micro second :)
auto admin_state = player_controller->bIsAdmin(); // saving admin status
player_controller->bIsAdmin() = true; // set temp admin
player_controller->ConsoleCommand(&result, &fcommand, true); // Do command!
player_controller->bIsAdmin() = admin_state; // rollback admin status
Can this be risky? and why do the star stick? UShooterCheatManager::SpawnActor
but that might be too high lvlUWorld::SpawnActor
might do itLog::Get().Init("ArkMod");
logger_ = std::make_shared<spdlog::logger>(plugin_name, begin(sinks), end(sinks));
this line creates the error#if _ITERATOR_DEBUG_LEVEL == 2
_Lockit _Lock(_LOCK_DEBUG);
_Orphan_me();
#endif // _ITERATOR_DEBUG_LEVEL == 2
} else { // have a parent, do adoption
_Container_proxy* _Parent_proxy = _Parent->_Myproxy;
#if _ITERATOR_DEBUG_LEVEL == 2
if (_Myproxy != _Parent_proxy) { // change parentage
_Lockit _Lock(_LOCK_DEBUG);
_Orphan_me();
_Mynextiter = _Parent_proxy->_Myfirstiter;
_Parent_proxy->_Myfirstiter = this;
_Myproxy = _Parent_proxy;
}
#else // _ITERATOR_DEBUG_LEVEL == 2
_Myproxy = _Parent_proxy;
#endif
is the src of the error, okvoid Load()
{
Log::Get().Init("ArkMod");
try
{
ArkApi::GetCommands().AddChatCommand("/TestSpawn", &Spawn);
}
catch (const std::exception& error)
{
Log::GetLog()->error(error.what());
throw;
}
}
and my dllmain:
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
try {
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Load();
break;
case DLL_PROCESS_DETACH:
Unload();
break;
}
return TRUE;
}
catch (const std::exception& error)
{
std::cout << error.what();
Log::GetLog()->error(error.what());
}
}
ArkApi::GetCommands().AddChatCommand("/TestSpawn", &Spawn);
c++
AShooterPlayerState* playerState = static_cast<AShooterPlayerState*>(player->PlayerStateField());
FTribeData* tribeData = playerState->MyTribeDataField();
uint64 tribeOwnerId = tribeData->OwnerPlayerDataIDField();
AShooterPlayerState* State = static_cast<AShooterPlayerState*>(player_controller->PlayerStateField());
FTribeData* tribe = State->MyTribeDataField();
if (!tribe)
return;
uint64 tribeOwnerId = tribe->OwnerPlayerDataIDField();
uint64 playerId = player_controller->GetLinkedPlayerID64();
bool isOwner = (playerId == tribeOwnerId);
This is what I ended up with and it works if anyone needs a full example. (edited)#include <iostream>
#include <API/ARK/Ark.h>
#pragma comment(lib, "ArkApi.lib")
UE_LOG
, I just have to cout?Log::GetLog()->info(string here);
#define DEFINE_CONTROL_CHANNEL_MESSAGE(Name, Index, ...) \
enum { NMT_##Name = Index }; \
template<> class FNetControlMessage<Index> \
{ \
public: \
template<typename... ParamTypes> \
static void Send(UNetConnection* Conn, ParamTypes&... Params) \
{ \
NativeCall<void, UNetConnection*, ParamTypes...>(nullptr, "FNetControlMessage<" #Index ">.Send", Conn, Params...); \
} \
};
DEFINE_CONTROL_CHANNEL_MESSAGE(Netspeed, 4, int32);
DEFINE_CONTROL_CHANNEL_MESSAGE(Failure, 6, FString);
DEFINE_CONTROL_CHANNEL_MESSAGE(Join, 9, uint64);
DEFINE_CONTROL_CHANNEL_MESSAGE(Skip, 12, FGuid);
DEFINE_CONTROL_CHANNEL_MESSAGE(Abort, 13, FGuid);
DEFINE_CONTROL_CHANNEL_MESSAGE(PCSwap, 15, int32);
DEFINE_CONTROL_CHANNEL_MESSAGE(ActorChannelFailure, 16, int32);
DEFINE_CONTROL_CHANNEL_MESSAGE(DebugText, 17, FString);
DEFINE_CONTROL_CHANNEL_MESSAGE(BuildIdMismatch, 19, uint32);
DEFINE_CONTROL_CHANNEL_MESSAGE(InitBattlEye, 22, FString);
DEFINE_CONTROL_CHANNEL_MESSAGE(BeaconWelcome, 25);
DEFINE_CONTROL_CHANNEL_MESSAGE(BeaconJoin, 26, FString);
DEFINE_CONTROL_CHANNEL_MESSAGE(BeaconAssignGUID, 27, FNetworkGUID);
DEFINE_CONTROL_CHANNEL_MESSAGE(BeaconNetGUIDAck, 28, FString);
FTribeData* tribe_data = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(tribe_data, 0x200);
ArkApi::GetApiUtils().GetShooterGameMode()->LoadTribeData(TribeId, tribe_data, false, false);
const string tribeName = tribe_data->TribeNameField().ToString();
Is this the only way to be able to look up a Tribe Name? (edited)#ifdef ATLAS
#include <API/Atlas/Atlas.h>
#pragma comment(lib, "AtlasApi.lib")
#else
#include <API/ARK/Ark.h>
#pragma comment(lib, "ArkApi.lib")
#endif
ADroppedItemEgg::UpdateEgg
MyItem->ItemDurability
(edited)if (MyItem->ItemDurabilityField() <= 0.f)
{
auto playerID = MyItem->DroppedByPlayerIDField();
//do something with player id
}
(edited)/* public: void __cdecl ADroppedItemEgg::UpdateEgg(float) __ptr64 */
void __thiscall UpdateEgg(ADroppedItemEgg *this,float param_1)
{
@substitutevoid __usercall ADroppedItemEgg::UpdateEgg(ADroppedItemEgg *this@<rcx>, float DeltaSeconds@<xmm1>, float a3@<xmm0>)
I think a3 might be IDA error btw (edited)DECLARE_HOOK(ADroppedItemEgg_UpdateEgg, void, ADroppedItemEgg*, float DeltaSeconds*);
ArkApi::GetHooks().SetHook("ADroppedItemEgg.UpdateEgg", yourCallback, &ADroppedItemEgg_UpdateEgg_original);
struct ADroppedItemEgg : ADroppedItem
{
float& IndoorsHypoThermalInsulationField() { return *GetNativePointerField<float*>(this, "ADroppedItemEgg.IndoorsHypoThermalInsulation"); }
float& IndoorsHyperThermalInsulationField() { return *GetNativePointerField<float*>(this, "ADroppedItemEgg.IndoorsHyperThermalInsulation"); }
float& EggThermalInsulationTemperatureMultiplierField() { return *GetNativePointerField<float*>(this, "ADroppedItemEgg.EggThermalInsulationTemperatureMultiplier"); }
double& LastInsulationCalcTimeField() { return *GetNativePointerField<double*>(this, "ADroppedItemEgg.LastInsulationCalcTime"); }
float& HyperThermalInsulationField() { return *GetNativePointerField<float*>(this, "ADroppedItemEgg.HyperThermalInsulation"); }
float& HypoThermalInsulationField() { return *GetNativePointerField<float*>(this, "ADroppedItemEgg.HypoThermalInsulation"); }
BitFieldValue<bool, unsigned __int32> bIsEggTooHot() { return { this, "ADroppedItem.bIsEggTooHot" }; }
BitFieldValue<bool, unsigned __int32> bIsEggTooCold() { return { this, "ADroppedItem.bIsEggTooCold" }; }
};
c++
if (playerController)
{
uint64 steamId = ArkApi::GetApiUtils().GetSteamIdFromController(playerController);
}
I get a crash from time to time calling it ??DECLARE_HOOK(ADroppedItemEgg_UpdateEgg, void, ADroppedItemEgg*, float*);
void Hook_ADroppedItemEgg_UpdateEgg(ADroppedItemEgg* _this, float* DeltaSeconds)
{
std::cout << "Hook_ADroppedItemEgg_UpdateEgg FIRING BEFORE" << std::endl;
ADroppedItemEgg_UpdateEgg_original(_this, DeltaSeconds);
std::cout << "Hook_ADroppedItemEgg_UpdateEgg FIRING AFTER" << std::endl;
}
ArkApi::GetHooks().SetHook("ADroppedItemEgg.UpdateEgg", &Hook_ADroppedItemEgg_UpdateEgg, &ADroppedItemEgg_UpdateEgg_original);
ArkApi::GetHooks().DisableHook("ADroppedItemEgg.UpdateEgg", &Hook_ADroppedItemEgg_UpdateEgg);
c++
auto* steam_net_id = static_cast<FUniqueNetIdSteam*>(player_state->UniqueIdField().UniqueNetId.Get());
this is the crash log:
VERSION.dll!ArkApi::IApiUtils::GetSteamIdFromController() (0x00007ffbc58c2f2b) + 8 bytes [C:\Users\Meduz\source\repos\ArkServerAPI\version\Core\Public\Ark\ArkApiUtils.h:195]
{
"structures": [
"ADroppedItemEgg"
]
}
try {
UPrimalItem* item = _this->MyItemField();
if (item) {
if (item->ItemDurabilityField() <= 0.f) {
FString itemName = item->DescriptiveNameBaseField();
AShooterPlayerController* pc = ArkApi::GetApiUtils().FindControllerFromCharacter(item->GetOwnerPlayer());
if (pc)
{
AShooterPlayerState* State = static_cast<AShooterPlayerState*>(pc->PlayerStateField());
if (State) {
FTribeData* tribe = State->MyTribeDataField();
(edited)unsigned __int64& DroppedByPlayerIDField() { return *GetNativePointerField<unsigned __int64*>(this, "ADroppedItem.DroppedByPlayerID"); }
struct ADroppedItem : AActor
TWeakObjectPtr<AActor> & DroppedByActorField() { return *GetNativePointerField<TWeakObjectPtr<AActor>*>(this, "ADroppedItem.DroppedByActor"); }
AddToTribeLog
ArkApi::GetCommands().AddRconCommand
(edited)CrossServerKey,UserId,SteamName,Nickname,Tribename,Message with Prefix
this will be send to other servers..Dino->bIsBaby().Get()
void SetItemStatValue(UPrimalItem* item, EPrimalItemStat::Type item_stat_type, const float new_value)
{
float newStat = 0.f;
if (item_stat_type == EPrimalItemStat::Armor || item_stat_type == EPrimalItemStat::MaxDurability)
{
item->ItemStatValuesField()()[item_stat_type] = 0;
float old_stat_modifier = item->GetItemStatModifier(item_stat_type);
item->ItemStatValuesField()()[item_stat_type] = 1;
newStat = (new_value - old_stat_modifier) / (item->GetItemStatModifier(item_stat_type) - old_stat_modifier);
}
else if (item_stat_type == EPrimalItemStat::WeaponDamagePercent)
{
item->ItemStatValuesField()()[item_stat_type] = 0;
float min_damage = item->GetItemStatModifier(item_stat_type);
item->ItemStatValuesField()()[item_stat_type] = 65535;
float max_damage = item->GetItemStatModifier(item_stat_type);
float diff = max_damage - min_damage;
float multiplier = 65535 / diff;
newStat = new_value / 100.f - min_damage;
newStat *= multiplier;
newStat += 1.f;
}
if (newStat >= 65536.f)
newStat = 65535;
item->ItemStatValuesField()()[item_stat_type] = newStat;
if (item_stat_type == EPrimalItemStat::MaxDurability)
{
if (item->bUseItemDurability()())
item->ItemDurabilityField() = item->GetItemStatModifier(item_stat_type);
}
#ifdef Ark
item->UpdatedItem(false);
#endif
#ifdef Atlas
item->UpdatedItem();
#endif
}
(edited)FString verb = "POST";
const bool result = ArkApi::Requests::Get().CreateRequest(DiscordWebhookURL, verb , &RequestCallback, FString(my_json.dump()), true, "application/json");
(edited)ShooterGameState->HTTPPostRequest(DiscordWebhook, request.c_str());
AShooterGameMode* GameMode = ArkApi::GetApiUtils().GetShooterGameMode();
AGameState* GameState = GameMode->GameStateField();
AShooterGameState* ShooterGameState = static_cast<AShooterGameState*>(GameState);
std::wstring request;
IsFirstPlayerSpawn
or HandleNewPlayer
and maybe OnLogout
- is this correct?c++
DECLARE_HOOK(AShooterGameMode_HandleNewPlayer, bool, AShooterGameMode*, AShooterPlayerController*, UPrimalPlayerData*, AShooterCharacter*, bool);
DECLARE_HOOK(AShooterGameMode_Logout, void, AShooterGameMode*, AController*);
IsFirstPlayerSpawn
?DECLARE_HOOK(AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation, void, AShooterPlayerState*, FPrimalPlayerCharacterConfigStructReplicated);
void Hook_AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation(AShooterPlayerState* _this, FPrimalPlayerCharacterConfigStructReplicated PlayerCharacterConfig)
{
if (_this && !PlayerCharacterConfig.PlayerCharacterName.IsEmpty())
{
if ((IsInvalidNameCharacter(PlayerCharacterConfig.PlayerCharacterName) || IsNameInBlackListCharacter(PlayerCharacterConfig.PlayerCharacterName)) && _this->GetShooterController())
{
ArkApi::GetApiUtils().SendNotification(_this->GetShooterController(), { 1,0,0,1 }, 2, 5, nullptr, *NameControl::conf::CannotUseCharacterName);
_this->GetShooterController()->ClientShowCharacterCreationUI(false);
return;
}
}
AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation_original(_this, PlayerCharacterConfig);
}
(edited)int IncrementItemTemplateQuantity(TSubclassOf<UPrimalItem> ItemTemplate, int amount, bool bReplicateToClient, bool bIsBlueprint, UPrimalItem * *UseSpecificItem, UPrimalItem * *IncrementedItem, bool bRequireExactClassMatch, bool bIsCraftingResourceConsumption, bool bIsFromUseConsumption, bool bIsArkTributeItem, bool ShowHUDNotification, bool bDontRecalcSpoilingTime, bool bDontExceedMaxItems) { return NativeCall<int, TSubclassOf<UPrimalItem>, int, bool, bool, UPrimalItem**, UPrimalItem**, bool, bool, bool, bool, bool, bool, bool>(this, "UPrimalInventoryComponent.IncrementItemTemplateQuantity", ItemTemplate, amount, bReplicateToClient, bIsBlueprint, UseSpecificItem, IncrementedItem, bRequireExactClassMatch, bIsCraftingResourceConsumption, bIsFromUseConsumption, bIsArkTributeItem, ShowHUDNotification, bDontRecalcSpoilingTime, bDontExceedMaxItems); }
?throw;
statement and find the call hierarchy which might yield some better functions
auto chatIcon = static_cast<ChatIcon>(icon);
UTexture2D *iconTexture = nullptr;
// get chat icon
if (chatIcon == ChatIcon::Admin)
{
auto engine = Globals::GEngine()();
auto primalglobals = engine->GameSingletonField()();
auto gamedata = primalglobals->PrimalGameDataOverrideField()();
if (!gamedata) gamedata = primalglobals->PrimalGameDataField()();
auto texture = gamedata->NameTagServerAdminField()();
if (texture) iconTexture = gamedata->NameTagServerAdminField()();
}
(edited) if (chatIcon == ChatIcon::Admin)
{
auto engine = Globals::GEngine()();
auto primalglobals = static_cast<UPrimalGlobals*>(engine->GameSingletonField());
auto gamedata = primalglobals->PrimalGameDataOverrideField();
if (!gamedata) gamedata = primalglobals->PrimalGameDataField();
auto texture = gamedata->NameTagServerAdminField();
if (texture) iconTexture = gamedata->NameTagServerAdminField();
}
DataValue<Type*>
instead of a raw pointer. (edited)DataValue<UEngine*>
, but GameSingletonField
returns UObject*
directly.GEngine()
returns DataValue<UEngine*>
DataValue<T>()
I believe is overloaded to return the pointer contained in that structure
GEngine()()
is the same as doing
auto EngineDV = GEngine();
auto Engine = EngineDV();
()
to reduce the need for variables T& operator()() const
{
return *value_;
}
DataValue
but does not nowNone
?
FName funcname = FName(TEXT("TestA"), EFindName::FNAME_Find, true);
FString nameString;
funcname.ToString(&nameString);
Log::GetLog()->warn("Function Check: {}", nameString.ToString());
None
?FName(TEXT("TestA"))
try thisFName::Init(&v146, L"None", 0, FNAME_Add, 0, 0);
FName::Init(&v146, L"None", 0, FNAME_Add, 0, 0);
FName::Init(&v147, L"ByteProperty", 0, FNAME_Add, 0, 1);
FName::Init(&v148, L"IntProperty", 0, FNAME_Add, 0, 2);
FName::Init(&v149, L"BoolProperty", 0, FNAME_Add, 0, 3);
FName::Init(&v6, L"FloatProperty", 0, FNAME_Add, 0, 4);
FName::Init(&v76, L"ObjectProperty", 0, FNAME_Add, 0, 5);
FName::Init(&v8, L"NameProperty", 0, FNAME_Add, 0, 6);
....
FName::Init(&v135, L"InterpCurveVector", 0, FNAME_Add, 0, 408);
FName::Init(&v137, L"InterpCurveTwoVectors", 0, FNAME_Add, 0, 409);
FName::Init(&v139, L"InterpCurveQuat", 0, FNAME_Add, 0, 410);
FName::Init(&v141, L"AI", 0, FNAME_Add, 0, 450);
FName::Init(&v143, L"NavMesh", 0, FNAME_Add, 0, 451);
FName::Init(&v145, L"PerformanceCapture", 0, FNAME_Add, 0, 500);
(edited)FName(TEXT("TestFunctionA"), EFindName::FNAME_Add, true);
FName funcname = FName(TEXT("TestFunctionA"), EFindName::FNAME_Find, true);
even no joy with this..
FName funcname = FName(TEXT("TestFunctionA"), EFindName::FNAME_Add, true);
also with ...FNAME_Add, false);
no joyvoid APrimalDinoCharacter::BrakeDinoBP(float val)
{
static auto fn = UObject::FindObject<UFunction>("Function ShooterGame.PrimalDinoCharacter.BrakeDinoBP");
APrimalDinoCharacter_BrakeDinoBP_Params params;
params.val = val;
auto flags = fn->FunctionFlags;
UObject::ProcessEvent(fn, ¶ms);
fn->FunctionFlags = flags;
}
struct Packed
{
char* parameters;
char* returnValue;
int size;
};
template<typename ...Ts> Packed f(Ts&&... args)
{
int i = sizeof...(Ts);
Packed packed;
packed.size = (sizeof(Ts) + ...);
char* memoryBlock = (char*)calloc(1, packed.size);
packed.parameters = memoryBlock;
auto pack = [&memoryBlock, &packed](auto& item)
{
memcpy(memoryBlock, &item, sizeof(item));
packed.returnValue = memoryBlock;
memoryBlock += sizeof(item); //move pointer forward
};
(pack(args), ...);
return packed;
}
Hook_AShooterGameMode_BeginPlay
after AShooterGameMode_BeginPlay_original
auto engine = Globals::GEngine()();
auto primalglobals = static_cast<UPrimalGlobals*>(engine->GameSingletonField());
auto gamedata = primalglobals->PrimalGameDataOverrideField();
// if (!gamedata) gamedata = primalglobals->PrimalGameDataField();
auto singletons = gamedata->ServerExtraWorldSingletonActorClassesField();
for (auto singleton : singletons) {
if (singleton.uClass) {
FString className;
singleton.uClass->GetDescription(&className);
if (className.Equals("Singleton_TestSingleton")) {
TArray<AActor*> SingletonActors;
UGameplayStatics::GetAllActorsOfClass(reinterpret_cast<UObject*>(ArkApi::GetApiUtils().GetWorld()), singleton, &SingletonActors);
for (auto singletonactor : SingletonActors) {
// works if i use the name of the class as the fucntion name
// FName funcname = singletonactor->NameField();
FName funcname = FName(TEXT("TestA"), EFindName::FNAME_Find, true);
FString nameString;
funcname.ToString(&nameString);
if (nameString.ToString() == "None") {
Log::GetLog()->warn("Function Check: {} for {}", nameString.ToString(), "TestA");
return;
}
UFunction* Func = singletonactor->FindFunctionChecked(funcname);
if (Func) {
int Args[] = { shooter_game_mode->ServerIDField() };
singletonactor->ProcessEvent(Func, Args);
} else {
Log::GetLog()->warn("No Function with name");
}
}
}
}
}
(edited) FUniqueNetIdSteam* steam_net_id = static_cast<FUniqueNetIdSteam*>(
_this->GetPlayerData()->MyDataField()->UniqueIDField().UniqueNetId.Get());
const uint64 victim_steam_id = steam_net_id->UniqueNetId;
Hook_AShooterCharacter_Die(AShooterCharacter* _this
GetSteamIdFromController
but that wants AController
void Hook_AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation(AShooterPlayerState* _this, FPrimalPlayerCharacterConfigStructReplicated PlayerCharacterConfig)
{
if (_this && !PlayerCharacterConfig.PlayerCharacterName.IsEmpty())
{
if ((IsInvalidNameCharacter(PlayerCharacterConfig.PlayerCharacterName) || IsNameInBlackListCharacter(PlayerCharacterConfig.PlayerCharacterName)) && _this->GetShooterController())
{
ArkApi::GetApiUtils().SendNotification(_this->GetShooterController(), { 1,0,0,1 }, 2, 5, nullptr, *NameControl::conf::CannotUseCharacterName);
_this->GetShooterController()->ClientShowCharacterCreationUI(false);
return;
}
}
AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation_original(_this, PlayerCharacterConfig);
}
struct FPrimalPlayerCharacterConfigStructReplicated
{
char __padding[0xb8L];
FieldArray<FLinearColor, 4> BodyColorsField() { return {this, "FPrimalPlayerCharacterConfigStructReplicated.BodyColors"}; }
FString& PlayerCharacterNameField() { return *GetNativePointerField<FString*>(this, "FPrimalPlayerCharacterConfigStructReplicated.PlayerCharacterName"); }
FieldArray<float, 22> RawBoneModifiersField() { return {this, "FPrimalPlayerCharacterConfigStructReplicated.RawBoneModifiers"}; }
int& PlayerSpawnRegionIndexField() { return *GetNativePointerField<int*>(this, "FPrimalPlayerCharacterConfigStructReplicated.PlayerSpawnRegionIndex"); }
// Functions
FPrimalPlayerCharacterConfigStruct * GetPlayerCharacterConfig(FPrimalPlayerCharacterConfigStruct * result) { return NativeCall<FPrimalPlayerCharacterConfigStruct *, FPrimalPlayerCharacterConfigStruct *>(this, "FPrimalPlayerCharacterConfigStructReplicated.GetPlayerCharacterConfig", result); }
FPrimalPlayerCharacterConfigStructReplicated * operator=(FPrimalPlayerCharacterConfigStructReplicated * __that) { return NativeCall<FPrimalPlayerCharacterConfigStructReplicated *, FPrimalPlayerCharacterConfigStructReplicated *>(this, "FPrimalPlayerCharacterConfigStructReplicated.operator=", __that); }
};
#include "BaseDeclarations.h"
and that error went away, but the class i'm including the file, still has these errorsstruct FPrimalPlayerCharacterConfigStructReplicated {};
in Base.h and now i get errors everywherestruct FPrimalPlayerCharacterConfigStructReplicated {};
with the struct from the dump file?PlayerCharacterConfig.PlayerCharacterName
to get the name from the struct in your example
but the struct has no member PlayerCharacterName
FString& PlayerCharacterNameField()
FPrimalPlayerCharacterConfigStructReplicated
look like? DECLARE_HOOK(AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation, void, AShooterPlayerState*, FPrimalPlayerCharacterConfigStructReplicated);
void Hook_AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation(AShooterPlayerState* _this, FPrimalPlayerCharacterConfigStructReplicated PlayerCharacterConfig) {
if (_this && !PlayerCharacterConfig.PlayerCharacterNameField().IsEmpty()) {
//FString name = PlayerCharacterConfig.PlayerCharacterNameField();
const FString name = PlayerCharacterConfig.PlayerCharacterNameField();
Log::GetLog()->warn(" >>>> AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation: - PlayerCharacterNameField:{}", name.ToString());
FString human = "Human";
if (PlayerCharacterConfig.PlayerCharacterNameField().Equals(human)) {
ArkApi::GetApiUtils().SendNotification(_this->GetShooterController(), FColorList::Green, 1.3f, 15.0f, nullptr, "Failed to create new player...");
return;
}
}
AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation_original(_this, PlayerCharacterConfig);
}
Actor.h
struct FPrimalPlayerCharacterConfigStructReplicated {
char __padding[0xb8L];
FieldArray<FLinearColor, 4> BodyColorsField() { return { this, "FPrimalPlayerCharacterConfigStructReplicated.BodyColors" }; }
FString& PlayerCharacterNameField() { return *GetNativePointerField<FString*>(this, "FPrimalPlayerCharacterConfigStructReplicated.PlayerCharacterName"); }
FieldArray<float, 22> RawBoneModifiersField() { return { this, "FPrimalPlayerCharacterConfigStructReplicated.RawBoneModifiers" }; }
int& PlayerSpawnRegionIndexField() { return *GetNativePointerField<int*>(this, "FPrimalPlayerCharacterConfigStructReplicated.PlayerSpawnRegionIndex"); }
// Functions
FPrimalPlayerCharacterConfigStruct* GetPlayerCharacterConfig(FPrimalPlayerCharacterConfigStruct* result) { return NativeCall<FPrimalPlayerCharacterConfigStruct*, FPrimalPlayerCharacterConfigStruct*>(this, "FPrimalPlayerCharacterConfigStructReplicated.GetPlayerCharacterConfig", result); }
FPrimalPlayerCharacterConfigStructReplicated* operator=(FPrimalPlayerCharacterConfigStructReplicated* __that) { return NativeCall<FPrimalPlayerCharacterConfigStructReplicated*, FPrimalPlayerCharacterConfigStructReplicated*>(this, "FPrimalPlayerCharacterConfigStructReplicated.operator=", __that); }
};
ArkApi::GetHooks().SetHook("AShooterPlayerState.ServerRequestCreateNewPlayer_Implementation", &Hook_AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation, &AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation_original);
ArkApi::GetHooks().DisableHook("AShooterPlayerState.ServerRequestCreateNewPlayer_Implementation", &Hook_AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation);
void Hook_AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation(AShooterPlayerState* _this, FPrimalPlayerCharacterConfigStructReplicated PlayerCharacterConfig) {
if (_this && !PlayerCharacterConfig.PlayerCharacterNameField().IsEmpty()) {
FString human = FString("Human");
if (!PlayerCharacterConfig.PlayerCharacterNameField().Contains(human)) {
ArkApi::GetApiUtils().SendNotification(_this->GetShooterController(), FColorList::Green, 1.3f, 15.0f, nullptr, "Failed to create new player...");
return;
}
}
AShooterPlayerState_ServerRequestCreateNewPlayer_Implementation_original(_this, PlayerCharacterConfig);
}
!PlayerCharacterConfig.PlayerCharacterNameField().IsEmpty()
on line 368
and then some null pointer on line 371 (edited)Exception thrown at 0x00007FFFBFAB122E (vcruntime140.dll) in ShooterGameServer.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
void Hook_validateNames(AShooterPlayerState* _this, FPrimalPlayerCharacterConfigStructReplicated* playerCharacterConfig)
{
LOG->info(playerCharacterConfig->PlayerCharacterName.ToString());
validateNames_original(_this, playerCharacterConfig);
}
struct FPrimalPlayerCharacterConfigStructReplicated
{
uint8 bIsFemale : 1;
FLinearColor BodyColors[4];
FString PlayerCharacterName;
};
FPrimalPlayerCharacterConfigStructReplicated
in Actor.h
and I changed struct FPrimalPlayerCharacterConfigStructReplicated {};
in Base.h
to struct FPrimalPlayerCharacterConfigStructReplicated;
AActor* Actor = player->GetPlayerCharacter()->GetAimedActor(ECC_GameTraceChannel2, nullptr, 0.0, 0.0, nullptr, nullptr, false, false);
But apparently that method requries a
FHitResult * outHitResult
How or where do i come up with that?
I thought passing in FHitResult* result
would do it?
Sorry if stupid question, my CPP is super rustyAActor* Actor = player->GetPlayerCharacter()->GetAimedActor(ECC_GameTraceChannel2, nullptr, 0.0, 0.0, nullptr, nullptr, false, false, false);
std::list<int> GetTribeSteamIds(int tribeId) {
FTribeData tribeDataResult;
ArkApi::GetApiUtils().GetShooterGameMode()->GetTribeData(&tribeDataResult, tribeId);
for (auto member : tribeDataResult.MembersConfigsField()) {
Log::GetLog()->info("Player in tribe ({})", member.PlayerCharacterName.ToString());
}
}
Currently failing on the GetTribeData callstd::list<int> GetTribeSteamIds(int tribeId) {
std::list<int> resultList;
FTribeData tribeDataResult;
ArkApi::GetApiUtils().GetShooterGameMode()->GetTribeData(&tribeDataResult, tribeId);
Log::GetLog()->info("Got Tribe Data");
for (auto member : tribeDataResult.MembersConfigsField()) {
Log::GetLog()->info("Player in tribe ({})", member.PlayerCharacterName.ToString());
}
return resultList;
}
No members logging, anything im missing?FTribeData
#include <API/ARK/Ark.h>
/* Macro to add a hook easily. */
#define SET_HOOK(functionName, hookName) \
ArkApi::GetHooks().SetHook(functionName, &Hook_ ## hookName, &hookName ## _original)
/* Macro to remove a hook easily. */
#define DISABLE_HOOK(functionName, hookName) \
ArkApi::GetHooks().DisableHook(functionName, &Hook_ ## hookName)
/* Shortcut */
#define HOOKS \
ArkApi::GetHooks()
/* Shortcut */
#define COMMANDS \
ArkApi::GetCommands()
/* Shortcut */
#define API_UTILS \
ArkApi::GetApiUtils()
/* Shortcut */
#define LOG \
Log::GetLog()
/* Shortcut */
#define INIT_LOG(text) \
Log::Get().Init(text)
defeatboss
on a player pawnPlayerPawnTest
BLUEPRINT(asdfasdfsdf,asdfasdfasdf)
PlayerPawnTest
PrimalPlayerDataBP_Base
afaikfor (auto& data : AShooterPlayerController::GetPrivateStaticClass()->NativeFunctionLookupTableField())
{
FString out;
(data.Name).ToString(&out);
Log::GetLog()->info(out.ToString());
}
i did something like this to dump BP func names also auto data = myPawn->GetPlayerData();
UFunction* bpFunction = data->FindFunctionChecked(FName(L"DefeatedBoss", EFindName::FNAME_Find, false));
if (bpFunction)
{
DefeatedBoss_Params params;
params.DifficultyIndex = 3;
params.tagOverride = FName(L"Dragon", EFindName::FNAME_Find, false);
params.PC = *(static_cast<AShooterPlayerController*>(_this));
myPawn->ProcessEvent(bpFunction, ¶ms);
}
*(static_cast<AShooterPlayerController*>
struct DefeatedBoss_Params
{
APrimalDinoCharacter* boss;
int DifficultyIndex;
FName tagOverride;
AShooterPlayerController* PC;
};
void Hook_chatMessage(AShooterPlayerController* _this, FString ChatMessage, EChatSendMode::Type SendMode)
{
//LOG->info("got a chat message of %s", ChatMessage.ToString().c_str());
return chatMessage_original(_this, ChatMessage, SendMode);
.....
*
or somethingstruct DefeatedBoss_Params
{
APrimalDinoCharacter* boss;
int DifficultyIndex;
FName tagOverride;
AShooterPlayerController* PC;
};
killPlayer
are called that in BP code, but in C++ it's killPlayer_Implementation
func_exec
-> BPfunc_implementation
-> C++func
is usually just a wrapper to one of (or both) of thosebool Hook_AActor_BPServerHandleNetExecCommand(AActor* _this, APlayerController* FromPC, FName CommandName, FBPNetExecParams* ExecParams)
std::list<int> GetTribeSteamIds(int tribeId) {
std::list<int> resultList;
FTribeData* tribe_data = static_cast<FTribeData*>(FMemory::Malloc(0x128 + 0x28));
RtlSecureZeroMemory(tribe_data, 0x128 + 0x28);
ArkApi::GetApiUtils().GetShooterGameMode()->GetOrLoadTribeData(tribeId, tribe_data);
auto members = tribe_data->MembersConfigsField();
for (auto member : members) {
Log::GetLog()->info("Player in tribe ({})", member.PlayerCharacterName.ToString());
}
FMemory::Free(tribe_data);
return resultList;
}
still nothing coming from the tribe_data
malloc error is gone thoughstruct UPrimalPlayerDataBP_Base
{
unsigned char unk[0x028]; //UObject
unsigned char unk2[0x0498]; //PrimalPlayerData
int NumAscensions;
unsigned char UnknownData00[0x4];
TArray<float> AscensionData;
TArray<struct FName> BossDinoNameTagAscensionDataMap;
int SavedPlayerDataVersion;
int CurrentPlayerDataVersion;
int HexagonCount;
int NumChibiLevelUpsData;
};
void PostLogin(APlayerController* NewPlayer) { NativeCall<void, APlayerController*>(this, "AShooterGameMode.PostLogin", NewPlayer); }
(edited)const uint64 steamid = ArkApi::GetApiUtils().GetSteamIdFromController(NewPlayer);
void Hook_AShooterGameMode_PostLogin(AShooterGameMode* _AShooterGameMode, APlayerController* NewPlayer) {
int steam_id = ArkApi::GetApiUtils().GetSteamIdFromController(NewPlayer);
int character_id = ArkApi::GetApiUtils().GetPlayerID(NewPlayer);
...
AShooterGameMode_PostLogin_original(_AShooterGameMode, NewPlayer);
}
Any idea why character_id is 0
should i use a different hook? AShooterCharacter* myPawn = static_cast<AShooterCharacter*>(playerController->PawnField());
UPrimalPlayerData* data = myPawn->GetPlayerData();
(reinterpret_cast<UPrimalPlayerDataBP_Base*>(data))->NumChibiLevelUpsData = value; /* yolo */
/* yolo */
void SetChibi(AShooterPlayerController* playerController, int value)
{
AShooterCharacter* myPawn = static_cast<AShooterCharacter*>(playerController->PawnField());
UPrimalPlayerData* data = myPawn->GetPlayerData();
UFunction* bpFunction = myPawn->FindFunctionChecked(FName(L"SetNumChibiLevelUps", EFindName::FNAME_Find, false));
int params[] = { value };
myPawn->ProcessEvent(bpFunction, ¶ms);
(reinterpret_cast<UPrimalPlayerDataBP_Base*>(data))->NumChibiLevelUpsData = value; /* yolo */
data->SavePlayerData(ArkApi::GetApiUtils().GetWorld());
}
CorrM/Unreal-Finder-Tool
crash for me auto address = FindPattern(GetModuleHandleW(nullptr), reinterpret_cast<const unsigned char*>("\xc7\x05\x00\x00\x00\x00\x00\x00\x00\x00\xc6\x05\x00\x00\x00\x00\x01"), "xx????xxxxxx????x");
auto offset = *reinterpret_cast<uint32_t*>(address + 2);
GlobalObjects = (FUObjectArray*)(address + 0xA + offset);
auto address = FindPattern(GetModuleHandleW(nullptr), reinterpret_cast<const unsigned char*>("\x33\xdb\x48\x89\x1d\x00\x00\x00\x00\x8b\xc3\x48\x8b\x5c"), "xxxxx????xxxxx");
auto offset = *reinterpret_cast<uint32_t*>(address + 5);
GlobalNames = reinterpret_cast<decltype(GlobalNames)>(*reinterpret_cast<uintptr_t*>(address + 0x9 + offset));
auto address = FindPattern(GetModuleHandleW(nullptr), reinterpret_cast<const unsigned char*>("\x48\x89\x83\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x89\x1D"), "xxx????x????xxx");
address += 12;
auto offset = *reinterpret_cast<uint32_t*>(address + 3);
GlobalNames = reinterpret_cast<decltype(GlobalNames)>(*reinterpret_cast<uintptr_t*>(address + 7 + offset));
auto address = FindPattern(GetModuleHandleW(nullptr), reinterpret_cast<const unsigned char*>("\x89\x0D\x00\x00\x00\x00\x48\x8D\x4D\x00\xE8"), "xx????xxx?x");
auto offset = *reinterpret_cast<uint32_t*>(address + 2);
GlobalObjects = (FUObjectArray*)(address + 6 + offset);
rProcessEvent = reinterpret_cast<tProcessEvent>(DetourFindFunction("ShooterGame.exe", "UObject::ProcessEvent"));
rPostRender = reinterpret_cast<tPostRender>(DetourFindFunction("ShooterGame.exe", "UGameViewportClient::PostRender"));
if (chatIcon == ChatIcon::Admin)
{
auto engine = Globals::GEngine()();
auto primalglobals = engine->GameSingletonField();
auto gamedata = primalglobals->PrimalGameDataOverrideField();
if (!gamedata) gamedata = primalglobals->PrimalGameDataField();
auto texture = gamedata->NameTagServerAdminField();
if (texture) iconTexture = gamedata->NameTagServerAdminField();
}
but im getting UObject has no member PrimalGameDataOverrideField#pragma comment(lib, "Permissions.lib")
auto isDonor = Permissions::IsPlayerInGroup(steamId, FString("Donor1"));
it is fine (edited)API::AuthPC()
) is that it becomes trivial to crackFindFunction
will always workvoid SetChibi(AShooterPlayerController* playerController, int value)
{
AShooterCharacter* myPawn = static_cast<AShooterCharacter*>(playerController->PawnField());
UPrimalPlayerData* data = myPawn->GetPlayerData();
UFunction* bpFunction = myPawn->FindFunctionChecked(FName(L"SetNumChibiLevelUps", EFindName::FNAME_Find, false));
int params[] = { value };
myPawn->ProcessEvent(bpFunction, ¶ms);
(reinterpret_cast<UPrimalPlayerDataBP_Base*>(data))->NumChibiLevelUpsData = value; /* yolo */
data->SavePlayerData(ArkApi::GetApiUtils().GetWorld());
}
struct UPrimalPlayerDataBP_Base //This is 101% an unclean solution. :| gonna find to find a way to find the field a little bit easier.
{
unsigned char unk[0x028]; //UObject
unsigned char unk2[0x0498]; //PrimalPlayerData
int NumAscensions;
unsigned char UnknownData00[0x4];
TArray<float> AscensionData;
TArray<struct FName> BossDinoNameTagAscensionDataMap;
int SavedPlayerDataVersion;
int CurrentPlayerDataVersion;
int HexagonCount;
int NumChibiLevelUpsData;
};
///assume these are paths to YOUR skins
const wchar_t* skins[] = {
L"Blueprint'/Game/XXXX'",
L"Blueprint'/Game/XXXX'",
L"Blueprint'/Game/XXXX'"
};
//let's assume the player owns skin 0
const wchar_t* skin = skins[0];
//you can load here
UClass* skinClass = UVictoryCore::BPLoadClass(&FString(skin));
(edited)void doSkins(AShooterPlayerController* playerController)
{
///assume these are paths to YOUR skins
const wchar_t* skins[] = {
L"Blueprint'/Game/XXXX'",
L"Blueprint'/Game/XXXX'",
L"Blueprint'/Game/XXXX'"
};
//let's assume the player owns skin 0
const wchar_t* skin = skins[0];
//you can load here
UClass* skinClass = UVictoryCore::BPLoadClass(&FString(skin));
playerController->GetPlayerInventory()->AddItemObject(skinClass->GetDefaultObject(true));
}
playerController->GetPlayerInventory()->AddItemObject(static_cast<UPrimalItem*>(skinClass->GetDefaultObject(true)));
void ServerRequestHexagonTrade_Implementation(int RequestedTradableItemIndex, int Quantity) { NativeCall<void, int, int>(this, "AShooterCharacter.ServerRequestHexagonTrade_Implementation", RequestedTradableItemIndex, Quantity); }
void ServerRequestHexagonTrade(int RequestedTradableItemIndex, int Quantity) { NativeCall<void, int, int>(this, "AShooterCharacter.ServerRequestHexagonTrade", RequestedTradableItemIndex, Quantity); }
Might be useful in overriding hexagon store (edited)RequestedTradableItemIndex
they use a table/arraystruct FPlacementData
{
char __padding[0x60L];
FVector& AdjustedLocationField() { return *GetNativePointerField<FVector*>(this, "FPlacementData.AdjustedLocation"); }
FRotator& AdjustedRotationField() { return *GetNativePointerField<FRotator*>(this, "FPlacementData.AdjustedRotation"); }
bool& bSnappedField() { return *GetNativePointerField<bool*>(this, "FPlacementData.bSnapped"); }
bool& bDisableEncroachmentCheckField() { return *GetNativePointerField<bool*>(this, "FPlacementData.bDisableEncroachmentCheck"); }
int& MySnapToIndexField() { return *GetNativePointerField<int*>(this, "FPlacementData.MySnapToIndex"); }
int& TheirSnapToIndexField() { return *GetNativePointerField<int*>(this, "FPlacementData.TheirSnapToIndex"); }
AActor* FloorHitActorField() { return GetNativePointerField<AActor*>(this, "FPlacementData.FloorHitActor"); }
APrimalStructure* ParentStructureField() { return GetNativePointerField<APrimalStructure*>(this, "FPlacementData.ParentStructure"); }
APrimalStructure* ForcePlacedOnFloorParentStructureField() { return GetNativePointerField<APrimalStructure*>(this, "FPlacementData.ForcePlacedOnFloorParentStructure"); }
APrimalStructure* ReplacesStructureField() { return GetNativePointerField<APrimalStructure*>(this, "FPlacementData.ReplacesStructure"); }
APawn& AttachToPawnField() { return *GetNativePointerField<APawn*>(this, "FPlacementData.AttachToPawn"); }
FName& AttachToBoneField() { return *GetNativePointerField<FName*>(this, "FPlacementData.AttachToBone"); }
APrimalDinoCharacter* DinoCharacterField() { return GetNativePointerField<APrimalDinoCharacter*>(this, "FPlacementData.DinoCharacter"); }
};
if(OutPlacementData)
{
if (OutPlacementData->DinoCharacterField())
{
APrimalDinoCharacter* theDino = OutPlacementData->DinoCharacterField();
if (theDino && theDino->IsA(APrimalDinoCharacter::GetPrivateStaticClass())) {
crashes on the IsA()ShooterGameServer.exe!UObjectBaseUtility::IsA()(0x00007ff68699a045)+0bytes[f:\build\live312jenkins\engine\source\runtime\coreuobject\private\uobject\uobjectbaseutility.cpp:265]
struct FPlacementData
look correct?struct FPlacementData
{
FVector AdjustedLocation;
FRotator AdjustedRotation;
bool bSnapped;
bool bDisableEncroachmentCheck;
int MySnapToIndex;
int TheirSnapToIndex;
AActor* FloorHitActor;
APrimalStructure* ParentStructure;
APrimalStructure* ForcePlacedOnFloorParentStructure;
APrimalStructure* ReplacesStructure;
APawn* AttachToPawn;
FName AttachToBone;
APrimalDinoCharacter* DinoCharacter;
};
Seems to work fine.reinterpret_cast<UPrimalPlayerDataBP_Base*>(data))->NumChibiLevelUpsData = value; /* yolo */
reinterpret_cast
wrong, shit crashesstruct UPrimalPlayerDataBP_Base //This is 101% an unclean solution. :| gonna find to find a way to find the field a little bit easier.
{
unsigned char unk[0x028]; //UObject
unsigned char unk2[0x0498]; //PrimalPlayerData
int NumAscensions;
unsigned char UnknownData00[0x4];
TArray<float> AscensionData;
TArray<struct FName> BossDinoNameTagAscensionDataMap;
int SavedPlayerDataVersion;
int CurrentPlayerDataVersion;
int HexagonCount;
int NumChibiLevelUpsData;
};
void SetChibi(AShooterPlayerController* playerController, int value)
{
AShooterCharacter* myPawn = static_cast<AShooterCharacter*>(playerController->PawnField());
UPrimalPlayerData* data = myPawn->GetPlayerData();
UFunction* bpFunction = myPawn->FindFunctionChecked(FName(L"SetNumChibiLevelUps", EFindName::FNAME_Find, false));
int params[] = { value };
myPawn->ProcessEvent(bpFunction, ¶ms);
(reinterpret_cast<UPrimalPlayerDataBP_Base*>(data))->NumChibiLevelUpsData = value; /* yolo */
data->SavePlayerData(ArkApi::GetApiUtils().GetWorld());
}
reinterpret_cast
SetNumChibiLevelUps
bp function is for updating the pawn, but NumChibiLevelUpsData
on UPrimalPlayerDataBP_Base
is where it's actually persisted.BP_FUNCTION("name", "function", type1, type2, ...., typeN)
(edited)name_BP(arg1, arg2, ....., argN
UFunction* bpFunction = data->FindFunctionChecked(FName(L"DefeatedBoss", EFindName::FNAME_Find, false));
DefeatedBoss_Params params;
params.boss = nullptr;
params.DifficultyIndex = difficulty;
params.tagOverride = FName(boss.c_str(), EFindName::FNAME_Add, false);
params.PC = playerController;
data->ProcessEvent(bpFunction, ¶ms);
Playerscommand :
/Bounty : show the actual bonty and their position "The position is not working good"
Wonder if this means it shows on the map?/linkTribe
in discord, responds with "tell your tribe owner to use /linkTribe asdgii324n52n3i4uqwaiue5AQ53
ingame
tribe owner ingame does /linkTribe asdgii324n52n3i4uqwaiue5AQ53
plugin inserts discordId+channelId+tribeId into sql (edited) TArray<UObject*, FDefaultAllocator> masterList;
Globals::GetObjectsOfClass(UPrimalCharacterStatusComponent().ClassField(), &masterList, true, EObjectFlags::RF_NoFlags);
Should this return back a list of all UPrimalCharacterStatusComponent's or am I missing something?TArray<UObject*, FDefaultAllocator> masterList;
TArray<FString> strings;
command->ParseIntoArray(strings, {L" "}, true);
TArray the DefaultAllocator by default (edited)UPrimalCharacterStatusComponent
that are on the server.UPrimalCharacterStatusComponent
may not actually exist in it's pure form, not sure if Globals::GetObjectsOfClass
returns only classes that exactly match, or if children classes match too.TActorIterator
looks like the C++ versionvoid FindAllActors(UWorld* World, TArray& Out)
{
for (TActorIterator It(World, T::StaticClass()); It; ++It)
{
T* Actor = Cast(*It);
if (Actor && !Actor->IsPendingKill())
{
Out.Add(Actor);
}
}
}
Globals::GetObjectsOfClass(APrimalDinoCharacter().ClassField(), &masterList, true, EObjectFlags::RF_NoFlags);
returned 0 as wellchat_message.Message = FString(L"3: медведь");
aShooterPC->ClientChatMessage(chat_message);
is saying [][][][][][] ingameunicode_ci
FString myFString = FString(ArkApi::Tools::Utf8Decode(myString))
FString to std::string
std::string myString = ArkApi::Tools::Utf8Encode(myFString)
std::string msg = ArkApi::Tools::Utf8Encode(**myFString);
void sendDiscordMessage(std::string message, std::string url) {
nlohmann::json j;
try {
j["content"] = message;
const std::string jsonMessage = j.dump().c_str();
const std::string webHookURL = url.c_str();
AShooterGameState* ShooterGameState = static_cast<AShooterGameState*>(ArkApi::GetApiUtils().GetShooterGameMode()->GameStateField());
ShooterGameState->HTTPPostRequest(FString(webHookURL),
FString(ArkApi::Tools::Utf8Decode(jsonMessage)));
}
catch (std::exception ex) {
Log::GetLog()->error(ex.what());
}
}
struct FStatusValueModifierDescription
?ᣠ翷 ⢐翷
outputTArray<APrimalBuff*> theBuffs;
_this->GetBuffs(&theBuffs);
Log::GetLog()->info("Buff Count: {}", theBuffs.Num());
Shows when a buff is active. Just need some identifier to know what buff.struct __declspec(align(8)) FStatusValueModifierDescription
{
char __padding[0x50L];
UTexture2D* ModifierIconField() { return GetNativePointerField<UTexture2D*>(this, "FStatusValueModifierDescription.ModifierIcon"); }
FString& ModifierNameField() { return *GetNativePointerField<FString*>(this, "FStatusValueModifierDescription.ModifierName"); }
FString& ModifierDescriptionField() { return *GetNativePointerField<FString*>(this, "FStatusValueModifierDescription.ModifierDescription"); }
FColor& ModifierColorField() { return *GetNativePointerField<FColor*>(this, "FStatusValueModifierDescription.ModifierColor"); }
bool& bDisplayHUDMessageField() { return *GetNativePointerField<bool*>(this, "FStatusValueModifierDescription.bDisplayHUDMessage"); }
FString& HUDMessageField() { return *GetNativePointerField<FString*>(this, "FStatusValueModifierDescription.HUDMessage"); }
FColor& HUDMessageColorField() { return *GetNativePointerField<FColor*>(this, "FStatusValueModifierDescription.HUDMessageColor"); }
bool& bPreventDrawingBuffDescriptionField() { return *GetNativePointerField<bool*>(this, "FStatusValueModifierDescription.bPreventDrawingBuffDescription"); }
int& BuffTypeField() { return *GetNativePointerField<int*>(this, "FStatusValueModifierDescription.BuffType"); }
// Functions
FStatusValueModifierDescription * operator=(FStatusValueModifierDescription * __that) { return NativeCall<FStatusValueModifierDescription *, FStatusValueModifierDescription *>(this, "FStatusValueModifierDescription.operator=", __that); }
};
struct __cppobj __declspec(align(8)) FStatusValueModifierDescription
{
UTexture2D *ModifierIcon;
FString ModifierName;
FString ModifierDescription;
FColor ModifierColor;
bool bDisplayHUDMessage;
FString HUDMessage;
FColor HUDMessageColor;
bool bPreventDrawingBuffDescription;
int BuffType;
};
Have to remove __cppobj for it to compilestruct FStatusValueModifierDescription
{
UTexture2D* ModifierIcon;
FString ModifierName;
FString ModifierDescription;
FColor ModifierColor;
bool bDisplayHUDMessage;
FString HUDMessage;
FColor HUDMessageColor;
bool bPreventDrawingBuffDescription;
int BuffType;
};
(edited)APrimalBuff
is wrongbuff->field
you're not getting the actual field.FStatusValueModifierDescription test;
buff->GetBuffDescription(&test);
v2 = UObject::FindFunctionChecked(v5, SHOOTERGAME_GetBuffDescription);
TArray<APrimalBuff*> theBuffs;
yeah?FStatusValueModifierDescription test;
buff->GetBuffDescription(&test);
TMap<FString, int64, FDefaultSetAllocator, TDefaultMapKeyFuncs<FString, int64, 0> > CommandCoolDowns;
CommandCoolDowns.Add(FString::Format("{}:{}", steam_id64, __FUNCTION__), (DrClean::DrTools::SystemEpochMillis() - 3600000));
const int64 time_stamp_millis = DrClean::DrTools::SystemEpochMillis();
int64 previous_time_stamp_millis;
CommandCoolDowns.RemoveAndCopyValue(FString::Format("{}:{}", steam_id64, __FUNCTION__), previous_time_stamp_millis);
int64 SystemEpochMillis() {
using namespace std::chrono;
return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}
TArray<FTribeAlliance> alliances = player_state->MyTribeDataField()->TribeAlliancesField();
for (FTribeAlliance alliance : alliances)
{
Log::GetLog()->info(fmt::format("Tribes Found: {}", alliance.MembersTribeIDField().Num()));
}
Some sample output
Tribes Found: -1515365888
Tribes Found: 1670472240for (auto TribeId : alliance.MembersTribeIDField())
{
//do stuff
}
_this->MyTribeDataField()->FindTribeAlliance(AllianceID);
It just gives me back junk Tribe Ids that don't exist.struct FTribeAlliance
{
FString AllianceNameField;
unsigned int AllianceIDField;
TArray<FString> MembersTribeNameField;
TArray<unsigned int> MembersTribeIDField;
TArray<unsigned int> AdminsTribeIDField;
};
UPrimalItem.EquippedBlueprintTick
but it doesn't seem to fire when something is equipped on the player. I've also tried to use UPrimalItem.EquippedTick
Is there anything I am misunderstanding here? (edited)AShooterGameMode.HandleNewPlayer
that would fire when a player joins, but you'll have to do your checks for when player controller or character is validcommands.AddOnChatMessageCallback("ChatMessageCallback", &ChatMessageCallback);
AddOnChatMessageCallback
for chat (which seems to have an unavoidable 1s spam timer)
When i return true to prevent default chat, chat stops going to rcon
Cant seem to find a way to get the RconClient other than adding rcon commands?void Hook_AShooterPlayerController_ServerSendChatMessage_Impl(
AShooterPlayerController* player_controller, FString* message, EChatSendMode::Type mode)
to bypass the built in chat spamdel "$(SolutionDir)$(PlatformName)\$(ConfigurationName)\*.ArkApi"
Post-Build Event: copy "$(SolutionDir)$(PlatformName)\$(ConfigurationName)\*.dll" "$(SolutionDir)$(PlatformName)\$(ConfigurationName)\*.dll.ArkApi" /y
rem deployment.bat
@ECHO OFF
CLS
setlocal enabledelayedexpansion
set SolutionDir=%1
set Platform=%2
set Configuration=%3
set ProjectName=%4
for %%x in (
INSTALL_TESTSERVERA,
INSTALL_TESTSERVERB,
INSTALL_TESTSERVERC,
INSTALL_THEISLAND,
INSTALL_SCORCHEDE,
INSTALL_ABERATION,
INSTALL_RAGNAROK,
INSTALL_THECENTER,
INSTALL_CRYSTAL,
INSTALL_EXTINCTION,
INSTALL_VALGUERO,
INSTALL_GENESIS1
) do (
rem LOCAL
rem set _directory=D:\ARK_SERVER\%%x\ShooterGame\Binaries\Win64\ArkApi\Plugins\%ProjectName%
rem Mapped Network Drive
set _directory=W:\%%x\ShooterGame\Binaries\Win64\ArkApi\Plugins\%ProjectName%
if not exist "!_directory!" mkdir !_directory!
rem will not overwrite dll if server running but will be overwritten by auto reload dll.ArkApi...
copy /y "%SolutionDir%%Platform%\%Configuration%\%ProjectName%\%ProjectName%.dll" "!_directory!\%ProjectName%.dll"
copy /y "%SolutionDir%%Platform%\%Configuration%\%ProjectName%\%ProjectName%.dll" "!_directory!\%ProjectName%.dll.ArkApi"
copy /y "%SolutionDir%%Platform%\%Configuration%\%ProjectName%\%ProjectName%.pdb" "!_directory!\%ProjectName%.pdb"
copy /y "%SolutionDir%%Platform%\%Configuration%\%ProjectName%\PluginInfo.json" "!_directory!\PluginInfo.json"
copy /y "%SolutionDir%%Platform%\%Configuration%\%ProjectName%\config_defaults.json" "!_directory!\config_defaults.json"
)
EXIT
Build Events > Post Build Events > Command Line
start $(SolutionDir)deployment.bat "$(SolutionDir)" "$(Platform)" "$(Configuration)" "$(ProjectName)"
(edited)deployment.bat
is located in the root dir, so as long as the child project is within, any project can be deployed easily (edited)int Hook_APrimalStructure_BPIsAllowedToBuild(APrimalStructure* _this, FPlacementData* OutPlacementData, int CurrentAllowedReason)
{
bool isObstructued = _this->IsPointObstructedByWorldGeometry(ArkApi::GetApiUtils().GetWorld(), OutPlacementData->AdjustedLocation, false, false, false, 300);
if (isObstructued)
{
Log::GetLog()->info("Is OBSTRUCTUED");
return -2;
}
Log::GetLog()->info("Is NOT OBSTRUCTUED");
return APrimalStructure_BPIsAllowedToBuild_original(_this, OutPlacementData, CurrentAllowedReason);
}
but it always returns false, despite being inside mesh, or in the middle of mesh/world. I also tried to raise the obstruction check radius up to 30k but it still had the same output.08/01/20 18:36 [Permission][error] (d:\programs\ark\plugins\permissions\permissions\private\hooks.cpp Permissions::Hooks::Hook_AShooterGameMode_HandleNewPlayer) Couldn't add player
I dont have a d: storage so i have no idea where this is coming from, any suggestions? (edited)AShooterCharacter::AllowGrappling_Implementation()
hook, but it doesn't give me the player who tries to grapple someone. I need to have targeting team fields of both the players.
APrimalCharacter::OnBeginDrag(...)
hook called only for dead bodies, not for alive players/dinos.
I tried AShooterCharacter::UpdateGrapHook()
hook, but it always shows no grappled/dragged characters currently (it works for corpses and dinos though)
Probably I have to use APrimalWeaponGrapplingHook
somehow, but it isn't in API {
"Quality": 100,
"ForceBlueprint": false,
"Amount": 1,
"Blueprint": "\"Blueprint'/Game/PrimalEarth/CoreBlueprints/Weapons/PrimalItem_WeaponPike.PrimalItem_WeaponPike'\""
},
"Blueprint": "Blueprint'/Game/PrimalEarth/CoreBlueprints/Weapons/PrimalItem_WeaponPike.PrimalItem_WeaponPike'"
This would be the proper format for that line.HttpVoteCallBack
is only handling a basic response that expects a single integer, TopArkServers API now returns a JSON response that requires parsing.http://toparkservers.com/api/rewards/<API_KEY>/<STEAM_ID>/status
http://toparkservers.com/api/rewards/<API_KEY>/<STEAM_ID>/claim
you should see a response like
{
"username": "Bonjela",
"votetype": "like",
"rewardvalue": "2",
"reason": "The player has already claimed their reward or they have not voted in the last 12 hours."
}
catch (...)
works? HMODULE api = GetModuleHandle(NULL);
using pfnIsPluginLoaded = bool(__fastcall*)(const std::string& plugin_name);
const auto isLoaded = reinterpret_cast<pfnIsPluginLoaded>(GetProcAddress(api, "PluginManager::IsPluginLoaded"));
if (isLoaded != nullptr)
{
loaded = isLoaded("PluginNameHere");
}
GetModuleHandleA("ntdll.dll")
auto loaded = GetModuleHandleA("Plugin.dll");
if(loaded)
Flag = Plugin::Function(Params);
else
Log::GetLog()->info("Plugin Unloaded?");
SHOP_API bool CanUseKit(AShooterPlayerController* player_controller, uint64 steam_id, const FString& kit_name);
should wrap it#define ARK_API __declspec(dllimport)
ARK_API bool MyFunction(int param);
ReadInt
for (UProperty* Property = data->ClassField()->PropertyLinkField(); Property = Property->PropertyLinkNextField();)
{
LOG->info(Property->Offset_InternalField());
FName aName;
FString aString;
FString bString;
Property->GetID(&aName);
aName.ToString(&aString);
LOG->info(aString.ToString());
Property->GetCPPMacroType(&aString, &bString);
LOG->info(aString.ToString());
LOG->info(bString.ToString());
aName = static_cast<UObject*>(Property)->NameField();
aName.ToString(&aString);
LOG->info(aString.ToString());
}
UProperty* FindProperty(FName name, UObject* object)
{
for (UProperty* Property = object->ClassField()->PropertyLinkField(); Property = Property->PropertyLinkNextField();)
{
FName propName = ((UObject*)(Property))->NameField();
if (propName.Compare(&name) == 0)
return Property;
}
return nullptr;
}
template<typename T>
T Get(UProperty* prop, UObject* object)
{
if (sizeof(T) != prop->ElementSizeField())
throw "Bad Size"; //users can handle this if they so choose.
return *((T*)(object + prop->Offset_InternalField()));
}
template<typename T>
void Set(UProperty* prop, UObject* object, T value)
{
if (sizeof(T) != prop->ElementSizeField())
throw "Bad Size"; //users can handle this if they so choose.
*((T*)(object + prop->Offset_InternalField())) = value;
}
FindFunctionChecked
is)T Get(FName name, UObject* object)
UProperty*
and then read the data if it isn't nullptr
(edited) template<typename T>
T Get(UObject* object)
{
if(!object->StaticClass()->HasProperty(this))
throw std::invalid_argument("Object does not contain this property.")
if (sizeof(T) != this->ElementSizeField())
throw std::invalid_argument("Expected size does not match property size.")
return *((T*)(object + this->Offset_InternalField()));
}
template<typename T>
void Set(UObject* object, T value)
{
if (!object->StaticClass()->HasProperty(this))
throw std::invalid_argument("Object does not contain this property.")
if (sizeof(T) != this->ElementSizeField())
throw std::invalid_argument("Expected size does not match property size.")
*((T*)(object + this->Offset_InternalField())) = value;
}
UE.h
RaycastSingle
FHitResult res;
might not work because this function may expect that memory to already be allocated, which isn't done properly this wayFMemory
static_cast<FItemNetInfo*>(FMemory::Malloc(sizeof(FItemNetInfo)))
LineTraceByChannel
struct parameters
{
bool a
int b
}
(edited) UFunction* bpFunction = data->FindFunctionChecked(FName(L"DefeatedBoss", EFindName::FNAME_Find, false));
DefeatedBoss_Params params;
params.boss = nullptr;
params.DifficultyIndex = difficulty;
params.tagOverride = FName(boss.c_str(), EFindName::FNAME_Add, false);
params.PC = playerController;
data->ProcessEvent(bpFunction, ¶ms);
data
is UPrimalPlayerData*
DefeatedBoss_Params
is
struct DefeatedBoss_Params
{
APrimalDinoCharacter* boss;
int DifficultyIndex;
FName tagOverride;
AShooterPlayerController* PC;
};
success
it would be like
struct DefeatedBoss_Params
{
APrimalDinoCharacter* boss;
int DifficultyIndex;
FName tagOverride;
AShooterPlayerController* PC;
bool success;
};
Packed block = packParameters(2, 65, 10., 1337, 1., nullptr, 0, 0);
((void(*)(void*))test)(block.parameters); //just to call by a function pointer
bool* bIsAlreadyInSetPtr
says unknown memory or something like that (edited)TEnumAsByte<EDrawDebugTrace::Type> debugTrace
? (edited)UKismetSystemLibrary
UObject::StaticClass()
probablyVTraceSingleBP
maybe?VictoryCore
UVictoryCore::VTraceSingleBP
if (GetVictoryCore().VTraceSingleBP(GetUWorld(), PlayerLoc, ActorLoc, sdk::ECollisionChannel::ECC_GameTraceChannel3, 0, "None", false, GetShooterCharacter(), 0, &HitResult)) { continue; }
ShooterGame.VictoryCore.VTraceSingleBP
is the function name in BPShooterGame.KismetSystemLibrary.LineTraceByChannel
LineTraceByChannel
Ran out of memory allocating 18446744058824253440 bytes with alignment 0
(edited)AShooterCharacter.Die
that occasionally crashes the server. I tried placing it in a try / catch but it doesn't help. TArray<FString> strings;
command->ParseIntoArray(strings, {L" "}, true);
if (strings.Num() != 2)
return; //invalid args
int value = 0;
try
{
value = std::atoi(strings[1].ToString().c_str());
}
catch (std::exception what) { return; /* could not parse */}
if (ptr == nullptr)
//or
if (!ptr)
AShooterCharacter* myPawn = static_cast<AShooterCharacter*>(playerController->PawnField());
if (!myPawn) return;
TArray<FHitResult>* aHit = static_cast<TArray<FHitResult>*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(aHit, 0x200);
FHitResult* hit = static_cast<FHitResult*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(hit, 0x200);
FCollisionQueryParams* Params = static_cast<FCollisionQueryParams*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(Params, 0x200);
Params->bReturnPhysicalMaterial = 0;
Params->bTraceComplex = 0;
FCollisionResponseParams* OutParams = static_cast<FCollisionResponseParams*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(OutParams, 0x200);
I'm allocating memory like this so it doesn't crash.
then doing this after i'm done with them
FMemory::Free(hit);
FMemory::Free(Params);
FMemory::Free(OutParams);
bool foundHit = world->LineTraceSingle(hit, &AtLocation, &End, ECC_Visibility, Params, OutParams, 0, 0.0f);
ShooterGame.NPCZoneVolume
UVictoryCore::VTraceSingleBP(world, hit, &AtLocation, &End, ECollisionChannel::ECC_WorldStatic, CollisionGroups, FName(L"None", EFindName::FNAME_Add,false), true, nullptr);
FVector* Vector(FVector* result) { return NativeCall<FVector*, FVector*>(this, "FRotator.Vector", result); }
KismetMath
has a forwards from RotatorFindObject<UClass>
StaticFindObject
null
Class Engine.KismetMathLibrary
as nameUObject *__fastcall FindObject<UClass>(UObject *Outer, const wchar_t *Name, UClass **ExactClass, void (__fastcall *a4)())
{
UObject *v4; // rsi
UClass *v5; // rcx
char v6; // bl
const wchar_t *v7; // rdi
v4 = Outer;
v5 = (UClass *)ClassToLookFor;
v6 = (char)ExactClass;
v7 = Name;
if ( !ClassToLookFor )
{
GetPrivateStaticClassBody<UClass>(L"/Script/CoreUObject", &word_143CBCDEA, ExactClass, a4);
v5 = (UClass *)ClassToLookFor;
}
return StaticFindObject(v5, v4, v7, v6);
}
Global.FindObject
should be the native call I think (edited) void* donk = packParameters(0, params.tagOverride).parameters;
FString test;
reinterpret_cast<FName*>(donk)->ToString(&test);
LOG->info(test.ToString());
hook_vector.push_back(std::make_shared<Hook>(new_target, detour, original));
API does this when setting a hookExecBP(UObjectRefHere, L"function", 5);
template<typename ...Rs, typename ...Ts> void* faf(Ts&&... args)
{
Packed data = packParameters(sizeof...(Rs), std::forward<Ts>(args)...);
//std::unique_ptr<void> returnData = std::unique_ptr<void>
}
template<typename ...Ts> void ExecBP(UObject* object, std::wstring name, Ts&&... args)
{
Packed data = packParameters(0, std::forward<Ts>(args)...);
if (object)
{
UFunction* bpFunction = object->FindFunctionChecked(FName(name.c_str(), EFindName::FNAME_Find, false));
if (bpFunction)
object->ProcessEvent(bpFunction, data.parameters);
}
free(data.parameters);
}
void doof()
{
ExecBP(nullptr, L"function", 5);
faf<int, bool>(12.f, 4, nullptr);
}
faf
is my work in progress test for that<>
and the args in ()
void DefeatBoss(std::wstring boss, int difficulty, AShooterPlayerController* playerController)
{
UPrimalPlayerData* data = (static_cast<AShooterCharacter*>(playerController->PawnField()))->GetPlayerData();
ExecBP(data, L"DefeatedBoss", nullptr, difficulty, FName(boss.c_str(), EFindName::FNAME_Add, false), playerController);
}
auto res = ExecBP<FVector>(playerController, L"BPCheckCanDinoSpawnFromLocation", APrimalDinoCharacter::StaticClass(), FVector(69,69,69));
LOG->info("Returned data {0}", std::get<0>(res).ToString().ToString());
ExecBP<return values>(args)
auto player = (static_cast<AShooterCharacter*>(playerController->PawnField()));
auto result = ExecBP<int>(player, L"GetTheNumChibiLevelUps");
if (result.has_value())
{
auto chibiLevels = result.value();
LOG->info("Returned data {0}", std::to_string(chibiLevels));
}
example with single value auto result = ExecBP<int,int>(player, L"GetPlayerStats");
if (result.has_value())
{
auto [health, stam] = result.value();
LOG->info("Player has {0} hp and {1} stam.", std::to_string(health), std::to_string(stam));
}
FHitResult::Size()
(edited)void GObj(AShooterPlayerController* pc)
{
auto a = GObjects();
printf("GObjects %p\n", GObjects());
LOG->info("total objects {0}", a.ObjObjects.NumElements);
UClass* myGuy = nullptr;
for (int i = 0; i < a.ObjObjects.NumElements; ++i)
{
UObjectBase* object = a.ObjObjects.GetObjectPtr(i)->Object;
if (object == nullptr)
continue;
FString expt;
object->NameField().ToString(&expt);
if (expt.ToString().find("KismetSystemLibrary") != std::string::npos)
{
myGuy = static_cast<UClass*>(object);
break;
}
}
UFunctionExec::create(myGuy->GetDefaultObject(true), L"LineTraceSingle_NEW")
.add("WorldContextObject", pc)
.add("Start", FVector(0, 0, 0))
.add("End", FVector(0, 0, 0))
.add("TraceChannel", 0) //whatever
.add("bTraceComplex", false)
.add("ActorsToIgnore", TArray<AActor*>())
.add("DrawDebugType", 0)
.skip("OutHit") //we know that this isn't quite required, so we force the check to skip this.
.add("bIgnoreSelf", true)
.add<bool>("ReturnValue")
.call();
}
ArkApi::GetApiUtils().SendNotification(player, color, display_scale, display_time,
nullptr, *message);
AShooterCharacter* rider = dino->RiderField().Get();
if (rider)
{
AShooterPlayerController* player_controller = static_cast<AShooterPlayerController*>(rider->GetInstigatorController());
if (player_controller)
{
ArkApi::GetApiUtils().SendNotification(player_controller, color, display_scale, display_time, nullptr, *message);
}
}
(edited)actor->IsA(APrimalDinoCharacter::GetPrivateStaticClass())
AShooterPlayerController* player_controller = static_cast<AShooterPlayerController*>(rider->GetInstigatorController())
AShooterPlayerController* player = ArkApi::GetApiUtils().FindControllerFromCharacter(
static_cast<AShooterCharacter*>(actor));
dino->RiderField.Get()
DECLARE_HOOK(FTribeData_MarkTribeNameChanged, void, FTribeData*, UObject*);
APrimalDinoCharacter.DoAttack
would stop working when the dino is picked up by a skiff?FSpawnPointInfo
for ARK?FSpawnPointInfo
for ARK? struct FSpawnPointInfo
{
int SpawnPointID;
FString BedName;
ABiomeZoneVolume *SpawnPointVolume;
TSubclassOf<AActor> SpawnPointActorClass;
FVector AtLocation;
long double NextAllowedUseTime;
bool bAllowedUse;
};
Log::GetLog()->info("Spawn Point {}: ID={}, Name={}, Loc={},{},{}", i, point.SpawnPointID, point.BedName.ToString(), point.AtLocation.X, point.AtLocation.Y, point.AtLocation.Z);
12/11/20 14:27 [KalsFastTravel][info] Spawn Point 0: ID=72071714, Name=, Loc=2.44073e-17,9.94922e-43,-238446
12/11/20 14:27 [KalsFastTravel][info] Spawn Point 1: ID=6356993, Name=, Loc=0,0,-0.00618458
12/11/20 14:27 [KalsFastTravel][info] IMPL: Fast Travel from 182878032 to 785478952
(edited)void Hook_APrimalStructureBed_PlacedStructure(APrimalStructureBed* _this, AShooterPlayerController* PC)
{
FVector toLoc;
_this->GetPlayerSpawnLocation(&toLoc);
std::string bedName = _this->BedNameField().ToString();
Log::GetLog()->info("Placed new spawn point '{}' at {},{},{}", bedName, toLoc.X, toLoc.Y, toLoc.Z)
APrimalStructureBed_PlacedStructure_original(_this, PC);
}
if (toBedObj->IsA(APrimalStructureBed::StaticClass()))
or using APrimalStructureBed in any way is causing crashes of 2 of 5 test machinesHook_AShooterPlayerState_AddToTribe
version.dll
wrapper from the Ark APIversion.dll
automaticallyTSubclassOf<UPrimalItem>
?TSubclassOf<UPrimalItem>
? UPrimalItem* item = (UPrimalItem*)YourTSubclassOfVariable.uClass->GetDefaultObject(true);
if (item)
{
FString itemName;
item->GetItemShortName(&itemName);
}
void Hook_AShooterGameMode_PostLogin(AShooterGameMode* _this, APlayerController* NewPlayer)
APrimalWorldSettings
? I need to calc GPS coords and want to do it the with the proper scales.learn c+++
which is not my part of coding, iam mostly just a discord bot coder of nodejs/javascript so yea @WETBATMAN (edited)c++
auto& pos = structure->DefaultActorLocationField();
but all of them are 0.c++
auto& pos = structure->DefaultActorLocationField();
but all of them are 0. utf8mb4
as well.‘; drop table users
ArkApi::Tools::Utf8Encode(*tribeName)
db_.query(fmt::format(
"INSERT INTO TribeLogRelay (TribeId, DiscordWebhook, TribeName) VALUES ({}, '{}', '{}');",
TribeId, "", ArkApi::Tools::Utf8Encode(*tribeName)));
return db_.query("UPDATE TribeLogRelay SET TribeName = '%s' WHERE TribeId = %I32i;", ArkApi::Tools::Utf8Encode(*tribeName), TribeId);
Stores P5%Å
instead of 部落名称变更至
but the value comes out properly in discord. Was trying to make database show the actual same value when I paste in the text.db_.query(fmt::format(
"INSERT INTO TribeLogRelay (TribeId, DiscordWebhook, TribeName) VALUES ({}, '{}', '{}');",
TribeId, "", ArkApi::Tools::Utf8Encode(*tribeName)));
daotk::mysql::connect_options options;
...
options.charset = "utf8";
...
'
while 'ab'
might become '
once insert.'
and \
has working for me so far in chatutf8mb4
and the default collation utf8mb4_0900_ai_ci
and it works now.options.charset
(edited)utf8mb4_0900_ai_ci
is not compatible with MariaDB. I had to switch that to utf8mb4_general_ci
for it to work with both MySQL/MariaDB.shooterCheatManager->ForcePlayerToJoinTribeId(player_id, tribe_id);
On the chat, it shows the message "Player added to tribe", but the player is not added to the tribe. Anyone has any tips on how to find out what is wrong?shooterCheatManager->ForcePlayerToJoinTribeId(player_id, tribe_id);
On the chat, it shows the message "Player added to tribe", but the player is not added to the tribe. Anyone has any tips on how to find out what is wrong? if (PC->GetPlayerCharacter() && !PC->IsSpectator() && !PC->IsInTribe())
{
AShooterGameMode* GameMode = ArkApi::GetApiUtils().GetShooterGameMode();
FString TribeName = L"Tribe of " + ArkApi::GetApiUtils().GetCharacterName(PC);
int CreatedTribeID = GameMode->ForceCreateTribe(&TribeName, 0);
FTribeData* CreatedTribeData = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(CreatedTribeData, 0x200);
if (GameMode->GetOrLoadTribeData(CreatedTribeID, CreatedTribeData))
PC->GetShooterPlayerState()->AddToTribe(CreatedTribeData, false, false, false, nullptr);
FMemory::Free(CreatedTribeData);
}
(edited)if (PC->GetPlayerCharacter() && !PC->IsSpectator() && !PC->IsInTribe())
{
AShooterGameMode* GameMode = ArkApi::GetApiUtils().GetShooterGameMode();
FString TribeName = L"Tribe of " + ArkApi::GetApiUtils().GetCharacterName(PC);
int CreatedTribeID = GameMode->ForceCreateTribe(&TribeName, 0);
FTribeData* CreatedTribeData = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(CreatedTribeData, 0x200);
if (GameMode->GetOrLoadTribeData(CreatedTribeID, CreatedTribeData))
PC->GetShooterPlayerState()->AddToTribe(CreatedTribeData, false, false, false, nullptr);
FMemory::Free(CreatedTribeData);
}
(edited)if (PC->GetPlayerCharacter() && !PC->IsSpectator() && !PC->IsInTribe())
{
AShooterGameMode* GameMode = ArkApi::GetApiUtils().GetShooterGameMode();
FString TribeName = L"Tribe of " + ArkApi::GetApiUtils().GetCharacterName(PC);
int CreatedTribeID = GameMode->ForceCreateTribe(&TribeName, 0);
FTribeData* CreatedTribeData = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(CreatedTribeData, 0x200);
if (GameMode->GetOrLoadTribeData(CreatedTribeID, CreatedTribeData))
PC->GetShooterPlayerState()->AddToTribe(CreatedTribeData, false, false, false, nullptr);
FMemory::Free(CreatedTribeData);
}
(edited)if (PC->GetPlayerCharacter() && !PC->IsSpectator() && !PC->IsInTribe())
{
AShooterGameMode* GameMode = ArkApi::GetApiUtils().GetShooterGameMode();
FString TribeName = L"Tribe of " + ArkApi::GetApiUtils().GetCharacterName(PC);
int CreatedTribeID = GameMode->ForceCreateTribe(&TribeName, 0);
FTribeData* CreatedTribeData = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(CreatedTribeData, 0x200);
if (GameMode->GetOrLoadTribeData(CreatedTribeID, CreatedTribeData))
PC->GetShooterPlayerState()->AddToTribe(CreatedTribeData, false, false, false, nullptr);
FMemory::Free(CreatedTribeData);
}
(edited) if (Dino->IsTamed() && Dino->LastInAllyRangeTime > 0 && GetWorld()->TimeSeconds > Dino->GetForceClaimTime() &&
UPrimalPlayerData::IsTribeID(Dino->TargetingTeam))
{
Dino->Destroy();
}
(edited)void Hook_APrimalDinoCharacter_Tick(APrimalDinoCharacter* _this, float DeltaSeconds)
{
APrimalDinoCharacter_Tick_original(_this, DeltaSeconds);
if (_this && _this->TargetingTeamField() >= 50000 && _this->GetForceClaimTime() > 0)
{
if (_this->GetForceClaimTime() <= static_cast<AShooterGameState*>(ArkApi::GetApiUtils().GetShooterGameMode()->GameStateField())->NetworkTimeField())
_this->Suicide();
}
}
(edited)void Hook_APrimalDinoCharacter_Tick(APrimalDinoCharacter* _this, float DeltaSeconds)
{
APrimalDinoCharacter_Tick_original(_this, DeltaSeconds);
if (_this && _this->TargetingTeamField() >= 50000 && _this->GetForceClaimTime() > 0)
{
if (_this->GetForceClaimTime() <= static_cast<AShooterGameState*>(ArkApi::GetApiUtils().GetShooterGameMode()->GameStateField())->NetworkTimeField())
_this->Suicide();
}
}
(edited)static ticks = 0;
if (ticks == 0)
{
//do your logic
}
(++ticks) %= x;
(edited)x
is max number of ticks to deferrx = 15
would be every half second.static time = 0
if (time == 0)
{
//logic
}
time += delta
if (time >= x)
{
time = 0;
}
(edited)bWantsServerThrottledTick=True
and AActor::ThrottledTick
Could probably use it on aprimaldinocharacterif (_this->GetForceClaimTime() <= static_cast<AShooterGameState*>(ArkApi::GetApiUtils().GetShooterGameMode()->GameStateField())->NetworkTimeField())
_this->Suicide();
(edited)fmt
{}
is implicit{:d}
and get that sweet compile time checkingHook_UPrimalInventoryComponent_AddItem
RemoteInventoryAllowRemoveItems
isn't for only blocking viewingbool Hook_UPrimalInventoryComponent_RemoteInventoryAllowViewing(UPrimalInventoryComponent* _this, AShooterPlayerController* PC, float MaxAllowedDistanceOffset)
{
if (_this && _this->GetOwner() && PC)
{
AActor* actor = _this->GetOwner();
if (ProtectCharacters && actor->IsA(AShooterCharacter::StaticClass()) && actor->TargetingTeamField() != PC->TargetingTeamField() && actor->TargetingTeamField() != 0 && actor->TargetingTeamField() >= 50000)
return false;
}
return UPrimalInventoryComponent_RemoteInventoryAllowViewing_original(_this, PC, MaxAllowedDistanceOffset);
}
targetingTeamField ()
returned each time I transferred the item _this was the same targetingTeamField ()
that I got when I opened Inventory at the beginningHook_UPrimalInventoryComponent_RemoteInventoryAllowRemoveItems(UPrimalInventoryComponent* _this, AShooterPlayerController* PC, UPrimalItem* anItemToTransfer, int* requestedQuantity, bool bRequestedByPlayer, bool bRequestDropping)
bool Hook_UPrimalInventoryComponent_RemoteInventoryAllowViewing(UPrimalInventoryComponent* _this, AShooterPlayerController* PC, float MaxAllowedDistanceOffset)
{
if (_this && _this->GetOwner() && PC)
{
AActor* actor = _this->GetOwner();
if (ProtectCharacters && actor->IsA(AShooterCharacter::StaticClass()) && actor->TargetingTeamField() != PC->TargetingTeamField() && actor->TargetingTeamField() != 0 && actor->TargetingTeamField() >= 50000)
return false;
}
return UPrimalInventoryComponent_RemoteInventoryAllowViewing_original(_this, PC, MaxAllowedDistanceOffset);
}
AShooterGameMode* GameMode = ArkApi::GetApiUtils().GetShooterGameMode();
GameMode->GlobalCommandsCheatManagerField()->DoExit();
UShooterCheatManager* shooterCheatManager = GetCheatManagerByPC(player);
shooterCheatManager->DoExit();
URCONServer::Init(URCONServer *this, FString *Password, int InPort, UShooterCheatManager *CSheatManager)
bool __fastcall URCONServer::Init(URCONServer *this, FString Password, int InPort, UShooterCheatManager *CSheatManager)
UCheatManager* cheat = player->CheatManagerField();
UShooterCheatManager* shooterCheatManager = static_cast<UShooterCheatManager*>(cheat);
shooterCheatManager->DoExit();
(edited)FItemNetID
FItemNetID item_id;
item_id.ItemID1 = id1;
item_id.ItemID2 = id2;
Now on the inventory:
inventory->RemoveItem(&item_id, false, false, true, true);
UCheatManager* cheat = player->CheatManagerField();
player->AddCheats(true);
UShooterCheatManager* shooterCheatManager = static_cast<UShooterCheatManager*>(cheat);
shooterCheatManager->DoExit();
bool __fastcall URCONServer::Init(URCONServer *this, FString Password, int InPort, UShooterCheatManager *CSheatManager)
if(bIsRCONCheatManager || PC->bIsAdmin) {
if(bIsRCONCheatManager) URCONServer::SetClientMessage(FString::Printf(L"Exiting or whatever..."));
GEngine->Exec(UWorldRef, L"Exit");
}
(edited)bool Hook_UPrimalInventoryComponent_RemoteInventoryAllowViewing(UPrimalInventoryComponent* _this, AShooterPlayerController* PC, float MaxAllowedDistanceOffset)
How can I prevent this from happening when the player is invited to join or accept a clan invitation
UCheatManager* cheat = player->CheatManagerField();
player->AddCheats(true);
UShooterCheatManager* shooterCheatManager = static_cast<UShooterCheatManager*>(cheat);
shooterCheatManager->DoExit();
FString GetBlueprint(UObjectBase* object)
{
if (object != nullptr && object->ClassField() != nullptr)
{
FString path_name;
object->ClassField()->GetDefaultObject(true)->GetFullName(&path_name, nullptr);
if (int find_index = 0; path_name.FindChar(' ', find_index))
{
path_name = "Blueprint'" + path_name.Mid(find_index + 1,
path_name.Len() - (find_index + (path_name.EndsWith(
"_C", ESearchCase::
CaseSensitive)
? 3
: 1))) + "'";
return path_name.Replace(L"Default__", L"", ESearchCase::CaseSensitive);
}
}
return FString("");
}
"Blueprint'/Game/PrimalEarth/Structures/StorageBox_Small.StorageBox_Small'"
instead of the value at the ARK wiki
"Blueprint'/Game/PrimalEarth/CoreBlueprints/Items/Structures/Misc/PrimalItemStructure_StorageBox_Small.PrimalItemStructure_StorageBox_Small'"
(edited)FString GetItemStructurePath(APrimalStructure* structure)
{
UClass* PrimalItem = structure->ConsumesPrimalItemField().uClass;
if (PrimalItem) // It might not be valid, as some structures are not placed with items
{
return GetBlueprint(PrimalItem->GetDefaultObject(true));
}
return FString("");
}
@Uacabool Hook_AShooterGameMode_HandleNewPlayer_Implementation(AShooterGameMode* _this, AShooterPlayerController* newPlayer, UPrimalPlayerData* playerData, AShooterCharacter* playerCharacter, bool isFromLogin)
{
if (!newPlayer)
{
return AShooterGameMode_HandleNewPlayer_Implementation_original(_this, newPlayer, playerData, playerCharacter, isFromLogin);
}
const uint64 steamId = ArkApi::GetApiUtils().GetSteamIdFromController(reinterpret_cast<AController*>(newPlayer));
if (!Store::Get().IsPlayerExists(steamId))
{
const uint64 playerId = ArkApi::GetApiUtils().GetPlayerID(newPlayer);
const FString playerName = ArkApi::GetApiUtils().GetCharacterName(newPlayer);
Log::GetLog()->warn("Char name: {}", playerName.ToString());
Store::Get().CreatePlayer(steamId, playerId, playerName.ToString());
}
return AShooterGameMode_HandleNewPlayer_Implementation_original(_this, newPlayer, playerData, playerCharacter, isFromLogin);
}
Here playerName
is always Survivor
. It worked fine earlier, so maybe it is caused by Ark updates? I have relevant ArkApi version. (edited)ue_coord / multiplier + 50
, but multiplier may be any for non-official maps. Multiplier can be easily determined if we know size of the map, I think, but which method can be used to get the size?FTribeData* CreatedTribeData = static_cast<FTribeData*>(FMemory::Malloc(0x128 + 0x28));
RtlSecureZeroMemory(CreatedTribeData, 0x128 + 0x28);
if (GameMode->GetOrLoadTribeData(tribe_id, CreatedTribeData))
shooterPlayerController->GetShooterPlayerState()->AddToTribe(CreatedTribeData, false, false, false, nullptr))
FMemory::Free(CreatedTribeData);
It was working, but now, after the players log off and connect again he is not in the tribe, also after the just after executing the AddToTribe, if the player press L to see the tribe it ask to create a new oneshooterPlayerController->ForceNetUpdate(true, true, true);
shooterPlayerController->GetShooterPlayerState()->PreSave();
GameMode->UpdateTribeData(CreatedTribeData);
All without success. Any hints of where to start looking to fix this will be greatly appreciated.FTribeData* CreatedTribeData = static_cast<FTribeData*>(FMemory::Malloc(0x128 + 0x28));
RtlSecureZeroMemory(CreatedTribeData, 0x128 + 0x28);
if (GameMode->GetOrLoadTribeData(tribe_id, CreatedTribeData))
shooterPlayerController->GetShooterPlayerState()->AddToTribe(CreatedTribeData, false, false, false, nullptr))
FMemory::Free(CreatedTribeData);
It was working, but now, after the players log off and connect again he is not in the tribe, also after the just after executing the AddToTribe, if the player press L to see the tribe it ask to create a new one bForce
try setting that to truePC->GetShooterPlayerState()->AddToTribe(CreatedTribeData, false, true, false, nullptr);
PC->GetShooterPlayerState()->UpdateTribeData(CreatedTribeData);
on the tribe manager is shows the tribe, without all the players that is progress, but on login/logoff still loses tribeC++
for (int i = 1; i <= 30; i++) {
if (!Dino->IsDead()) {
Dino->Suicide();
}
else if(Dino->IsDead())
{
break;
}
}
C++
for (int i = 1; i <= 30; i++) {
if (!Dino->IsDead()) {
Dino->Suicide();
}
else if(Dino->IsDead())
{
break;
}
}
do
Dino->Suicide();
while(!Dino->IsDead());
(edited)const auto status_component = dino->MyCharacterStatusComponent;
const auto base_character_level = status_component->BaseCharacterLevel;
const auto extra_character_level = status_component->ExtraCharacterLevel;
const auto total_level = base_character_level + extra_character_level;
c++
UPrimalInventoryComponent* inventory = shooter_pc->GetPlayerCharacter()->MyInventoryComponentField();
TArray<UPrimalItem*> items = inventory->ArkTributeItemsField();
for (UPrimalItem* item : items)
{
if (item->ClassField() != nullptr)
{
Log::GetLog()->error(std::to_string(item->ItemIDField().ItemID1)+"-"+ std::to_string(item->ItemIDField().ItemID2));
inventory->RemoveItem(&item->ItemIDField(), false, false, true, true);
}
}
item->RemoveItemFromArkTributeInventory();
AActor* Actor = player->GetPlayerCharacter()->GetAimedActor(ECollisionChannel::ECC_GameTraceChannel2, nullptr, 0.0, 0.0, nullptr, nullptr, false, false);
FHitResult Result;
player->GetPlayerCharacter()->GetAimedActor(&Result, ECollisionChannel::ECC_GameTraceChannel2,0.0, 0.0, false, false);
AActor* Actor= Result.GetActor();
Log::GetLog()->warn("2")
; I tried to write this but it crashed the serverFHitResult Result;
player->GetPlayerCharacter()->GetAimedActor(&Result, ECollisionChannel::ECC_GameTraceChannel2,0.0, 0.0, false, false);
AActor* Actor= Result.GetActor();
Log::GetLog()->warn("2")
; I tried to write this but it crashed the server NPCReplacements=(FromClassName="<classname>", ToClassName="<classname>")
namespace EPrimalCharacterStatusValue
{
enum Type
{
Health = 0x0,
Stamina = 0x1,
Torpidity = 0x2,
Oxygen = 0x3,
Food = 0x4,
Water = 0x5,
Temperature = 0x6,
Weight = 0x7,
MeleeDamageMultiplier = 0x8,
SpeedMultiplier = 0x9,
TemperatureFortitude = 0xA,
CraftingSpeedMultiplier = 0xB,
MAX = 0xC,
};
}
DECLARE_HOOK(UObject_ProcessEvent, void, UObject*, UFunction*, void*);
void Hook_UObject_ProcessEvent(UObject* _this, UFunction* Function, void* Parameters)
{
if (!Function)
return;
FString name;
Function->NameField().ToString(&name);
if (name.Find(L"NetExec") != -1
&& GetBlueprint(_this).Find(L"TekCloningChamber") != -1)
{
BPParams::BPServerHandleNetExec_Params* params = static_cast<BPParams::BPServerHandleNetExec_Params*>(Parameters);
if (params != nullptr
&& params->FromPC
&& params->CommandName.ToString().Find(L"Clone") != -1)
{
APrimalDinoCharacter* dino = static_cast<APrimalDinoCharacter*>(params->ExecParams.ObjParam1);
if (dino
&& dino->bNeutered()())
{
GET_MESSAGE("CannotCloneNeutered");
UTILS.SendNotification(static_cast<AShooterPlayerController*>(params->FromPC), disp_color, disp_scale, disp_time, nullptr, *msg);
return; // If you return, dino won't be cloned.
}
}
}
}
(edited)struct UFunction : UObject
struct __declspec(align(8)) BPServerHandleNetExec_Params
{
APlayerController* FromPC;
FName CommandName;
FBPNetExecParams ExecParams;
bool ReturnValue;
};
DECLARE_HOOK(UObject_ProcessEvent, void, UObject*, UFunction*, void*);
void Hook_UObject_ProcessEvent(UObject* _this, UFunction* Function, void* Parameters)
{
if (!Function)
return;
FString name;
Function->NameField().ToString(&name);
if (name.Find(L"NetExec") != -1
&& GetBlueprint(_this).Find(L"TekCloningChamber") != -1)
{
BPParams::BPServerHandleNetExec_Params* params = static_cast<BPParams::BPServerHandleNetExec_Params*>(Parameters);
if (params != nullptr
&& params->FromPC
&& params->CommandName.ToString().Find(L"Clone") != -1)
{
APrimalDinoCharacter* dino = static_cast<APrimalDinoCharacter*>(params->ExecParams.ObjParam1);
if (dino
&& dino->bNeutered()())
{
GET_MESSAGE("CannotCloneNeutered");
UTILS.SendNotification(static_cast<AShooterPlayerController*>(params->FromPC), disp_color, disp_scale, disp_time, nullptr, *msg);
return; // If you return, dino won't be cloned.
}
}
}
}
(edited)std::unordered_map<int, std::any> FuncMap;
bool __fastcall AActor::BPServerHandleNetExecCommand(AActor *this, APlayerController *FromPC, FName CommandName, FBPNetExecParams *ExecParams)
bool __fastcall AActor::BPServerHandleNetExecCommand(AActor *this, APlayerController *FromPC, FName CommandName, FBPNetExecParams *ExecParams)
我在api中没有找到这个钩子 我应该怎么使用它FBPNetExecParams
this?BPParams::BPServerHandleNetExec_Params
struct FNetExecParams {};
lolstruct __declspec(align(8)) BPServerHandleNetExec_Params
{
APlayerController* FromPC;
FName CommandName;
FBPNetExecParams ExecParams;
bool ReturnValue;
};
struct FBPNetExecParams
{
int IntParam1;
int IntParam2;
int IntParam3;
float FloatParam1;
float FloatParam2;
float FloatParam3;
UObject *ObjParam1;
UObject *ObjParam2;
UObject *ObjParam3;
FString StringParam1;
};
void*
Mentors
and ranks above can repost it for you. It's restricted from Beginners role to prevent spam or false code.bool GiveDinoInACryoPod(AShooterPlayerController* player_controller, DinoData* creation_data);
where DinoData
is something like
struct
{
std::string blueprintDino
std::string blueprintDinoSaddle
int level
bool bIsNeutered
} DinoData
DinoData
structure before/after the function call in it's own stack frame and do all kinds of things / reuse the same memoryDinoData
to then pass to GiveDinoInACryoPod
DinoData RandomDino(std::string&& dino_blueprint, std::string&& saddle_blueprint)
bool __fastcall URCONServer::Init(URCONServer *this, FString Password, int InPort, UShooterCheatManager *CSheatManager)
ArkApi::GetApiUtils().GetCheatManager();
(edited)ArkApi::GetApiUtils().GetCheatManager();
(edited)c++
void CreateFolderTest(APrimalStructureItemContainer* _this)
{
UPrimalInventoryComponent* inv = _this->MyInventoryComponentField();
if (inv) {
inv->AddCustomFolder(L"MYTESTFOLDER", 512);
}
}
Thank you in advancec++
void MakeFolderCmd(AShooterPlayerController* player_controller, FString* message, int mode) {
AActor* Actor = getAimedActor(player_controller);
// make sure we have a structure
if (Actor && Actor->IsA(APrimalStructure::GetPrivateStaticClass()))
{
APrimalStructure* objStructure = static_cast<APrimalStructure*>(Actor);
UPrimalInventoryComponent* objInventory = nullptr;
if (objStructure->IsA(APrimalStructureItemContainer::GetPrivateStaticClass()))
{
APrimalStructureItemContainer* objStructureIC = static_cast<APrimalStructureItemContainer*>(objStructure);
objInventory = objStructureIC->MyInventoryComponentField();
FString* myFolderName = static_cast<FString*>(FMemory::Malloc(sizeof(FString)));
RtlSecureZeroMemory(myFolderName, sizeof(FString));
myFolderName->Append("TEST");
objInventory->AddCustomFolder(*myFolderName, 512);
FMemory::Free(myFolderName);
}
}
}
(edited)TArray<AShooterPlayerController*> GetAllPlayerControllers()
{
TArray<AShooterPlayerController*> ControllerMap;
const auto& PCS = ArkApi::GetApiUtils().GetWorld()->PlayerControllerListField();
for (TWeakObjectPtr<APlayerController> APC : PCS)
{
AShooterPlayerController* PC = static_cast<AShooterPlayerController*>(APC.Get());
if (PC)
ControllerMap.Add(PC);
}
return ControllerMap;
}
TArray<uint64> nppAdminArray;
FString NPPAdminGroup;
NPPAdminGroup = FString(ArkApi::Tools::Utf8Decode(NPP::config["General"]["NPPAdminGroup"]).c_str());
nppAdminArray.Empty();
nppAdminArray.Append(Permissions::GetGroupMembers(NPPAdminGroup));
API::Timer::Get().DelayExecute(&LoadNppPermissionsArray, 60);
void RecurringExecute(const Func& callback, int execution_interval, int execution_counter, bool async, Args&&... args)
a good alternative to ArkApi::GetCommands().AddOnTimerCallback()
if I don't want the callback fired every second?void TimedLoop()
{
if (difftime(time(0), LastTimedLoop) >= 10) //10 seconds between
{
//your processing here
//your processing here
LastTimedLoop = time(0); //reset time
}
}
void TimeLoop {
auto diff = std::chrono::duration_cast<std::chrono::seconds>(next_player_update - std::chrono::system_clock::now());
if (diff.count() <= 0) {
// do things
next_player_update = std::chrono::system_clock::now() + std::chrono::minutes(PlayerUpdateIntervalInMins);
}
}
API::Timer::Get().DelayExecute(&LoadNppPermissionsArray, 60);
bool Die(float KillingDamage, FDamageEvent * DamageEvent, AController * Killer, AActor * DamageCauser) { return NativeCall<bool, float, FDamageEvent*, AController*, AActor*>(this, "APrimalCharacter.Die", KillingDamage, DamageEvent, Killer, DamageCauser); }
this one, right?bool Die(float KillingDamage, FDamageEvent * DamageEvent, AController * Killer, AActor * DamageCauser) { return NativeCall<bool, float, FDamageEvent*, AController*, AActor*>(this, "APrimalDinoCharacter.Die", KillingDamage, DamageEvent, Killer, DamageCauser); }
void Hook_APrimalDinoCharacter_EmitPoop(APrimalDinoCharacter* _this)
{
std::string emite = _this->bPoopIsEgg().Get() ? "EGG" : "POOP";
Log::GetLog()->error(emite);
APrimalDinoCharacter_EmitPoop_original(_this);
}
FTribeData* tribe_data = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(tribe_data, 0x200);
ArkApi::GetApiUtils().GetShooterGameMode()->LoadTribeData(TribeId, tribe_data, false, false);
const string tribeName = tribe_data->TribeNameField().ToString();
Is this the only way to be able to look up a Tribe Name? (edited)GetStructSize<FTribeData>()
FTribeData* TribeData;
ArkApi::GetApiUtils().GetShooterGameMode()->LoadTribeData(TribeID, TribeData, false, false);
std::string TribeName = TribeData->TribeNameField().ToString();
FTribeData* TribeData = new FTribeData();
?FTribeData* TribeData;
ArkApi::GetApiUtils().GetShooterGameMode()->LoadTribeData(TribeID, TribeData, false, false);
std::string TribeName = TribeData->TribeNameField().ToString();
FTribeData* TribeData = new FTribeData();
? if (mymultimap.find(path_name) == mymultimap.end()) {
mymultimap.insert(std::pair<FString, int>(path_name, 1));
}
else {
for (auto itr = mymultimap.find(path_name); itr != mymultimap.end(); itr++)
itr->second++;
}
First structure will print 2 (reality only 1)
second structure will print 2 (correct)
3rd structure will print 9 (reality only 8)mymultimap[path_name] = 1
mymultimap[path_name]++
_1
to engrams._1
to engrams. - '/Loot' - Drop player loot.
- '/Lava' - TP the player on foundation in the middle of Lava
- '/Water' - TP the player deep underwater in some vacuum moonpool
- '/Dodo' - Summon on the player X of dodos
- '/Bola' - Bola the player for X amount of time
- '/Sleep' - Tranq the player for X amount of time
- '/DoubleTroll' - TP the player to some random player (or specific player) - troll them both.
- '/AntiDinos' - Give the player "Grapple Buff" that disallow him to mount dinos for X amount of time.
- '/Kill' - Ofc basic troll - kill the player
If someone find this thing doable - Let me know
All rights reserved ©️
Have a good night yall !- '/Loot' - Drop player loot.
- '/Lava' - TP the player on foundation in the middle of Lava
- '/Water' - TP the player deep underwater in some vacuum moonpool
- '/Dodo' - Summon on the player X of dodos
- '/Bola' - Bola the player for X amount of time
- '/Sleep' - Tranq the player for X amount of time
- '/DoubleTroll' - TP the player to some random player (or specific player) - troll them both.
- '/AntiDinos' - Give the player "Grapple Buff" that disallow him to mount dinos for X amount of time.
- '/Kill' - Ofc basic troll - kill the player
If someone find this thing doable - Let me know
All rights reserved ©️
Have a good night yall ! c++
auto shooter = player_controller->GetPlayerCharacter();
if (shooter)
{
if (shooter->LastGrapHookPullingOwnerField())
{
// points to the last character to grapple me
// will still has a value even if you are not currently being grappled
}
if (shooter->LastGrapHookPullingMeField())
{
// points to the current player grappling me
// if not grappled, then this is null
Log::GetLog()->info("I'm being grappled! HELP!");
}
}
(edited)c++
DECLARE_HOOK(AShooterGameState_DayNumberField, int&, AShooterGameState*);
void plugin_load()
{
Log::Get().Init("AzTest");
ArkApi::GetHooks().SetHook("AShooterGameState.DayNumberField", &Hook_AShooterGameState_DayNumberField, &AShooterGameState_DayNumberField_original);
}
void plugin_unload()
{
ArkApi::GetHooks().DisableHook("AShooterGameState.DayNumberField", &Hook_AShooterGameState_DayNumberField);
}
int ORIGINAL_VALUE = 0;
int CUSTOM_VALUE = 1000;
int& _cdecl Hook_AShooterGameState_DayNumberField(AShooterGameState* _this)
{
ORIGINAL_VALUE = AShooterGameState_DayNumberField_original(_this);
return CUSTOM_VALUE;
}
03/12/22 21:16 [API][warning] Failed to find hook (AShooterGameState.DayNumberField)
03/12/22 21:50 [API][warning] Failed to find hook (APrimalCharacter.TakeDamage)
DECLARE_HOOK(APrimalCharacter_TakeDamage, float, APrimalCharacter*, float, FDamageEvent*, AController*, AActor*);
void plugin_load()
{
Log::Get().Init("AzTest");
ArkApi::GetHooks().SetHook("APrimalCharacter.TakeDamage", &Hook_APrimalCharacter_TakeDamage, &APrimalCharacter_TakeDamage_original);
}
float _cdecl Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
return 0;
}
(edited)c++
DECLARE_HOOK(AShooterGameState_DayNumberField, int&, AShooterGameState*);
void plugin_load()
{
Log::Get().Init("AzTest");
ArkApi::GetHooks().SetHook("AShooterGameState.DayNumberField", &Hook_AShooterGameState_DayNumberField, &AShooterGameState_DayNumberField_original);
}
void plugin_unload()
{
ArkApi::GetHooks().DisableHook("AShooterGameState.DayNumberField", &Hook_AShooterGameState_DayNumberField);
}
int ORIGINAL_VALUE = 0;
int CUSTOM_VALUE = 1000;
int& _cdecl Hook_AShooterGameState_DayNumberField(AShooterGameState* _this)
{
ORIGINAL_VALUE = AShooterGameState_DayNumberField_original(_this);
return CUSTOM_VALUE;
}
DECLARE_HOOK(APrimalCharacter_TakeDamage, float, APrimalCharacter*, float, FDamageEvent*, AController*, AActor*);
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}
ArkApi::GetHooks().SetHook("APrimalCharacter.TakeDamage", &Hook_APrimalCharacter_TakeDamage, &APrimalCharacter_TakeDamage_original);
ArkApi::GetHooks().DisableHook("APrimalCharacter.TakeDamage", &Hook_APrimalCharacter_TakeDamage);
DECLARE_HOOK(APrimalCharacter_TakeDamage, float, APrimalCharacter*, float, FDamageEvent*, AController*, AActor*);
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
return 0;
}
void plugin_load()
{
Log::Get().Init("AzTest");
ArkApi::GetHooks().SetHook("APrimalCharacter.TakeDamage", &Hook_APrimalCharacter_TakeDamage, &APrimalCharacter_TakeDamage_original);
}
Does I have to create a ticket ? (edited)void Hook_UShooterCheatManager_ScriptCommand(UShooterCheatManager* _this, FString* commandString)
Is there a way to get the Player Controller from UShooterCheatManager ? i only found functions the other way around.AShooterPlayerController* MyPCField()
(edited)UPrimalCharacterStatusComponent
That component has function to set current/max status modifier (hp, stam, torpor, etc...)
You can get it off APrimalCharacter::GetCharacterStatusComponent
float& TorporExitPercentThresholdField()
float& TheMaxTorporIncreasePerBaseLevelField()
float& OriginalMaxTorporField()
float& FortitudeTorpidityDecreaseMultiplierField()
float& FortitudeTorpidityIncreaseResistanceField()
float& KnockedOutTorpidityRecoveryRateMultiplierField()
float& DehydrationTorpidityMultiplierField()
float& StarvationTorpidityMultuplierField()
float& StarvationTorpidityIncreaseRateField()
float& DehyrdationTorpidityIncreaseRateField()
float& InjuredTorpidityIncreaseMultiplierField()
these are the options in statuscomponent, which don't really seem like the current direct torpor valueBPDirectSetStatusModifier
or soBPDirectSetCurrentStatusValue
and BPDirectSetMaxStatusValue
EPrimalCharacterStatusValue::Type
which has all the possible statuses you wantEPrimalCharacterStatusValue::Torpidity
void Hook_UObject_ProcessEvent(UObject* _this, UFunction* Function, void* Params)
{
UObject_ProcessEvent_original(_this, Function, Params);
// get the steamid
UProperty* steamIdProperty = _this->FindProperty(FName("Steam ID", EFindName::FNAME_Add));
if (steamIdProperty)
{
// variable was found
FString steamId_String = steamIdProperty->Get<FString>(_this);
uint64 steamId = std::stoull(*steamId_String);
}
}
void Hook_UObject_ProcessEvent(UObject* _this, UFunction* Function, void* Params)
{
UObject_ProcessEvent_original(_this, Function, Params);
// get the steamid
UProperty* steamIdProperty = _this->FindProperty(FName("Steam ID", EFindName::FNAME_Add));
if (steamIdProperty)
{
// variable was found
FString steamId_String = steamIdProperty->Get<FString>(_this);
uint64 steamId = std::stoull(*steamId_String);
}
}
UFunction
's bytecode through its TArray<unsigned char> &UStruct::ScriptField()
. Is it safe to modify that? Do UFunction
s get overwritten or garbage collected during runtime or anything like that I need to worry about?UFunction
with a Func
field (not currently exposed in ArkServerApi) that points to my dll function
2. Modify an existing blueprint function by inserting EX_FinalFunction
or similar bytecode instructions with a call to my dll UFunction
UFunction
's bytecode through its TArray<unsigned char> &UStruct::ScriptField()
. Is it safe to modify that? Do UFunction
s get overwritten or garbage collected during runtime or anything like that I need to worry about? UFunction
. From our native function, we can access the Blueprint function's inputs, outputs, and local variables through the FFrame* Stack
argument. This SetScriptHook()
example currently only works on some functions (I've been playing with the cryopod's CanDeploy
and TryDeploy
functions, which are internal calls handled by UObject::CallFunction()
, not UObject::ProcessEvent()
). Shouldn't be too hard to make function insertion more intelligent to generalize this to most BP functions, regardless of how they're invoked.c++
#define UFUNC_FLAG_Native 0x400
#define UPROP_FLAG_Edit 0x001
#define UPROP_FLAG_Parm 0x080
#define UPROP_FLAG_OutParm 0x100
#define USCRIPT_EX_Return 0x04
#define USCRIPT_EX_Nothing 0x0B
#define USCRIPT_EX_FinalFunction 0x1C
#define USCRIPT_EX_EndOfScript 0x53
#define UFUNCTION_SIZE 0xB0 // Better to calculate this at runtime
struct FProperty : UField {};
struct FOutParmRec
{
FOutParmRec* NextOutParmField() { return *GetNativePointerField<FOutParmRec**>(this, "FOutParmRec.NextOutParm"); }
uint8* PropAddrField() { return *GetNativePointerField<uint8**>(this, "FOutParmRec.PropAddr"); }
FProperty* PropertyField() { return *GetNativePointerField<FProperty**>(this, "FOutParmRec.Property"); }
};
struct FFrame : FOutputDevice
{
UFunction* NodeField() { return *GetNativePointerField<UFunction**>(this, "FFrame.Node"); }
FOutParmRec* OutParmsField() { return *GetNativePointerField<FOutParmRec**>(this, "FFrame.OutParms"); }
uint8* LocalsField() { return *GetNativePointerField<uint8**>(this, "FFrame.Locals"); }
};
typedef void (*FNativeFuncPtr)(UObject*, FFrame*, void* const);
struct UFunction : UStruct
{
int& FunctionFlagsField() { return *GetNativePointerField<int*>(this, "UFunction.FunctionFlags"); }
FNativeFuncPtr& FuncField() { return *GetNativePointerField<FNativeFuncPtr*>(this, "UFunction.Func"); }
};
c++
void SetScriptHook(UFunction* scriptUFunction, FNativeFuncPtr nativeFunction)
{
int scriptSize = scriptUFunction->ScriptField().Num();
if (scriptSize < 3)
{
Log::GetLog()->error("Too few bytes in script");
return;
}
// For now, just initialize the new UFunction by copying the one we're hooking.
// Maybe not a good idea, need to investigate!
UFunction* hookUFunction = static_cast<UFunction*>(malloc(UFUNCTION_SIZE));
if (!hookUFunction)
{
Log::GetLog()->error("null hookUFunction");
return;
}
memcpy(hookUFunction, scriptUFunction, UFUNCTION_SIZE);
// Point the new UFunction at our native function
hookUFunction->FunctionFlagsField() = UFUNC_FLAG_Native;
hookUFunction->FuncField() = nativeFunction;
// This won't work for all functions. Need to detect dynamically whether or not
// there is an EX_Return, etc
if ((scriptUFunction->ScriptField()[scriptSize - 3] != USCRIPT_EX_Return) ||
(scriptUFunction->ScriptField()[scriptSize - 2] != USCRIPT_EX_Nothing) ||
(scriptUFunction->ScriptField()[scriptSize - 1] != USCRIPT_EX_EndOfScript))
{
Log::GetLog()->error("Bad end of script");
return;
}
// Insert a call to our UFunction at the end of the script
scriptUFunction->ScriptField().RemoveAt(scriptSize - 3, 3, true);
unsigned char instructions[] = { USCRIPT_EX_FinalFunction,
(DWORD64)hookUFunction >> 0 & 0xFF,
(DWORD64)hookUFunction >> 8 & 0xFF,
(DWORD64)hookUFunction >> 16 & 0xFF,
(DWORD64)hookUFunction >> 24 & 0xFF,
(DWORD64)hookUFunction >> 32 & 0xFF,
(DWORD64)hookUFunction >> 40 & 0xFF,
(DWORD64)hookUFunction >> 48 & 0xFF,
(DWORD64)hookUFunction >> 56 & 0xFF,
USCRIPT_EX_Return,
USCRIPT_EX_Nothing,
USCRIPT_EX_EndOfScript
};
scriptUFunction->ScriptField().Append(instructions, sizeof(instructions));
}
c++
void ExampleScriptHook(UObject* _this, FFrame* Stack, void* const Result)
{
if (!Stack->NodeField())
return;
Log::GetLog()->info("-- Inputs --");
for (UProperty* property = Stack->NodeField()->PropertyLinkField(); property; property = property->PropertyLinkNextField())
if ((property->PropertyFlagsField() & UPROP_FLAG_Parm) && !(property->PropertyFlagsField() & UPROP_FLAG_OutParm))
Log::GetLog()->info(" " + property->NameField().ToString().ToString());
Log::GetLog()->info("-- Local Vars --");
for (UProperty* property = Stack->NodeField()->PropertyLinkField(); property; property = property->PropertyLinkNextField())
if (property->PropertyFlagsField() & UPROP_FLAG_Edit)
Log::GetLog()->info(" " + property->NameField().ToString().ToString());
// Inputs and local vars can be accessed with the FFrame::LocalsField() uint8 ptr plus the UProperty::Offset_InternalField()
Log::GetLog()->info("-- Outputs --");
for (UProperty* property = Stack->NodeField()->PropertyLinkField(); property; property = property->PropertyLinkNextField())
if ((property->PropertyFlagsField() & UPROP_FLAG_Parm) && (property->PropertyFlagsField() & UPROP_FLAG_OutParm))
Log::GetLog()->info(" " + property->NameField().ToString().ToString());
// Outputs can be accessed by traversing the FFrame's FOutParmRec linked list and using FOutParmRec::PropAddrField().
// However, the list doesn't seem to be null terminated so this needs to be done carefully (maybe I'm just inspecting the
// wrong value or I have something badly defined)
}
c++
void SetScriptHook(UFunction* scriptUFunction, FNativeFuncPtr nativeFunction)
{
int scriptSize = scriptUFunction->ScriptField().Num();
if (scriptSize < 3)
{
Log::GetLog()->error("Too few bytes in script");
return;
}
// For now, just initialize the new UFunction by copying the one we're hooking.
// Maybe not a good idea, need to investigate!
UFunction* hookUFunction = static_cast<UFunction*>(malloc(UFUNCTION_SIZE));
if (!hookUFunction)
{
Log::GetLog()->error("null hookUFunction");
return;
}
memcpy(hookUFunction, scriptUFunction, UFUNCTION_SIZE);
// Point the new UFunction at our native function
hookUFunction->FunctionFlagsField() = UFUNC_FLAG_Native;
hookUFunction->FuncField() = nativeFunction;
// This won't work for all functions. Need to detect dynamically whether or not
// there is an EX_Return, etc
if ((scriptUFunction->ScriptField()[scriptSize - 3] != USCRIPT_EX_Return) ||
(scriptUFunction->ScriptField()[scriptSize - 2] != USCRIPT_EX_Nothing) ||
(scriptUFunction->ScriptField()[scriptSize - 1] != USCRIPT_EX_EndOfScript))
{
Log::GetLog()->error("Bad end of script");
return;
}
// Insert a call to our UFunction at the end of the script
scriptUFunction->ScriptField().RemoveAt(scriptSize - 3, 3, true);
unsigned char instructions[] = { USCRIPT_EX_FinalFunction,
(DWORD64)hookUFunction >> 0 & 0xFF,
(DWORD64)hookUFunction >> 8 & 0xFF,
(DWORD64)hookUFunction >> 16 & 0xFF,
(DWORD64)hookUFunction >> 24 & 0xFF,
(DWORD64)hookUFunction >> 32 & 0xFF,
(DWORD64)hookUFunction >> 40 & 0xFF,
(DWORD64)hookUFunction >> 48 & 0xFF,
(DWORD64)hookUFunction >> 56 & 0xFF,
USCRIPT_EX_Return,
USCRIPT_EX_Nothing,
USCRIPT_EX_EndOfScript
};
scriptUFunction->ScriptField().Append(instructions, sizeof(instructions));
}
UFunction
. From our native function, we can access the Blueprint function's inputs, outputs, and local variables through the FFrame* Stack
argument. This SetScriptHook()
example currently only works on some functions (I've been playing with the cryopod's CanDeploy
and TryDeploy
functions, which are internal calls handled by UObject::CallFunction()
, not UObject::ProcessEvent()
). Shouldn't be too hard to make function insertion more intelligent to generalize this to most BP functions, regardless of how they're invoked. FFrame
and FOutParmRec
and fixing UFunction
opens some really cool doors (I had FProperty
in my example but that's really just UProperty
which is already in ArkServerApi). I also found that ArkServerApi already has enums for function flags and the UnrealScript bytecode, EFunctionFlags
and EExprToken
. The UProperty flags are #defines in the Unreal Engine source so I guess they didn't get extracted however the enums did.Ex_Return
(although there may or may not be a return value). You have A LOT of power at the end of a script function with access to its locals and outputs, but I think it would still be nice in some cases to have the ability to insert a call at a specific offset in the script.ProcessEvent()
and you could handle CallFunction()
the same way. I always wonder if that has an impact on performance. I guess it may be negligible if done carefully.UFunction
s by index in ProcessEvent()
rather than name, that seems reasonablec++
typedef void (*BlueprintHookFuncPtr)(UObject*, FFrame*);
#define BLUEPRINT_HOOK_USCRIPT_SIZE 12 // EX_FinalFunction + 8 address bytes + EX_Return + EX_Nothing + EX_EndOfScript
std::unordered_map<UFunction*, std::vector<BlueprintHookFuncPtr>> preHooks;
std::unordered_map<UFunction*, std::vector<BlueprintHookFuncPtr>> postHooks;
void BlueprintHookDispatcher(UObject* obj, FFrame* frame, void* const result)
{
unsigned char instructions[BLUEPRINT_HOOK_USCRIPT_SIZE];
unsigned char* savedCode;
// Call pre-hooks
for (BlueprintHookFuncPtr preHook : preHooks[frame->NodeField()])
preHook(obj, frame);
// Remove the hook dispatcher script from the original blueprint script
for (int i = 0; i < BLUEPRINT_HOOK_USCRIPT_SIZE; ++i)
{
instructions[i] = frame->NodeField()->ScriptField().GetData()[0];
frame->NodeField()->ScriptField().RemoveAt(0);
}
savedCode = frame->CodeField();
frame->CodeField() = frame->NodeField()->ScriptField().GetData();
// Process the original script with the current stack frame
obj->ProcessInternal(frame, result);
// Re-insert the hook dispatcher script
for (int i = 0; i < BLUEPRINT_HOOK_USCRIPT_SIZE; ++i)
frame->NodeField()->ScriptField().Insert(instructions[i], i);
frame->CodeField() = savedCode;
// Call post-hooks
for (BlueprintHookFuncPtr postHook : postHooks[frame->NodeField()])
postHook(obj, frame);
}
void Foo(UObject*, FFrame*, void* const)
signature instead of regular native arguments. using x = void(__thiscall)();
x* my_ptr;
std::cout << typeid(x*).name();
== Error using x = void(__thiscall*)();
x my_ptr;
std::cout << typeid(x).name();
my_ptr
and the result of typeid
should be the same between thesestdcall
is ok)x = void(__thiscall)(); x*
is congruent with x = void(__thiscall*)(); x
void*
)cheat SetImprintQuality 1
does not seem to help. They have the whole ancestry and everything else you'd expect for a bred dino in the UI but as far as imprinting is concerned it seems as if they are treated as tamed.
Anyone have any ideas what could be causing this issue? Is there a flag signifying that a dino is bred and can be imprinted?cheat SetImprintQuality 1
does not seem to help. They have the whole ancestry and everything else you'd expect for a bred dino in the UI but as far as imprinting is concerned it seems as if they are treated as tamed.
Anyone have any ideas what could be causing this issue? Is there a flag signifying that a dino is bred and can be imprinted? UpdateImprintingDetails
?UpdateImprintingDetails
to see if that might be it.UpdateImprintingDetails
to see if that might be it. Hook_APrimalDinoCharacter_SpawnFromDinoDataEx
and check targeting team or claim. if ok - claim dino and set imprintArkApi::GetApiUtils().SendChatMessage()
.
How would one go about reading the last chat message on the server? (edited)ArkApi::GetApiUtils().SendChatMessage()
.
How would one go about reading the last chat message on the server? (edited)c++
static UClass* Tusoteuthis_Character_BP_C = (UClass*)Globals::FindClass("BlueprintGeneratedClass /Game/PrimalEarth/Dinos/Tusoteuthis/Tusoteuthis_Character_BP.Tusoteuthis_Character_BP_C");