KillerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr); (edited)float Hook_APrimalStructure_TakeDamage(APrimalStructure* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
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;
}
}
APrimalStructure_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
} (edited)float Hook_APrimalStructure_TakeDamage(APrimalStructure* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)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("MyPlugin");
LoadConfiguration();
MyPluginDatabase::InitDatabase();
ArkApi::GetHooks().SetHook("AShooterGameMode.HandleNewPlayer_Implementation", &Hook_AShooterGameMode_HandleNewPlayer, &AShooterGameMode_HandleNewPlayer_original);
ArkApi::GetCommands().AddChatCommand("/myplugin", &MyPluginFunction);
}
void Unload()
{
ArkApi::GetHooks().DisableHook("AShooterGameMode.HandleNewPlayer_Implementation", &Hook_AShooterGameMode_HandleNewPlayer);
ArkApi::GetCommands().RemoveChatCommand("/myplugin");
}
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;
}11/28/18 09:02 [API][info] Loaded plugin - myplugin
11/28/18 09:03 [API][info] Unloaded plugin - myplugin
11/28/18 09:04 [API][info] Loaded plugin - myplugin"settings":{
"AutomaticPluginReloading":false,
"AutomaticPluginReloadSeconds":5,
"SaveWorldBeforePluginReload":true
},11/28/18 11:29 [API][warning] (ArkApi::PluginManager::UnloadPluginCmd) Plugin extendedrcon is not loaded
11/28/18 11:31 [API][info] Loaded plugin - extendedrcon
11/28/18 11:34 [API][info] Unloaded plugin - extendedrcon[API][info] Unloaded plugin - ExtendedRcon
yes
"
struct TribeScore
{
uint64 PlayerSteamID;
uint64 PlayerTribeID;
int Score;
TribeScore(uint64 PlayerSteamID, uint64 PlayerTribeID, int Score) : PlayerSteamID(PlayerSteamID), PlayerTribeID(PlayerTribeID), Score(Score) {}
};
typedef std::vector<TribeScore> TribeScoreA;
TribeScoreA TribeScoreData;
I have this which loads up from a file at first.
I want to get which player has the highest score of a certain tribe.
Kind of like: void GetTribeBestScorer(uint64 tribeID)
Do correct me if anything above is not how it is usually done.struct TribeScore
{
TribeScore(uint64 PlayerSteamID, int Score)
: PlayerSteamID(PlayerSteamID),
Score(Score)
{
}
uint64 PlayerSteamID;
int Score;
};
std::unordered_map<uint64, std::vector<TribeScore>> TribeScoreData;
uint64 GetTribeBestScorer(uint64 tribeID)
{
auto& tribe_scores = TribeScoreData[tribeID];
const auto result = std::max_element(tribe_scores.begin(), tribe_scores.end(),
[](const TribeScore& a, const TribeScore& b)
{
return a.Score < b.Score;
});
return result != tribe_scores.end() ? result->PlayerSteamID : 0;
} (edited)int ownerPlayerId = _this->OwningPlayerIDField();
if (ownerPlayerId == 0) // Owner is tribe (edited)DEBUG: Hook_APrimalStructure_TakeDamage - damageReceiverPlayerID: 564558341 bool RequiresNotFollowing;
bool RequiresPassiveFlee;
bool RequiresIgnoreWhistle;
bool RequiresNeutered;
My inner hook variables: int following;
bool passiveflee;
bool ignorewhistle;
bool neutered; (edited)if (RequiresNotFollowing && following) Do1(); (edited)if ((RequiresNotFollowing && following) && (RequiresPassiveFlee && passiveflee) && (...)) Do1();bool config[10];
bool hook[10];
for (int i = 0; i < 10; ++i)
{
if (config[i] && !hook[i])
return false;
}//check for enemy structures nearby
TArray<AActor*> AllStructures;
UGameplayStatics::GetAllActorsOfClass(reinterpret_cast<UObject*>
(ArkApi::GetApiUtils().GetWorld()), APrimalStructure::GetPrivateStaticClass(), &AllStructures);
for (AActor* StructureActor : AllStructures)
{
if (StructureActor)
{
if (StructureActor->TargetingTeamField() > 0 && _this->TargetingTeamField() != StructureActor->TargetingTeamField())
{
APrimalStructure* Structure = static_cast<APrimalStructure*>(StructureActor);
if (FVector::Distance(_this->RootComponentField()->RelativeLocationField(), Structure->RootComponentField()->RelativeLocationField()) <= DinoPassiveProtection::MinimumEnemyStructureDistance)
{
isNotNearEnemyStructures = false;
break;
}
else
{
isNotNearEnemyStructures = true;
}
}
}
}//build config array
bool configConditions[] = {
DinoPassiveProtection::RequiresNotFollowing,
DinoPassiveProtection::RequiresPassiveFlee,
DinoPassiveProtection::RequiresIgnoreWhistle,
DinoPassiveProtection::RequiresNeutered,
DinoPassiveProtection::RequiresNoRider,
DinoPassiveProtection::RequiresNoInventory,
DinoPassiveProtection::RequiresNoNearbyEnemyStructures,
true
};
//build hook vars array
bool hookActuals[] = {
isNotFollowing,
(isPassiveAggressive && isPassiveFlee),
isIgnoringWhistles,
isNeutered,
hasNoRider,
hasNoInventory,
isNotNearEnemyStructures,
isHealthAboveMin
};
for (int i = 0; i < 8 ; ++i)
{
if (configConditions[i] && !hookActuals[i])
return APrimalDinoCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}//check for enemy structures nearby
TArray<AActor*> AllStructures;
UGameplayStatics::GetAllActorsOfClass(reinterpret_cast<UObject*>
(ArkApi::GetApiUtils().GetWorld()), APrimalStructure::GetPrivateStaticClass(), &AllStructures);
for (AActor* StructureActor : AllStructures)
{
if (StructureActor)
{
if (StructureActor->TargetingTeamField() > 0 && _this->TargetingTeamField() != StructureActor->TargetingTeamField())
{
APrimalStructure* Structure = static_cast<APrimalStructure*>(StructureActor);
if (FVector::Distance(_this->RootComponentField()->RelativeLocationField(), Structure->RootComponentField()->RelativeLocationField()) <= DinoPassiveProtection::MinimumEnemyStructureDistance)
{
isNotNearEnemyStructures = false;
break;
}
else
{
isNotNearEnemyStructures = true;
}
}
}
} (edited)
1
1#include "AtlasShop.h" (edited)player_controller->GiveItem(&out_items, &fblueprint, default_amount, quality, force_blueprint,
false, 0);//bool GiveItem(FString * blueprintPath, int quantityOverride, float qualityOverride, bool bForceBlueprint) { return NativeCall<bool, FString *, int, float, bool>(this, "AShooterPlayerController.GiveItem", blueprintPath, quantityOverride, qualityOverride, bForceBlueprint); }
//bool GiveItem(FString * blueprintPath, int quantityOverride, float qualityOverride, bool bForceBlueprint) { return NativeCall<bool, FString *, int, float, bool>(this, "AShooterPlayerController.GiveItem", blueprintPath, quantityOverride, qualityOverride, bForceBlueprint); }Creating library ArkApi\Ark Server API\x64\Release\ArkApi.lib and object ArkApi\Ark Server API\x64\Release\ArkApi.exp
Requests.obj : error LNK2001: unresolved external symbol __imp_curl_multi_remove_handle
Requests.obj : error LNK2001: unresolved external symbol __imp_curl_multi_add_handle
Requests.obj : error LNK2001: unresolved external symbol __imp_curl_global_init
Requests.obj : error LNK2001: unresolved external symbol __imp_curl_multi_info_read
Requests.obj : error LNK2001: unresolved external symbol __imp_curl_global_cleanup
Requests.obj : error LNK2001: unresolved external symbol __imp_curl_easy_init
Requests.obj : error LNK2001: unresolved external symbol __imp_curl_multi_init
Requests.obj : error LNK2001: unresolved external symbol __imp_curl_easy_cleanup
Requests.obj : error LNK2001: unresolved external symbol __imp_curl_easy_setopt
Requests.obj : error LNK2001: unresolved external symbol __imp_curl_multi_perform
ArkApi\Ark Server API\x64\Release\version.dll : fatal error LNK1120: 10 unresolved externalslibcurl.lib(asyn-thread.obj) : warning LNK4099: PDB 'libcurl.pdb' was not found with 'libcurl.lib(asyn-thread.obj)' or at 'ArkApi\Ark Server API\x64\Ark\libcurl.pdb'; linking object as if no debug info
libcurl.lib(base64.obj) : warning LNK4099: PDB 'libcurl.pdb' was not found with 'libcurl.lib(base64.obj)' or at 'ArkApi\Ark Server API\x64\Ark\libcurl.pdb'; linking object as if no debug info
libcurl.lib(conncache.obj) : warning LNK4099: PDB 'libcurl.pdb' was not found with 'libcurl.lib(conncache.obj)' or at 'ArkApi\Ark Server API\x64\Ark\libcurl.pdb'; linking object as if no debug info
libcurl.lib(connect.obj) : warning LNK4099: PDB 'libcurl.pdb' was not found with 'libcurl.lib(connect.obj)' or at 'ArkApi\Ark Server API\x64\Ark\libcurl.pdb'; linking object as if no debug info
libcurl.lib(content_encoding.obj) : warning LNK4099: PDB 'libcurl.pdb' was not found with 'libcurl.lib(content_encoding.obj)' or at 'ArkApi\Ark Server API\x64\Ark\libcurl.pdb'; linking object as if no debug info
Should these be an issue?const auto& player_controllers = GetWorld()->PlayerControllerListField();
for (TWeakObjectPtr<APlayerController> player_controller : player_controllers)
{
AShooterPlayerController* shooter_pc = static_cast<AShooterPlayerController*>(player_controller.Get());
}player->ConsoleCommand(..)
How would I accomplish this using an RCON command method.
As in, I want to use a console command when I issue an rcon command in a plugin. (edited)world->GetFirstPlayerController()
and then you can call ConsoleCommand from him.auto player_controller = ArkApi::GetApiUtils().GetWorld()->GetFirstPlayerController();
player_controller->ConsoleCommand(&result, &fcommand, true);DECLARE_HOOK(AShooterGameMode_Logout, void, AShooterGameMode*, AController *); (edited)DECLARE_HOOK(AShooterGameMode_Logout, void, AShooterGameMode*, AController*);{"response":{"lender_steamid":"0"}}AShooterGameMode_HandleNewPlayervoid BanPlayer(FString PlayerSteamName) { NativeCall<void, FString>(this, "UShooterCheatManager.BanPlayer", PlayerSteamName); }DECLARE_HOOK(AShooterGameMode_HandleNewPlayer_Implementation, bool, AShooterGameMode*, AShooterPlayerController *, UPrimalPlayerData *, AShooterCharacter *, bool);ArkApi::GetApiUtils().GetShooterGameMode()->BannedMapField();
and every time you ban a player it automatically get saved const auto banned = ArkApi::GetApiUtils().GetShooterGameMode()->BannedMapField();
for (const auto currentEntry : banned)
{
if(currentEntry.Value == FString(steamId))
{
// Do something
}
}currentEntry.Key would be PlayerName
currentEntry.Value would be the SteamIdBannedMapFieldif (currentEntry.Value == FString(steamId))
{
// Do something
}{"response":{"lender_steamid":"0"}} nlohmann::json Json = Response;
if (int LenderSteamID; (LenderSteamID = Json["response"].value("lender_steamid", 0)) != 0)
{
//LenderSteamID
} (edited)FString URL = FString::Format("YourFullStringHere", steamId);FString URL = FString::Format("http://api.steampowered.com/IPlayerService/IsPlayingSharedGame/v0001/?key=whateversteamid={}&appid_playing=346110&format=json", steam_id);& missing between your key and the steamId parameter but yea ToString() function from FString URL.ToString() instead of putting a string with ToString() in it void GetCallback(bool Success, std::string Result)
{
Log::GetLog()->info("LenderSteamID: {}", Result);
}{"response":{"lender_steamid":"0"}}nlohmann::json Json = Result;
if (int LenderSteamID; (LenderSteamID = Json["response"].value("lender_steamid", 0)) != 0)
{
//LenderSteamID
}{
Log::GetLog()->info("LenderSteamID: {}", Result);
nlohmann::json Json = nlohmann::json::parse(Result);
if (int LenderSteamID; (LenderSteamID = Json["response"].value("lender_steamid", 0)) != 0)
{
//LenderSteamID
}
}
API::Requests::Get().CreateGetRequest("URL", &GetCallback);const auto banned = ArkApi::GetApiUtils().GetShooterGameMode()->BannedMapField(); and match it against the id we're obtaining from the steam api ?fmt::format("someurl.com?steamid={}", steamid") void GetCallback(bool Success, std::string Result)
{
Log::GetLog()->info("LenderSteamID: {}", Result);
nlohmann::json Json = nlohmann::json::parse(Result);
if (int LenderSteamID; (LenderSteamID = Json["response"].value("lender_steamid", 0)) != 0)
{
//LenderSteamID
}
}
API::Requests::Get().CreateGetRequest("fmt::format("http://api.steampowered.com/IPlayerService/IsPlayingSharedGame/v0001/?key=86B1steamid={}&appid_playing=346110&format=json", "steam_id")", &GetCallback); (edited)void GetCallback(bool Success, std::string Result)
{
Log::GetLog()->info("LenderSteamID: {}", Result);
nlohmann::json Json = nlohmann::json::parse(Result);
if (int LenderSteamID; (LenderSteamID = Json["response"].value("lender_steamid", 0)) != 0)
{
//LenderSteamID
}
}
API::Requests::Get().CreateGetRequest(fmt::format("http://api.steampowered.com/IPlayerService/IsPlayingSharedGame/v0001/?key=F2D86B1steamid={}&appid_playing=346110&format=json", "steam_id"), &GetCallback);
} (edited)const auto banned = ArkApi::GetApiUtils().GetShooterGameMode()->BannedMapField();for (auto& Elem : FruitMap)
{
FPlatformMisc::LocalPrint(
*FString::Printf(
TEXT("(%d, \"%s\")\n"),
Elem.Key,
*Elem.Value
)
);
}FruitMap to BannedMap will it work ? TEXT("(%d, \"%s\")\n"),bool bHas7 = FruitMap.Contains(7);
bool bHas8 = FruitMap.Contains(8);
// bHas7 == true
// bHas8 == false//Steam API Request
void GetCallback(bool Success, std::string Result)
API::Requests::Get().CreateGetRequest(fmt::format("http://api.steampowered.com/IPlayerService/IsPlayingSharedGame/v0001/?key=B1steamid={}&appid_playing=346110&format=json", steam_id), &GetCallback);{
void GetCallback(bool Success, std::string Result)
} API::Requests::Get().CreateGetRequest(fmt::format("http://api.steampowered.com/IPlayerService/IsPlayingSharedGame/v0001/?key=162F2D86B1steamid={}&appid_playing=346110&format=json", steam_id), &GetCallback);#include the headerProject Settings --> C/C++ --> General and called Additional Includedirectories (edited)#include "sqlite/sqlite_modern_cpp.h" (edited)ArkPluginLibrary.lib from? Even the whole Library?()() - I think you can figgure it out on your own ARKPluginLibray fix it first and then generate a static Library from it to later include it into your current projectvoid Hook_AShooterGameMode_StartNewShooterPlayer(AShooterGameMode* _this, APlayerController* new_player,
bool force_create_new_player_data, bool is_from_login,
FPrimalPlayerCharacterConfigStruct* char_config,
UPrimalPlayerData* ark_player_data) (edited) UShooterCheatManager* cheatManager = static_cast<UShooterCheatManager*>(OtherPlayer->CheatManagerField());
if (cheatManager)
{
} (edited)std::fstream file(config_path, fstream::out);
01/14/19 20:46 [ArkShop][error] (d:\programs\ark\plugins\arkshop\arkshop\private\points.cpp ArkShop::Points::GetPoints) Unexpected DB error not all rows extracted
01/14/19 20:51 [ArkShop][error] (d:\programs\ark\plugins\arkshop\arkshop\private\points.cpp ArkShop::Points::GetPoints) Unexpected DB error not all rows extracted
01/14/19 20:56 [ArkShop][error] (d:\programs\ark\plugins\arkshop\arkshop\private\points.cpp ArkShop::Points::GetPoints) Unexpected DB error not all rows extracted
01/14/19 21:17 [ArkShop][error] (d:\programs\ark\plugins\arkshop\arkshop\private\points.cpp ArkShop::Points::GetPoints) Unexpected DB error not all rows extracted
01/14/19 21:22 [ArkShop][error] (d:\programs\ark\plugins\arkshop\arkshop\private\points.cpp ArkShop::Points::GetPoints) Unexpected DB error not all rows extracted
01/14/19 21:27 [ArkShop][error] (d:\programs\ark\plugins\arkshop\arkshop\private\points.cpp ArkShop::Points::GetPoints) Unexpected DB error not all rows extracted
01/14/19 21:32 [ArkShop][error] (d:\programs\ark\plugins\arkshop\arkshop\private\points.cpp ArkShop::Points::GetPoints) Unexpected DB error not all rows extracted
01/14/19 21:37 [ArkShop][error] (d:\programs\ark\plugins\arkshop\arkshop\private\points.cpp ArkShop::Points::GetPoints) Unexpected DB error not all rows extractedERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TRANSACTION' at line 1ERROR 1064 (42000) at line 1: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'AUTOINCREMENT,
`SteamId` integer DEFAULT 0,
`Groups` text DEFAULT 'Default,' C' at line 2AUTO_INCREMENTERROR 1101 (42000) at line 1: BLOB, TEXT, GEOMETRY or JSON column 'Groups' can't have a default valueERROR 1273 (HY000) at line 1: Unknown collation: 'NOCASE' COLLATE NOCASEERROR 1062 (23000) at line 6: Duplicate entry '1' for key 'PRIMARY'`CREATE TABLE IF NOT EXISTS `Players` (`Id`integer NOT NULL PRIMARY KEY AUTO_INCREMENT,`SteamId`integer DEFAULT 0,`Groups`text);`
`CREATE TABLE IF NOT EXISTS `Groups` (`Id`integer NOT NULL PRIMARY KEY AUTO_INCREMENT,`GroupName`text NOT NULL,`Permissions` text);` (edited)CREATE TABLE command from your SQL file. It will work then DELETE FROM PermissionGroups WHERE Id = <ID OF YOUR GROUP> (edited) {
db_.execute(fmt::format("DELETE FROM PermissionGroups WHERE GroupName = '?';", group.ToString()));
}UPDATE Players SET PermissionGroups = '' WHERE PermissionGroups LIKE "%<YOURGROUP>%";
Though it's not 100% perfect. if some has the group and something else they will loose the other groups. But i yeah it's something that could be for use.bool Hook_APrimalDinoCharacter_CancelCurrentAttack(APrimalDinoCharacter* _this, bool bStopCurrentAttackAnim, float AttackAnimBlendOutTime, AController* EventInstigator, AShooterPlayerController* player_controller)bool Hook_APrimalDinoCharacter_CancelCurrentAttack(APrimalDinoCharacter* _this, bool bStopCurrentAttackAnim, float AttackAnimBlendOutTime)DECLARE_HOOK(APrimalDinoCharacter_CancelCurrentAttack, bool, APrimalDinoCharacter*, bool, float);
bool Hook_APrimalDinoCharacter_CancelCurrentAttack(APrimalDinoCharacter* _this, bool bStopCurrentAttackAnim, float AttackAnimBlendOutTime)
{
return APrimalDinoCharacter_CancelCurrentAttack_original(_this, bStopCurrentAttackAnim, AttackAnimBlendOutTime);
}
ArkApi::GetHooks().SetHook("APrimalDinoCharacter.CancelCurrentAttack", &Hook_APrimalDinoCharacter_CancelCurrentAttack, &APrimalDinoCharacter_CancelCurrentAttack_original);
ArkApi::GetHooks().DisableHook("APrimalDinoCharacter.CancelCurrentAttack", &Hook_APrimalDinoCharacter_CancelCurrentAttack);DECLARE_HOOK(APrimalDinoCharacter_CanAttack, bool, APrimalDinoCharacter*, int);DECLARE_HOOK(APrimalDinoCharacter_DoAttack, bool, APrimalDinoCharacter*, int, bool, bool); ?bool Hook_APrimalDinoCharacter_DoAttack(APrimalDinoCharacter* _this, int AttackIndex, bool bSetCurrentAttack, bool bInterruptCurrentAttack)bool Hook_APrimalDinoCharacter_DoAttack(APrimalDinoCharacter* _this, int AttackIndex, bool bSetCurrentAttack, bool bInterruptCurrentAttack)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;
}
}bool IsEnemyStructureNear(AShooterPlayerController* player_controller, int radius)
{
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;
}std::string apiKey = config["APIKey"];
API::Requests::Get().CreateGetRequest(fmt::format("http://api.steampowered.com/IPlayerService/IsPlayingSharedGame/v0001/?key={}&steamid={}&appid_playing=346110&format=json",
apiKey, steamId), std::function<void > & isPlayingSharedGame); i have something like this but i'm retarded and cant get it to workbool CreateGetRequest(const std::string& url, const std::function<void(bool, std::string)>& callback);Api::Requests::CreateGetRequest(std::string& url, const std::function<void(bool, std::string)>& isPlayingSharedGame);API::Requests::Get().CreateGetRequest(fmt::format(
"http://api.steampowered.com/IPlayerService/IsPlayingSharedGame/v0001/?key={}&steamid={}&appid_playing=346110&format=json",
apiKey, steamId), std::bind(& isPlayingSharedGame);bool CreateGetRequest(const std::string& url, const std::function<void(bool, std::string)>& callback);API::Requests::Get().CreateGetRequest(std::string& url, const std::function<void(bool, std::string)>& isPlayingSharedGame);Request.h but thats the updated code:void Hook_AShooterGameMode_PreLogin(AShooterGameMode* _this, FString* Options, FString* Address,
TSharedPtr<FUniqueNetId, 0>* UniqueId, FString* authToken, FString* ErrorMessage)
{
const uint64 steamId = static_cast<FUniqueNetIdSteam*>(UniqueId->Get())->UniqueNetId;
std::string apiKey = config["APIKey"];
FString url = FString::Format(
"http://api.steampowered.com/IPlayerService/IsPlayingSharedGame/v0001/?key={}&steamid={}&appid_playing=346110&format=json",
apiKey, steamId);
API::Requests::Get().CreateGetRequest(url.ToString(), [steamId](bool success, std::string response)
{
isPlayingSharedGame(success, response, steamId);
});
AShooterGameMode_PreLogin_original(_this, Options, Address, UniqueId, authToken, ErrorMessage);
}void isPlayingSharedGame(bool success, std::string response, uint64 steamId)
{
if (success)
{
if (!response.empty() && !response.find("Forbidden"))
{
nlohmann::json parsedResponse = nlohmann::json::parse(response);
const uint64 lenderSteamId = std::stoull(
static_cast<std::string>(parsedResponse["response"]["lender_steamid"]), nullptr);
if (lenderSteamId != 0)
{
if (!VectorContains(steamId))
{
familysharing.push_back(steamId);
}
}
}
else
{
Log::GetLog()->warn("Please check your config for a valid API Key");
}
}
else
{
Log::GetLog()->warn("API Limit reached(100.000 per 24h) / Steam API down");
}
}3.0 brought us a new library called CURL (you might know it from linux).. ofc the usage of the library is differentARK-Server-API-master\out_lib
float Hook_APrimalDinoCharacter_TakeDamage(APrimalDinoCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
ACharacter* character = EventInstigator->CharacterField();
const int enemy_min_distance = AntiFireBreath::config["General"]["EnemyStructureMinDistance"];
if (character != nullptr && character && character->IsA(APrimalDinoCharacter::GetPrivateStaticClass()))
{
APrimalDinoCharacter* dino = static_cast<APrimalDinoCharacter*>(character);
FString descr;
dino->GetDinoDescriptiveName(&descr);
if (descr.Contains(L"Dragon")
|| descr.Contains(L"Raphus")
|| descr.Contains(L"Primordius"))
return 0;
}
return APrimalDinoCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}{
return APrimalDinoCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}if(something){----this is a block---}if (EventInstigator && EventInstigator->CharacterField())
{
ACharacter* character = EventInstigator->CharacterField();
if (character != nullptr && character && character->IsA(APrimalDinoCharacter::GetPrivateStaticClass()))
{
APrimalDinoCharacter* dino = static_cast<APrimalDinoCharacter*>(character);
FString descr;
dino->GetDinoDescriptiveName(&descr);
if (descr.Contains(L"Direwolf")
|| descr.Contains(L"Wyvern")
|| descr.Contains(L"Broodmother"))
{
UWorld* world = ArkApi::GetApiUtils().GetWorld();
TArray<AActor*> new_actors;
TArray<AActor*> actors_ignore;
TArray<TEnumAsByte<enum EObjectTypeQuery>> types;
UKismetSystemLibrary::SphereOverlapActors_NEW(world, EventInstigator->RootComponentField()->RelativeLocationField(),
static_cast<float>((AntiFireBreath::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())
{
return 0;
}
else
{
return APrimalDinoCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}
}
}
}
}if (structure->TargetingTeamField() !=EventInstigator->TargetingTeamField())1>dllmain.cpp
1>d:\wf\arkmodding\ark-server-api\version\core\public\api\ue\windows\windowsplatformatomics.h(24): error C2039: '_InterlockedIncrement64': is not a member of '`global namespace''
1>d:\wf\arkmodding\ark-server-api\version\core\public\api\ue\windows\windowsplatformatomics.h(24): error C3861: '_InterlockedIncrement64': identifier not found
1>d:\wf\arkmodding\ark-server-api\version\core\public\api\ue\windows\windowsplatformatomics.h(48): error C2039: '_InterlockedDecrement64': is not a member of '`global namespace''
1>d:\wf\arkmodding\ark-server-api\version\core\public\api\ue\windows\windowsplatformatomics.h(48): error C3861: '_InterlockedDecrement64': identifier not found
1>d:\wf\arkmodding\ark-server-api\version\core\public\api\ue\windows\windowsplatformatomics.h(72): error C2039: '_InterlockedExchangeAdd64': is not a member of '`global namespace''
1>d:\wf\arkmodding\ark-server-api\version\core\public\api\ue\windows\windowsplatformatomics.h(72): error C3861: '_InterlockedExchangeAdd64': identifier not found
1>d:\wf\arkmodding\ark-server-api\version\core\public\api\ue\windows\windowsplatformatomics.h(95): error C2039: '_InterlockedExchange64': is not a member of '`global namespace''
1>d:\wf\arkmodding\ark-server-api\version\core\public\api\ue\windows\windowsplatformatomics.h(95): error C3861: '_InterlockedExchange64': identifier not found
1>d:\wf\arkmodding\ark-server-api\version\core\public\api\ue\windows\windowsplatformatomics.h(112): error C2039: '_InterlockedExchange64': is not a member of '`global namespace''
1>d:\wf\arkmodding\ark-server-api\version\core\public\api\ue\windows\windowsplatformatomics.h(112): error C3861: '_InterlockedExchange64': identifier not foundif (_this->TargetingTeamField() > 10000 && character != nullptr && character && character->IsA(APrimalDinoCharacter::GetPrivateStaticClass())) ?if (EventInstigator && EventInstigator->CharacterField())
{
//Do the things
}
return original; //if EventInstigator = NULLif (EventInstigator=nullptr)
{
return APrimalDinoCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}==if (!EventInstigator)if (EventInstigator && EventInstigator->CharacterField())
{
//Do the things
}
return APrimalDinoCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);GetDamageInstigator(AController * InstigatedBy, UDamageType * DamageType) char& CurrentAttackIndexField() { return *GetNativePointerField<char*>(this, "APrimalDinoCharacter.CurrentAttackIndex"); }
char& LastAttackIndexField() { return *GetNativePointerField<char*>(this, "APrimalDinoCharacter.LastAttackIndex"); } (edited) "Id INT NOT NULL AUTO_INCREMENT,"
"SteamId BIGINT(11) NOT NULL DEFAULT 0,"
"Kits VARCHAR(256) NOT NULL DEFAULT '{}',"
"Points INT DEFAULT 0,"
"TotalSpent INT DEFAULT 0,"
"PRIMARY KEY(Id),"
"UNIQUE INDEX SteamId_UNIQUE (SteamId ASC)); ");CREATE TABLE IF NOT EXISTS ArkShopPlayers ("
"Id INT NOT NULL AUTO_INCREMENT,"
"SteamId BIGINT(11) NOT NULL DEFAULT 0,"
"Kits VARCHAR(256) NOT NULL DEFAULT '{}',"
"Points INT DEFAULT 0,"
"TotalSpent INT DEFAULT 0,"
"PRIMARY KEY(Id),"
"UNIQUE INDEX SteamId_UNIQUE (SteamId ASC));struct APrimalRaft : APrimalDinoCharacter
{
// Functions
bool IsAnchored() { return NativeCall<bool>(this, "APrimalRaft.IsAnchored"); }
static UClass * GetPrivateStaticClass() { return NativeCall<UClass *>(nullptr, "APrimalRaft.GetPrivateStaticClass"); }
static UClass * StaticClass() { return NativeCall<UClass *>(nullptr, "APrimalRaft.StaticClass"); }
};APrimalRaft to your config.json of your APIAPrimalRaft too (edited)IsInLandClaimedFlagRadius
GetLandClaim
From APrimalStructureClaimFlag might help youPlayerData[player->LinkedPlayerIDField()].NextVoteTime[VoteSiteIndex] = nNow + 30;VERSION: 15.67
ShooterGameServer.exe!compress2() (0x00007ff7f61b100b) + 0 bytes [UnknownFile:0]
ParkedShipProtection.dll!UnknownFunction (0x00007ffcfea88e2c) + 0 bytes [UnknownFile:0]
ShooterGameServer.exe!UGameplayStatics::ApplyDamage() (0x00007ff7f7755d9d) + 0 bytes [h:\yarkupdatelivereal\engine\source\runtime\engine\private\gameplaystatics.cpp:393]
ShooterGameServer.exe!APrimalStructureShipHull::ApplyPlankDecayDamageInterval() (0x00007ff7f66def25) + 0 bytes [h:\yarkupdatelivereal\projects\shootergame\source\shootergame\private\primalstructureshiphull.cpp:195]
ShooterGameServer.exe!APrimalStructureShipHull::TickHull() (0x00007ff7f66e86d2) + 0 bytes [h:\yarkupdatelivereal\projects\shootergame\source\shootergame\private\primalstructureshiphull.cpp:1250]
ShooterGameServer.exe!APrimalRaft::Tick() (0x00007ff7f6622fd8) + 0 bytes [h:\yarkupdatelivereal\projects\shootergame\source\shootergame\private\primalraft.cpp:855]
ShooterGameServer.exe!AActor::TickActor() (0x00007ff7f76acbbe) + 0 bytes [h:\yarkupdatelivereal\engine\source\runtime\engine\private\actor.cpp:775]
ShooterGameServer.exe!FActorTickFunction::ExecuteTick() (0x00007ff7f7693d7a) + 27 bytes [h:\yarkupdatelivereal\engine\source\runtime\engine\private\actor.cpp:150]
ShooterGameServer.exe!FTickTaskManager::StartFrame() (0x00007ff7f7940383) + 41 bytes [h:\yarkupdatelivereal\engine\source\runtime\engine\private\ticktaskmanager.cpp:871]
ShooterGameServer.exe!UWorld::Tick() (0x00007ff7f77e3595) + 24 bytes [h:\yarkupdatelivereal\engine\source\runtime\engine\private\leveltick.cpp:1209]
ShooterGameServer.exe!UGameEngine::Tick() (0x00007ff7f77846c2) + 0 bytes [h:\yarkupdatelivereal\engine\source\runtime\engine\private\gameengine.cpp:1181]NewPlayer->God 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(),
10000, &types, APrimalStructureClaimFlag::GetPrivateStaticClass(), &actors_ignore, &new_actors); UKismetSystemLibrary::SphereOverlapActors_NEW(world, _this->RootComponentField()->RelativeLocationField(),float Hook_APrimalDinoCharacter_TakeDamage(APrimalDinoCharacter* _this, float Damage, FDamageEvent* DamageEvent,
AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsShip())
{
//check for Friendly Claim Flags 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(),
10000, &types, APrimalStructureClaimFlag::GetPrivateStaticClass(), &actors_ignore, &new_actors);
for (const auto& actor : new_actors)
{
APrimalStructureClaimFlag* claimFlag = static_cast<APrimalStructureClaimFlag*>(actor);
//Log::GetLog()->warn(FVector::Distance(_this->RootComponentField()->RelativeLocationField(), actor->RootComponentField()->RelativeLocationField()));
if (claimFlag->TargetingTeamField() == _this->TargetingTeamField())
{
if (FVector::Distance(_this->RootComponentField()->RelativeLocationField(), claimFlag->RootComponentField()->RelativeLocationField()) <= claimFlag->LandClaimRadiusField())
{
return APrimalDinoCharacter_TakeDamage_original(_this, 0, DamageEvent, EventInstigator, DamageCauser);
}
}
}
}
return APrimalDinoCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
} (edited)RelativeLocationField is also not null? APrimalStructureClaimFlag::GetPrivateStaticClass();if (_this->GetAttachedToShip())
{
if (_this->GetAttachedToShip()->IsAnchored())
{_this->GetAttachedToShip()->IsAnchored()Sorry for marking it as spoiler - wanted to try out this feature.. lol
As you can see the function doesn't seems to be corrupted :D
void debugCommand(AShooterPlayerController* sender, FString* message, EChatSendMode::Type)
{
TArray<AActor*> actorsInSphere;
TArray<AActor*> actors_ignore;
TArray<TEnumAsByte<enum EObjectTypeQuery>> types;
UKismetSystemLibrary::SphereOverlapActors_NEW(ArkApi::GetApiUtils().GetWorld(), sender->DefaultActorLocationField(), 1000,
&types, nullptr, &actors_ignore, &actorsInSphere);
for(AActor* current: actorsInSphere)
{
if(current->IsA(APrimalRaft::StaticClass()))
{
ArkApi::GetApiUtils().SendChatMessageToAll("DEBUG", "Found a ship!");
auto* ship = static_cast<APrimalRaft*>(current);
if(ship && ship->IsAnchored())
{
ArkApi::GetApiUtils().SendChatMessageToAll("DEBUG", "which is anchored!");
}
}
}
} (edited)struct APrimalRaft : APrimalDinoCharacter
{
static UClass * StaticClass() { return NativeCall<UClass *>(nullptr, "APrimalRaft.StaticClass"); }
bool IsAnchored() { return NativeCall<bool>(this, "APrimalRaft.IsAnchored"); }
};"APrimalRaft", to your config.json located in Win64 folder#include <Api/Atlas/Atlas.h>
#pragma comment(lib, "AtlasApi.lib")
DECLARE_HOOK(APrimalStructure_TakeDamage, float, APrimalStructure*, float, FDamageEvent*, AController*, AActor*);
struct APrimalRaft : APrimalDinoCharacter
{
// Functions
bool IsAnchored() { return NativeCall<bool>(this, "APrimalRaft.IsAnchored"); }
static UClass * GetPrivateStaticClass() { return NativeCall<UClass *>(nullptr, "APrimalRaft.GetPrivateStaticClass"); }
static UClass * StaticClass() { return NativeCall<UClass *>(nullptr, "APrimalRaft.StaticClass"); }
};
float Hook_APrimalStructure_TakeDamage(APrimalStructure* _this, float Damage, FDamageEvent* DamageEvent,
AController* EventInstigator, AActor* DamageCauser)
{
if (_this->GetAttachedToShip())
{
if(_this->GetAttachedToShip()->IsAnchored())
{
FString descr;
_this->GetHumanReadableName(&descr);
if (descr.Contains(L"plank") || descr.Contains(L"deck") || descr.Contains(L"hull"))
{
Log::GetLog()->warn("{}", descr.ToString());
Log::GetLog()->warn("{} took no damage!", descr.ToString());
return APrimalStructure_TakeDamage_original(_this, 0, DamageEvent, EventInstigator, DamageCauser);
}
}
}
return APrimalStructure_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
} (edited)void Load()
{
Log::Get().Init("ParkedShipProtection");
ArkApi::GetHooks().SetHook("APrimalStructure.TakeDamage", &Hook_APrimalStructure_TakeDamage,
&APrimalStructure_TakeDamage_original);
}
void Unload()
{
ArkApi::GetHooks().DisableHook("APrimalStructure.TakeDamage", &Hook_APrimalStructure_TakeDamage);
}
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;
} (edited) if(_this->GetAttachedToShip()->IsAnchored())
IsAttachedToShipInWetDock() IsAttachedToShipInDryDock() Anyone know the difference in a wet and dry dock?{
"APIKey": "Censored",
"KickMessage": "Family Shared Accounts Are Not Allowed on DopeArk, Please Connect With A Different Account!",
"Whitelist": []
}APrimalCharacter::IsConscious() might help void AutoKill(AShooterPlayerController* AttackerShooterController, FString* message, int mode)
{
if (!AttackerShooterController || !AttackerShooterController->PlayerStateField() || !AttackerShooterController->GetPlayerCharacter() || AttackerShooterController->GetPlayerCharacter()->IsDead() || !AttackerShooterController->GetPlayerCharacter()->IsConscious() || 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"Handcuffs")) return;
}
if (!ArkApi::GetApiUtils().IsRidingDino(AttackerShooterController)) AttackerShooterController->GetPlayerCharacter()->Suicide();
}if (!ArkApi::GetApiUtils().IsRidingDino(AttackerShooterController)) AttackerShooterController->GetPlayerCharacter()->Suicide();AttackerShooterController->GetPlayerCharacter()->Suicide();
if (EventInstigator && EventInstigator->CharacterField())
{
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 (_this->IsA(APlayerController::StaticClass()) && WeaponName.Contains(L"Armor Piercing"));
return Damage * 0.10;
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (EventInstigator && EventInstigator->CharacterField())
{
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 (_this->IsA(APlayerController::StaticClass()) && WeaponName.Contains(L"Armor Piercing"));
Damage = Damage * 0.10;
}return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}
}_this->IsA(APlayerController::StaticClass())float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (EventInstigator && _this->IsA(APlayerController::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"Armor Piercing"));
Log::GetLog()->warn("Weapon Name: {}", WeaponName.ToString());
Damage = Damage * 0.10;
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}GetOwnerControllerif (_this->GetOwnerController && WeaponName.Contains(L"Armor Piercing"));_this does not have anything in common with EventInstigator besides that event.. _this->GetOwnerController what arguments should i provide for thisc:\users\avtoj\source\repos\apbalancer\apbalancer\apbalancer.cpp(23): warning C4551: function call missing argument list (edited) // RCONCommand
int RCONRolls = LootBoxes::config["LootBoxes"][lootbox->ToString()]["RCONCommands"]["Count"];
for (int i = 0; i < RCONRolls; i++) {
const nlohmann::json itemArray = LootBoxes::config["LootBoxes"][lootbox->ToString()];
auto itemIter = itemArray.find("RCONCommands");
const nlohmann::basic_json<> item = itemIter.value();
auto possibleCommands = item.value("PossibleCommands", nlohmann::json::array());
int size = possibleCommands.size();
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> rand(0, size - 1);
nlohmann::json selectedCommand = possibleCommands.at(rand(eng));
std::string command = selectedCommand["Command"];
int MinPointsShop = selectedCommand["MinPointShop"];
int MaxPointsShop = selectedCommand["MaxPointShop"];
std::uniform_int_distribution<> points(MinPointsShop, MaxPointsShop);
int shoppoints = points(eng);
uint64 steamId = ArkApi::GetApiUtils().GetSteamIdFromController(sender);
// Use the ArkShop API to add points
ArkShop::Points::AddPoints(shoppoints, steamId);
} std::string command = selectedCommand["Command"];
int MinPointsShop = selectedCommand["MinPointShop"];
int MaxPointsShop = selectedCommand["MaxPointShop"];
std::uniform_int_distribution<> points(MinPointsShop, MaxPointsShop);
int shoppoints = points(eng);
uint64 steamId = ArkApi::GetApiUtils().GetSteamIdFromController(sender);
// Use the ArkShop API to add points
ArkShop::Points::AddPoints(shoppoints, steamId); 
DECLARE_HOOK(AShooterGameMode_Logout, void, AShooterGameMode*, AController *);
DECLARE_HOOK(AShooterGameMode_PostLogin, void, AShooterGameMode*, APlayerController *);
Can i use these hooks for detect player entering/leaving the game?GetOwnerController ? (edited)float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (EventInstigator && EventInstigator->CharacterField())
{
AShooterPlayerController* AttackerShooterController = static_cast<AShooterPlayerController*>(EventInstigator);
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
APlayerController descr;
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
if (_this->IsA(AShooterPlayerController::GetPrivateStaticClass()) && WeaponName.Contains(L"Armor Piercing"));
Log::GetLog()->warn("Weapon Name: {}", WeaponName.ToString());
Damage = Damage * 0.10;
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (EventInstigator && EventInstigator->CharacterField())
{
AShooterPlayerController* AttackerShooterController = static_cast<AShooterPlayerController*>(EventInstigator);
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
APlayerController descr;
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
if (_this->IsA(AShooterPlayerController::GetPrivateStaticClass()) && WeaponName.Contains(L"Armor Piercing"));
{
Log::GetLog()->warn("Weapon Name: {}", WeaponName.ToString());
Damage = Damage * 0.10;
}
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (EventInstigator && EventInstigator->CharacterField())
{
AShooterPlayerController* AttackerShooterController = static_cast<AShooterPlayerController*>(EventInstigator);
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
APlayerController descr;
FString WeaponName;
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
if (_this->IsA(AShooterPlayerController::GetPrivateStaticClass()) && WeaponName.Contains(L"Armor Piercing"))
{
Log::GetLog()->warn("Weapon Name: {}", WeaponName.ToString());
Damage = Damage * 0.10;
}
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}virtual modifier internally I guess float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (EventInstigator && EventInstigator->CharacterField())
{
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 (_this->IsA(AShooterPlayerController::GetPrivateStaticClass()) && WeaponName.Contains(L"Armor Piercing"))
{
Log::GetLog()->warn("Weapon Name: {}", WeaponName.ToString());
Damage = Damage * 0.10;
}
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}_this->IsA(AShooterPlayerController::GetPrivateStaticClass()) (edited)if (_this->IsA(APrimalDinoCharacter::GetPrivateStaticClass()) && _this->TargetingTeamField() == 0)_this->IsA(APrimalDinoCharacter::GetPrivateStaticClass()) && _this->TargetingTeamField() < 10000if (_this != nullptr && WeaponName.Contains(L"Sword") != WeaponName.Contains(L"Tek Sword"))dino->bUseBPDoHarvestAttack()()dino->bUseBPDoHarvestAttack()() will just return if a dino can use a harvest attack. It's not a hook on a functionAPrimalDinoCharacter->DoAttack() function and see if AttackIndex changes based on which attack is used.APrimalDinoCharacter* _this,bool Hook_APrimalDinoCharacter_DoAttack(APrimalDinoCharacter* _this, int AttackIndex, bool bSetCurrentAttack, bool bInterruptCurrentAttack)Log::GetLog()->warn("Attack Index: {}", AttackIndex); (edited)float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()))
{
if (!_this->IsDead() && !_this->IsConscious() && _this != nullptr)
{
_this->Suicide();
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}bool meetsrequirements;
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()) && _this != nullptr)
{
if (!_this->IsDead() && !_this->IsConscious())
{
meetsrequirements = true;
}
else
{
meetsrequirements = false;
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}
void AutoKill(AShooterPlayerController* AttackerShooterController, FString* message, int mode)
{
if (meetsrequirements=true) AttackerShooterController->GetPlayerCharacter()->Suicide();
}if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()) && _this != nullptr)
{
if (!_this->IsDead() && !_this->IsConscious())
{
API::Timer::Get().DelayExecute(&_this->Suicide, 10);
}
}>c:\users\avtoj\source\repos\autokill\autokill\autokill.cpp(15): error C3083: 'Timer': the symbol to the left of a '::' must be a type
1>c:\users\avtoj\source\repos\autokill\autokill\autokill.cpp(15): error C2039: 'Get': is not a member of 'API'
1>c:\users\avtoj\desktop\arkserver\ark-server-api-master\version\core\public\tools.h(36): note: see declaration of 'API'
1>c:\users\avtoj\source\repos\autokill\autokill\autokill.cpp(15): error C3861: 'Get': identifier not found
1>c:\users\avtoj\source\repos\autokill\autokill\autokill.cpp(15): error C2276: '&': illegal operation on bound member function expressionvoid TimerCallBack(int arg1, int arg2)
{
Log::GetLog()->info("CallBack Executed Args: {}, {}", arg1, arg2);
}void TimerCallBack(int arg1, int arg2)float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()) && _this != nullptr)
{
if (!_this->IsDead() && !_this->IsConscious())
{
API::Timer::Get().DelayExecute(&TimerCallBack, 10);
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}
void TimerCallBack(APrimalCharacter* _this)
{
_this->Suicide();
}c:\users\avtoj\desktop\arkserver\ark-server-api-master\version\core\public\timer.h(31): error C2664: 'void API::Timer::DelayExecuteInternal(const std::function<void (void)> &,int)': cannot convert argument 1 from 'std::_Binder<std::_Unforced,void (__cdecl *const &)(APrimalCharacter *)>' to 'const std::function<void (void)> &'
1>c:\users\avtoj\desktop\arkserver\ark-server-api-master\version\core\public\timer.h(30): note: Reason: cannot convert from 'std::_Binder<std::_Unforced,void (__cdecl *const &)(APrimalCharacter *)>' to 'const std::function<void (void)>'
1>c:\users\avtoj\desktop\arkserver\ark-server-api-master\version\core\public\timer.h(30): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>c:\users\avtoj\source\repos\autokill\autokill\autokill.cpp(19): note: see reference to function template instantiation 'void API::Timer::DelayExecute<void(__cdecl *)(APrimalCharacter *),>(const Func &,int)' being compiledvoid TimerCallBack(APrimalCharacter* _this)
{
_this->Suicide();
}
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()) && _this != nullptr)
{
if (!_this->IsDead() && !_this->IsConscious())
{
API::Timer::Get().DelayExecute(&TimerCallBack, 10);
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}void TimerCallBack(APrimalCharacter* _this)
{
_this->Suicide();
}
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()) && _this != nullptr)
{
if (!_this->IsDead() && !_this->IsConscious())
{
API::Timer::Get().DelayExecute(&TimerCallBack, 10,_this);
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}TeamSelector.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) bool __cdecl Permissions::IsPlayerInGroup(unsigned __int64,class FString const &)" (__imp_?IsPlayerInGroup@Permissions@@YA_N_KAEBVFString@@@Z)
1>TeamSelector.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) class std::optional<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > __cdecl Permissions::AddPlayerToGroup(unsigned __int64,class FString const &)" (__imp_?AddPlayerToGroup@Permissions@@YA?AV?$optional@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@std@@_KAEBVFString@@@Z)
1>C:\Users\avtoj\source\repos\TeamSelector\x64\Release\TeamSelector.dll : fatal error LNK1120: 2 unresolved externalsTeamSelector.obj : error LNK2001: unresolved external symbol "class FString __cdecl TeamSelector::GetText(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?GetText@TeamSelector@@YA?AVFString@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
1>C:\Users\avtoj\source\repos\TeamSelector\x64\Release\TeamSelector.dll : fatal error LNK1120: 1 unresolved externalsvoid Broadcaster::StartBroadcasting()
{
m_is_working = true;
m_thread.reset(new std::thread(&Broadcaster::m_InternalFunc, this)); // Stucks here
}
This code is works well in other console projectLog::GetLog()->info("Before start timer"); // This executes
API::Timer::Get().RecurringExecute([]() {
Log::GetLog()->info("Entering into timer func"); // This doesn't execute
if(shutdown_process == true)
{
return;
}
TArray<uint64> players = database->GetPlayerIDs();
Log::GetLog()->info("After request to DB");
TArray<Rank> ranks = config.BuildRankList();
for(const auto steam_id : players)
{
if(auto* player_controller = ArkApi::GetApiUtils().FindPlayerFromSteamId(steam_id); player_controller != nullptr)
{
TArray<FString> player_groups = Permissions::GetPlayerGroups(steam_id);
uint64 total_play_time = (realtime_cache->GetPlayTime(steam_id) + database->GetPlayTime(steam_id)) / 60;
for(const auto& rank : ranks)
{
if(total_play_time >= rank.cost && !player_groups.Contains(FString(rank.name.c_str())))
{
ArkApi::GetApiUtils().SendChatMessage(player_controller, config.GetMessageText("Sender"), *config.GetMessageText("BroadcastMessage"));
break;
}
}
}
}
}, config.GetBroadcastInterval(), -1, true);
database it's wrapper for daotk::mysql::connection protected by mutex
realtime_cache it's simple storage for online players. Also protected by mutex
Nothing executes here and plugin loading stops. If i comment RecurringExecute then works fine.inline uint64 GetBroadcastInterval() const
{
std::lock_guard<std::mutex> guard(m_mutex);
return (static_cast<uint64>(m_config["General"]["BroadcastInterval"]) * static_cast<uint64>(60));
}std::cout << (static_cast<unsigned long long>(config["General"]["BroadcastInterval"]) * static_cast<unsigned long long>(60)) << std::endl;std::cout << (static_cast<unsigned long long>(config["General"]["BroadcastInterval"]) * static_cast<unsigned long long>(60)) << std::endl;
RecurringExecute, of course, in the gamevoid TimerCallBack(APrimalCharacter* _this)
{
_this->Suicide();
}
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()) && _this != nullptr)
{
if (!_this->IsDead() && !_this->IsConscious())
{
API::Timer::Get().DelayExecute(&TimerCallBack, 10,_this);
}
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}
1APrimalStructureClaimFlag::GetPrivateStaticClass() sometimes causes the server to crash I agree - but not any time. Have you added the APrimalStructureClaimFlag to your config.json of the API?StaticClassFieldvoid TimerCallBack(APrimalCharacter* _this, AShooterPlayerController * target)
{
while (!_this->IsConscious() && !_this->IsDead())
{
AShooterPlayerController* AttackerShooterController = static_cast<AShooterPlayerController*>(target);
AShooterPlayerController* player = (AShooterPlayerController*)target;
uint64 steamId = ArkApi::GetApiUtils().GetSteamIdFromController(player);
player->GetPlayerCharacter()->Suicide();
}
} (edited)float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
AShooterPlayerController* target = _this->GetCharacterController();
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()) && _this != nullptr)
{
API::Timer::Get().DelayExecute(&TimerCallBack, 10, _this, target);
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}loat Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()) && _this != nullptr)
if(!_this->IsConscious() && !_this->IsDead())
{
_this -> Suicide();
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
} (edited)float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()) && _this != nullptr)
{
if (!_this->IsConscious() && !_this->IsDead)
{
_this->Suicide();
}
}return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}bool suicide;
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()) && _this != nullptr)
{
if (!_this->IsConscious() && !_this->IsDead())
{
_this->Suicide();
suicide = true;
}
else
{
suicide = false;
}
}
if (suicide == false)
{
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}
}bool suicide;
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this != nullptr)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()))
{
if (!_this->IsConscious() && !_this->IsDead())
{
_this->Suicide();
suicide = true;
}
else
{
suicide = false;
}
}
}
if (suicide == false)
{
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}
}int Hook_APrimalStructure_IsAllowedToBuild(APrimalStructure* _this, APlayerController* PC, FVector AtLocation, FRotator AtRotation, FPlacementData* OutPlacementData, bool bDontAdjustForMaxRange, FRotator PlayerViewRotation, bool bFinalPlacement)
{
const FString path_name = GetBlueprint(_this);
if (bFinalPlacement && PC != nullptr)
{
if (path_name.ToString() == "Blueprint'/Game/PrimalEarth/CoreBlueprints/Items/Structures/Pipes/PrimalItemStructure_StonePipeIntake'")
{
return 211;
}
}
return APrimalStructure_IsAllowedToBuild_original(_this, PC, AtLocation, AtRotation, OutPlacementData,
bDontAdjustForMaxRange, PlayerViewRotation, bFinalPlacement);
}AllowIntakeToPlaceWithoutWater=true[StructuresPlus] in gameusersettings.ini
1Severity Code Description Project File Line Suppression State
Error C2039 '_snprintf': is not a member of 'std' LootBoxes c:\users\avtoj\desktop\arkserver\ark-server-api-master\version\core\public\json.hpp 11146 if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F))) {
if (codepoint <= 0xFFFF) {
std::snprintf(string_buffer.data() + bytes, 7, "\\u%04x",
static_cast<uint16_t>(codepoint));
bytes += 6;
}
else {
std::snprintf(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)),
static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF)));
bytes += 12;
}
}
to
if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F))) {
if (codepoint <= 0xFFFF) {
snprintf(string_buffer.data() + bytes, 7, "\\u%04x",
static_cast<uint16_t>(codepoint));
bytes += 6;
}
else {
snprintf(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)),
static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF)));
bytes += 12;
}
} (edited)#include "json.hpp"{
"FullName":"PluginName",
"Description":"Does things",
"Version":1.0,
"MinApiVersion":1.0,
"Dependencies": [
"ArkShop"
]
}OriginBegone.dll is that your plugin? (edited)03/06/19 08:01 [ShopRewards][warning] Event Manager Detected - Disabling Player rewards for people in EventManager!std::string getHWID() {
HW_PROFILE_INFO hwProfileInfo;
std::string hwid;
Log::GetLog()->error("getting hwid");
if (GetCurrentHwProfile(&hwProfileInfo)) {
//Fhwid = hwProfileInfo.szHwProfileGuid;
std::wstring Whwid(hwProfileInfo.szHwProfileGuid);
// your new String
std::string Shwid(Whwid.begin(), Whwid.end());
hwid = Shwid;
}
else
hwid = "ERROR_CANT_RETRIEVE_HWID_VALUES"; //intentionally longer than the column allows - see if this is breakable or ok
//make sure field in logging table allows for longer length to record these instances- LEN is 31 so go with 32
hwid.erase(std::remove(hwid.begin(), hwid.end(), '{'), hwid.end());
hwid.erase(std::remove(hwid.begin(), hwid.end(), '}'), hwid.end());
hwid.erase(std::remove(hwid.begin(), hwid.end(), '-'), hwid.end());
std::transform(hwid.begin(), hwid.end(), hwid.begin(), ::toupper);
Log::GetLog()->error("returning hwid >" + hwid + "<");
return hwid;
}#include <windows.h>
#include <stdio.h>...
{
getHWID();
...
use
...
{
std::string currenthwid = getHWID();
...void Unload();
std::string getHWID()
{
HW_PROFILE_INFO hwProfileInfo;
std::string hwid;
Log::GetLog()->error("getting hwid");
if (GetCurrentHwProfile(&hwProfileInfo)) {
//Fhwid = hwProfileInfo.szHwProfileGuid;
std::wstring Whwid(hwProfileInfo.szHwProfileGuid);
// your new String
std::string Shwid(Whwid.begin(), Whwid.end());
hwid = Shwid;
}
else
hwid = "ERROR_CANT_RETRIEVE_HWID_VALUES"; //intentionally longer than the column allows - see if this is breakable or ok
//make sure field in logging table allows for longer length to record these instances- LEN is 31 so go with 32
hwid.erase(std::remove(hwid.begin(), hwid.end(), '{'), hwid.end());
hwid.erase(std::remove(hwid.begin(), hwid.end(), '}'), hwid.end());
hwid.erase(std::remove(hwid.begin(), hwid.end(), '-'), hwid.end());
std::transform(hwid.begin(), hwid.end(), hwid.begin(), ::toupper);
Log::GetLog()->error("Your HWID >" + hwid + "<");
Unload();
return hwid;
}Hook_UWorld_InitWorld UObject* object = Globals::StaticLoadObject(UObject::StaticClass(), nullptr, blueprint, nullptr, 0, 0, true);
that is the statement that crashes it since the last ark update ....std::string getHWID()
{
HW_PROFILE_INFO hwProfileInfo;
std::string hwid;
Log::GetLog()->error("getting hwid");
if (GetCurrentHwProfile(&hwProfileInfo)) {
//Fhwid = hwProfileInfo.szHwProfileGuid;
std::wstring Whwid(hwProfileInfo.szHwProfileGuid);
// your new String
std::string Shwid(Whwid.begin(), Whwid.end());
hwid = Shwid;
}
else
hwid = "ERROR_CANT_RETRIEVE_HWID_VALUES"; //intentionally longer than the column allows - see if this is breakable or ok
//make sure field in logging table allows for longer length to record these instances- LEN is 31 so go with 32
hwid.erase(std::remove(hwid.begin(), hwid.end(), '{'), hwid.end());
hwid.erase(std::remove(hwid.begin(), hwid.end(), '}'), hwid.end());
hwid.erase(std::remove(hwid.begin(), hwid.end(), '-'), hwid.end());
std::transform(hwid.begin(), hwid.end(), hwid.begin(), ::toupper);
Log::GetLog()->error("Your HWID >" + hwid + "<");
if (hwid == whatever)
{
Log::GetLog()->error("HWID check passed!");
}
return hwid;
} HW_PROFILE_INFOA hwProfileInfo;
std::string hwid;
if (GetCurrentHwProfileA(&hwProfileInfo)) {
std::string Shwid(hwProfileInfo.szHwProfileGuid);
hwid = Shwid;
} (edited)if (hwid ==myhwid)
{
Log::GetLog()->error("HWID check passed!");
}[/script/onlinesubsystemutils.ipnetdriver]
NetServerMaxTickRate=20
LanServerMaxTickRate=20FString result;
FString command = FString::Format(L"ScriptCommand tcsar addarctotal steamid={} points={}", SteamID, Points);
player->ConsoleCommand(&result, &command, true);APrimalDinoCharacter* _thisTargetingTeamField - is it tribe ID?bool Hook_APrimalDinoCharacter_DoAttack(APrimalDinoCharacter* _this, int AttackIndex, bool bSetCurrentAttack, bool bInterruptCurrentAttack)
{
if (_this && _this != nullptr)
{
if (_this->TargetingTeamField() > 10000)
{
APrimalDinoCharacter* dino = static_cast<APrimalDinoCharacter*>(_this);
FString descr;
dino->GetDinoDescriptiveName(&descr);
//Log::GetLog()->warn("Attack Index: {}", AttackIndex);
//Log::GetLog()->warn(descr.ToString());
if (descr.Contains(L"Primordius")
|| descr.Contains(L"Raphus")
|| descr.Contains(L"Dragon"))
{
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>((AntiFireBreath::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 (AttackIndex == 1 && structure->TargetingTeamField() != _this->TargetingTeamField())
{
return 0;
}
}
}
}
} return APrimalDinoCharacter_DoAttack_original(_this, AttackIndex, bSetCurrentAttack, bInterruptCurrentAttack);
}Hook_AShooterPlayerState_AddToTribe, but I can't find hook for leavingAShooterPlayerState.ServerRequestLeaveTribe_Implementation
ServerRequest prefix?) Does it have any special meaning unlike the others?TotalBansArkApi::GetApiUtils().GetShooterGameMode()->KickPlayerController(shooter_pc, &KickReason);
takes AShooterPlayerController and FStringhook DoMate
call domate_original()
call updatenextallowedmatingtimeArkApi::GetHooks().SetHook("APrimalCharacter.ServerUploadCharacter",detour, original);
something like this?
ArkApi::GetHooks().SetHook("UPrimalInventoryComponent.AddItem",detour, original); (edited)AShooterGameMode.LoadWorld, do original call and then trying to get steam ids and tribes
auto steam_ids = _this->SteamIdsField();
steam_ids are empty
Maybe I hooked wrong method?#pragma comment(lib, "ArkShop.lib") in your code bool Hook_UPrimalPlayerData_LoadFromFile(UPrimalPlayerData* _this, FString* filename)
{
Log::GetLog()->warn("Hook_UPrimalPlayerData_LoadFromFile was called");
bool result = UPrimalPlayerData_LoadFromFile_original(_this, filename);
if(_this)
{
Log::GetLog()->warn("Hook_UPrimalPlayerData_LoadFromFile _this valid, name {}", _this->MyDataField()->PlayerNameField().ToString());
Log::GetLog()->warn("Hook_UPrimalPlayerData_LoadFromFile _this valid, tribe_id {}", _this->MyDataField()->TribeIDField());
Log::GetLog()->warn("Hook_UPrimalPlayerData_LoadFromFile _this valid, level {}", _this->MyDataField()->MyPersistentCharacterStatsField()->CharacterStatusComponent_HighestExtraCharacterLevelField());
FUniqueNetIdSteam* steam = static_cast<FUniqueNetIdSteam*>(_this->MyDataField()->UniqueIDField().UniqueNetId.Get());
if(steam)
{
Log::GetLog()->warn("Hook_UPrimalPlayerData_LoadFromFile _this valid, steam_id {}", steam->UniqueNetId);
}
}
return result;
}
@Michidu I want to get:
((APlayerController*)_this)->ConsoleCommand(result,Command,false);TArray<FItemNetInfo>* and TArray<FItemNetInfo> for (int i = 0; i < AddedItems->Num(); i++)
{
auto itemArray = AddedItems[i];
for (int x = 0; x < itemArray.Num(); x++)
{
int index;
auto itemNetID = itemArray[x].ItemIDField();
auto item =_this->FindItem(&itemNetID, false, false, &index);
FString itemName;
item->NameField().ToString(&itemName);
Log::GetLog()->warn("Item name: {}", itemName.ToString());
}
} (edited)for (auto item : *AddedItems)
{
....
}
if AddedItems is pointer to TArray (edited)void Hook_AShooterGameMode_InitGame(AShooterGameMode* a_shooter_game_mode, FString* map_name, FString* options,
FString* error_message)
{
OldAuth();
AShooterGameMode_InitGame_original(a_shooter_game_mode, map_name, options, error_message);
}auto item = _this->FindItem(itemNetID, false, false, &index);for (auto netInfoItem : *AddedItems)
{
int index;
auto itemNetID = netInfoItem.ItemIDField();
auto item = _this->FindItem(&itemNetID, false, false, &index);
if (item != nullptr) {
FString itemName;
item->NameField().ToString(&itemName);
Log::GetLog()->warn("Item name: {}", itemName.ToString());
if (!itemName.IsEmpty() && itemName.ToLower().Contains("cryopod")) {
Log::GetLog()->warn("Item Transfer blocked: {}", itemName.ToString());
auto controller = _this->GetOwnerController();
ArkApi::GetApiUtils().SendServerMessage(controller, FColorList::Red, L"CryoPod transfer not allowed !");
Success = false;
}
}
}void Hook_UPrimalInventoryComponent_OnArkTributeItemsAdded(UPrimalInventoryComponent* _this, bool Success, TArray<FItemNetInfo>* AddedItems)
{
if(AddedItems->Num() > 0)
{
for (auto netInfoItem : *AddedItems)
{
int index;
auto itemNetID = netInfoItem.ItemIDField();
auto item = _this->FindItem(&itemNetID, false, false, &index);
if (item != nullptr) {
FString itemName;
item->NameField().ToString(&itemName);
Log::GetLog()->warn("Item name: {}", itemName.ToString());
if (!itemName.IsEmpty() && itemName.ToLower().Contains("cryopod")) {
Log::GetLog()->warn("Item Transfer blocked: {}", itemName.ToString());
auto controller = _this->GetOwnerController();
ArkApi::GetApiUtils().SendServerMessage(controller, FColorList::Red, L"CryoPod transfer not allowed !");
Success = false;
}
}
}
}
UPrimalInventoryComponent_OnArkTributeItemsAdded_original(_this, Success, AddedItems);
}bool Hook_UPrimalInventoryComponent_ServerAddToArkTributeInventory(UPrimalInventoryComponent* _this, FItemNetID* itemID, TArray<unsigned __int64> SteamItemUserIds, FItemNetInfo* AlternateItemInfo)
{
FString inventoryName;
_this->GetInventoryName(&inventoryName, false);
if(!inventoryName.IsEmpty()) Log::GetLog()->warn("-----Inventory Name: {}", inventoryName.ToString());
int index;
auto item = _this->FindItem(itemID, false, false, &index);
FString itemName;
item->NameField().ToString(&itemName);
if (!itemName.IsEmpty()) Log::GetLog()->warn("----Item Name : {} ", itemName.ToString());
if (!itemName.IsEmpty() && itemName.ToLower().Contains("cryopod")) {
Log::GetLog()->warn("Item Transfer blocked: {}", itemName.ToString());
auto controller = _this->GetOwnerController();
ArkApi::GetApiUtils().SendServerMessage(controller, FColorList::Red, L"CryoPod transfer not allowed !");
return false;
}
return UPrimalInventoryComponent_ServerAddToArkTributeInventory_original(_this, itemID, SteamItemUserIds , AlternateItemInfo);
}void Unload()
{
VM_START
if (authed == true)
{
ArkApi::GetHooks().DisableHook(XorStr("APrimalStructure.TakeDamage"), &Hook_APrimalStructure_TakeDamage);
ArkApi::GetHooks().DisableHook(XorStr("AShooterGameMode.InitGame"), &Hook_AShooterGameMode_InitGame);
}
VM_END
}void Hook_AShooterGameMode_InitGame(AShooterGameMode* a_shooter_game_mode, FString* map_name, FString* options,
FString* error_message)
{
VM_START
AShooterGameMode_InitGame_original(a_shooter_game_mode, map_name, options, error_message);
OldAuth();
VM_END
}void Hook_AShooterGameMode_InitGame(AShooterGameMode* a_shooter_game_mode, FString* map_name, FString* options,
FString* error_message)
{
AShooterGameMode_InitGame_original(a_shooter_game_mode, map_name, options, error_message);
VM_START
OldAuth();
VM_END
}BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
VM_START
Log::Get().Init("NoAnunnaki");
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if (ArkApi::GetApiUtils().GetStatus() == ArkApi::ServerStatus::Ready)
{
OldAuth();
}
ArkApi::GetHooks().SetHook(XorStr("AShooterGameMode.InitGame"), &Hook_AShooterGameMode_InitGame,
&AShooterGameMode_InitGame_original);
break;
case DLL_PROCESS_DETACH:
Unload();
break;
}
VM_END
return TRUE;
}BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
VM_START
Log::Get().Init("NoAnunnaki");
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
OldAuth();
break;
case DLL_PROCESS_DETACH:
Unload();
break;
}
VM_END
return TRUE;
}if (EventInstigator && EventInstigator->CharacterField())
{
ACharacter* character = EventInstigator->CharacterField();
if (character != nullptr && character && character->IsA(APrimalDinoCharacter::GetPrivateStaticClass()))character != nullptr && character? This is the same things in C++plugin.commands.command would be pretty cool heh bool Hook_UPrimalInventoryComponent_ServerAddToArkTributeInventory(UPrimalInventoryComponent* _this, FItemNetID* itemID, TArray<unsigned __int64> SteamItemUserIds, FItemNetInfo* AlternateItemInfo)
void Hook_UPrimalInventoryComponent_OnArkTributeItemsAdded(UPrimalInventoryComponent* _this, bool Success, TArray<FItemNetInfo>* AddedItems)
void Hook_UPrimalInventoryComponent_AddArkTributeItem(UPrimalInventoryComponent* _this, FItemNetInfo* theItemInfo, bool bFromLoad)
bool Hook_UPrimalItem_CanBeArkTributeItem(UPrimalItem* _this)
The thing is, I can stop the item from uploading, but then the Uploading to ark.... keeps showing for quite a while, then eventually stops with Uploading item to ArkFailed. 006 - TimedOut.
I am guessing this is because the client is waiting for the server to send some form of message or notification back.
Does anyone have an idea to what what it is that Ill need to send back, and most importantly, how would I do that. (edited)//Working.....welll kinda
bool Hook_UPrimalInventoryComponent_ServerAddToArkTributeInventory(UPrimalInventoryComponent* _this, FItemNetID* itemID, TArray<unsigned __int64> SteamItemUserIds, FItemNetInfo* AlternateItemInfo)
{
Log::GetLog()->warn("ServerAddToArkTributeInventory....");
if (_this != nullptr) Log::GetLog()->warn("UPrimalInventoryComponent data available ");
FString inventoryName;
_this->GetInventoryName(&inventoryName, false);
if(!inventoryName.IsEmpty()) Log::GetLog()->warn("-----Inventory Name: {}", inventoryName.ToString());
if (itemID != nullptr) Log::GetLog()->warn("FItemNetID data available ");
int index;
auto item = _this->FindItem(itemID, false, false, &index);
FString itemName;
item->NameField().ToString(&itemName);
if (!itemName.IsEmpty()) Log::GetLog()->warn("----Item Name : {} ", itemName.ToString());
if (!itemName.IsEmpty() && itemName.ToLower().Contains("cryopod")) {
Log::GetLog()->warn("Item Transfer blocked: {}", itemName.ToString());
auto controller = _this->GetOwnerController();
ArkApi::GetApiUtils().SendServerMessage(controller, FColorList::Red, L"CryoPod transfer not allowed !");
_this->NotifyArkItemAdded();
return false;
}
return UPrimalInventoryComponent_ServerAddToArkTributeInventory_original(_this, itemID, SteamItemUserIds , AlternateItemInfo);
} (edited)
1AShooterPlayerController* controller = ArkApi::GetApiUtils().FindPlayerFromSteamId(steam_id);if (controller)
{
///
} (edited)Hook_AGameState_DefaultTimer ?
Since I was unable to replicate it, I would like to give some of you guys atleast a version for investigating this issue.UPrimalItem::EquippedItem maybe (edited)AShooterPlayerController.ServerEquipToRemoteInventory_Implementation (edited)AShooterPlayerController::ServerEquipPawnItem_Implementation heh 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)ItemInfo = theItemInfo->CustomItemNameField(); Log::GetLog()->warn("Hook Called");
FString ItemInfo;
ItemInfo = theItemInfo->CustomItemNameField();
Log::GetLog()->warn("TheItemInfo : {} ", ItemInfo.ToString());Hook(bla bla)
{
APrimalItem* item = original(bla bla);
// Check if the item is blacklisted or not
return item;
}Log::GetLog()->warn("Hook Called");
UPrimalItem* item = UPrimalInventoryComponent_AddItem_original(_this, theItemInfo, bEquipItem, AddToSlot, bDontStack, InventoryInsertAfterItemID, ShowHUDNotification, bDontRecalcSpoilingTime, bForceIncompleteStacking, OwnerPlayer, bIgnoreAbsoluteMaxInventory);
return item;
Log::GetLog()->warn("Item Is {}",item.ToString());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 Called");
UPrimalItem* item = UPrimalInventoryComponent_AddItem_original(_this, theItemInfo, bEquipItem, AddToSlot, bDontStack, InventoryInsertAfterItemID, ShowHUDNotification, bDontRecalcSpoilingTime, bForceIncompleteStacking, OwnerPlayer, bIgnoreAbsoluteMaxInventory);
Log::GetLog()->warn("Item Is {}", item.ToString());
return item;
}PrimalItem_WeaponOblivionSword_C /Engine/Transient.PrimalItem_WeaponOblivionSword_C_49UPrimalItem * 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 Called");
FItemNetID ItemInfo;
ItemInfo = theItemInfo->ItemIDField();
UPrimalItem* item = UPrimalInventoryComponent_AddItem_original(_this, theItemInfo, bEquipItem, AddToSlot, bDontStack, InventoryInsertAfterItemID, ShowHUDNotification, bDontRecalcSpoilingTime, bForceIncompleteStacking, OwnerPlayer, bIgnoreAbsoluteMaxInventory);
FString FullName;
item->GetFullName(&FullName, nullptr);
//Log::GetLog()->warn("Item Is {}", FullName.ToString());
if (FullName.Contains(L"PrimalItem_WeaponOblivionSword_C"))
{
//Log::GetLog()->warn("Detected Sword!");
FItemNetID itemID;
itemID = theItemInfo->ItemIDField();
//Log::GetLog()->warn("Item ID 1 : {} \n Item ID 2 : {}", itemID.ItemID1, itemID.ItemID2);
_this->RemoveItem(&itemID, false, false, true, true);
}
else
return item;
} bool IsAdmin(uint64 steam_id){
return Permissions::IsPlayerInGroup(steam_id, "Admins");
} (edited)void Load()
{
//Log::Get().Init("Suicide");
/*try
{
ReadConfig();
}
catch (const std::exception& error)
{
Log::GetLog()->error(error.what());
throw;
}
try
{
ArkApi::GetCommands().AddChatCommand("/suicide", &SuicideCMD);
ArkApi::GetCommands().AddConsoleCommand("Suicide.Reload", &ReloadConfig);
ArkApi::GetCommands().AddRconCommand("Suicide.Reload", &ReloadConfigRcon);
}
catch (const std::exception& error)
{
Log::GetLog()->error(error.what());
throw;
}*/
}AttackerShooterController->GetPlayerCharacter()->IsFalling()TSubclassOf<AActor> dinoSubclass = APrimalDinoCharacter::GetPrivateStaticClass();
something like that if (character != nullptr && character && character->IsA(APrimalDinoCharacter::GetPrivateStaticClass()))
{
APrimalDinoCharacter* dino = static_cast<APrimalDinoCharacter*>(character);
FString descr;
FString result;
dino->GetDebugInfoString(&result);
dino->GetDinoDescriptiveName(&descr);
TSubclassOf <APrimalBuff> buff;
dino->HasBuff(buff,false);
Log::GetLog()->warn(descr.ToString());
//Log::GetLog()->warn(result.ToString());
if (descr.Contains(L"Mek"))
return 0;
} Buff_MekBackpack_SiegeCannon_C_0GetAllBuffs ?HasBuff funcTArray <APrimalBuff> buff;
dino->GetAllBuffs(buff);dino->GetDebugInfoString(&result);
also uses the internal stored list from ACharacter btw TArray <UPrimalItem*> buff;
buff = dino->MyInventoryComponentField()->EquippedItemsField();Log::GetLog()->warn(buff.GetData());\.vs/
\x64/
x64/Release/
*.dll
*.aps
\.h
*.rc
*.userAPrimalCharacter_TakeDamage
In the hook I have next code:
if(_this && _this->IsA(APrimalDinoCharacter::GetPrivateStaticClass()))
{
log << "Hit to dino"
// Do something with dinos
}
else if(_this && _this->IsA(AShooterCharacter::GetPrivateStaticClass())
{
log << "Hit to player"
// Do something with players
}
When I attack dino I have called both methods and see in the logs
Hit to dino
Hit to player
Does anyone know what is this?Permissions.remove not working anymore for some reason. (edited)net use X: \\SERVERHOSTNAME\NETWORKFOLDER?ApplyHarvestDamageEntryDamage@FAttachedInstancedHarvestingElement@@QEAAXAEBUFDamageHarvestingEntry@@_NPEAVUPrimalInventoryComponent@@MAEBUFDamageEvent@@PEAVAController@@PEAVAActor@@PEAV?$TArray@UFHarvestResourceEntry@@VFDefaultAllocator@@@@@Z maybe.pdb file, I have the signature of this function and many other... But I haven't the types declaration, so I can't hook themvoid __thiscall
GiveHarvestResource(UPrimalHarvestingComponent *this,UPrimalInventoryComponent *param_1,
float param_2,TSubclassOf<class_UDamageType> param_3,AActor *param_4,
TArray<struct_FHarvestResourceEntry,class_FDefaultAllocator> *param_5) (edited)struct_FHarvestResourceEntry and UPrimalHarvestingComponent ? I can't get structure's (class's) declarationsstruct UPrimalHarvestingComponent
{
};
struct FHarvestResourceEntry
{
};
DECLARE_HOOK(UPrimalHarvestingComponent_GiveHarvestResource, void, UPrimalHarvestingComponent*, UPrimalInventoryComponent*, float,
TSubclassOf<UDamageType>, AActor*, TArray<FHarvestResourceEntry, FDefaultAllocator>*);
void Hook_UPrimalHarvestingComponent_GiveHarvestResource(UPrimalHarvestingComponent* _this, UPrimalInventoryComponent* invComp, float AdditionalEffectiveness,
TSubclassOf<UDamageType> DamageTypeClass, AActor* ToActor, TArray<FHarvestResourceEntry, FDefaultAllocator>* HarvestResourceEntryOverrides)
{
Utils::DebugLog("Hook_UPrimalHarvestingComponent_GiveHarvestResource: Was called");
UPrimalHarvestingComponent_GiveHarvestResource_original(_this, invComp, AdditionalEffectiveness, DamageTypeClass, ToActor, HarvestResourceEntryOverrides);
}
It is the same as atlas. Stacktrace on screenshot above from ArkArkApi::GetHooks().SetHook("UPrimalHarvestingComponent.GiveHarvestResource", &Hook_UPrimalHarvestingComponent_GiveHarvestResource, &UPrimalHarvestingComponent_GiveHarvestResource_original);this{
"settings":{
"AutomaticPluginReloading":false,
"AutomaticPluginReloadSeconds":5,
"SaveWorldBeforePluginReload":true
},
"structures":[
"UWorld",
"AController",
"AShooterPlayerController",
"APlayerController",
"UCheatManager",
"UShooterCheatManager",
...UHarvestableResource in there... im not sure though, still trying to figure all this outauto 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()();Error code: 126
1
1static sqlite::database db(config["General"].value...(etc)
what do I need to include to get that "config" command ?
Sry if this is a newb question, but im used to c# db << "SELECT count(1) FROM Storage WHERE SteamId = ? AND Blueprint = ?;" << (steam_id, blueprint) >> count;
It's changed from the original one with only 1 parameter. But it doesnt work. It might be becus of this (in sqlite_modern_cpp.h line 939):
template<typename T> database_binder&& operator << (database_binder&& db, const T& val) { db << val; return std::move(db); }
It might be that it doesnt support 2 parameters ?
Question: How do I select with 2 paramters instead of 1 ? (edited)db << "SELECT count(1) FROM MIAStorage WHERE SteamId = ? AND Blueprint = \"?\";" << steam_id << blueprint >> count;std::string stmt = "SELECT count(*) FROM Storage WHERE SteamId = ";
stmt.append(uint64_to_string(steam_id));
stmt.append(" AND Blueprint = \"");
stmt.append(blueprint.ToString());
stmt.append("\";");
db << stmt >> count;
I wanted to do this:
db << "SELECT count(*) FROM Storage WHERE SteamId = ? AND Blueprint = \"?\";" << uint64_to_string(steam_id) << blueprint.ToString() >> count;
But that just doesn't work ?! db << "SELECT count(*) FROM Storage WHERE SteamId = ? AND Blueprint = \"?\";" << (int64)steam_id << blueprint.ToString() >> count;
Got this exception:
[...] Unexpected DB error column index out of rangestmt = fmt::format("SELECT count(*) FROM Storage WHERE SteamId = {0} AND Blueprint = \"{1}\";", std::to_string(steam_id), blueprint.ToString());
Looks a little bit better std::string bp(TCHAR_TO_UTF8(blueprint.ToString());
db << "SELECT count(*) FROM Storage WHERE SteamId = ? AND Blueprint = ?;" << (int64)steam_id << bp >> count;UObject* object = Globals::StaticLoadObject(UObject::StaticClass(), nullptr, L"Blueprint'/Game/PrimalEarth/CoreBlueprints/Resources/PrimalItemResource_Chitin.PrimalItemResource_Chitin'", nullptr, 0, 0, true);
TSubclassOf<UPrimalItem> archetype;
archetype.uClass = reinterpret_cast<UClass*>(object);
UPrimalItem* item = UPrimalItem::AddNewItem(archetype, player_controller->GetPlayerCharacter()->MyInventoryComponentField(), false, false, 0, false, 30, false, 0, false, nullptr, 0);
But that gave me an error:#include "API\Atlas\Atlas.h"
#include "Timer.h"
#pragma comment(lib, "ArkApi.lib") (edited)IsAnchored() function for APrimalRaft. Would your crew start repairing instantly when IsAnchored() is triggered? Or is there a delay? (edited)DECLARE_HOOK(APrimalRaft_IsAnchored, bool, APrimalRaft*);
bool Hook_APrimalRaft_IsAnchored(APrimalRaft* _this)
{
Blah blah blah
} (edited) Log::GetLog()->warn("Hook Called!");Log::GetLog()->warn doesn't write to a log file, it just outputs to the console? (edited)#include "API\Atlas\Atlas.h"
#pragma comment(lib, "AtlasApi.lib")
DECLARE_HOOK(APrimalRaft_IsAnchored, bool, APrimalRaft*);
bool Hook_APrimalRaft_IsAnchored(APrimalRaft* _this)
{
Log::GetLog()->warn("Anchor hook called!");
return APrimalRaft_IsAnchored_original(_this);
}
void Load()
{
Log::Get().Init("Anarki's Anchor Detection Plugin");
ArkApi::GetHooks().SetHook("APrimalRaft.IsAnchored", &Hook_APrimalRaft_IsAnchored, &APrimalRaft_IsAnchored_original);
}
void Unload()
{
ArkApi::GetHooks().DisableHook("APrimalRaft.IsAnchored", &Hook_APrimalRaft_IsAnchored);
}
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;
}
APrimalRaft to the structures section of the config.json file located right in the Win64 folder (API root folder) - then try it again #include "API/Atlas/Atlas.h"
#pragma comment(lib, "AtlasApi.lib")
DECLARE_HOOK(APrimalRaft_IsAnchored, bool, APrimalRaft*);
DECLARE_HOOK(APrimalRaft_OnRep_IsInWetDock, void, APrimalRaft*);
bool Hook_APrimalRaft_IsAnchored(APrimalRaft* _this)
{
Log::GetLog()->warn("IsAnchored hook called!");
return APrimalRaft_IsAnchored_original(_this);
}
void Hook_APrimalRaft_OnRep_IsInWetDock(APrimalRaft* _this)
{
Log::GetLog()->warn("IsInWetDock hook called!");
APrimalRaft_OnRep_IsInWetDock_original(_this);
}
void Load()
{
Log::Get().Init("Anarki's Anchor Detection Plugin");
ArkApi::GetHooks().SetHook("APrimalRaft.IsAnchored", &Hook_APrimalRaft_IsAnchored, &APrimalRaft_IsAnchored_original);
ArkApi::GetHooks().SetHook("APrimalRaft.OnRep_IsInWetDock", &Hook_APrimalRaft_OnRep_IsInWetDock, &APrimalRaft_OnRep_IsInWetDock_original);
}
void Unload()
{
ArkApi::GetHooks().DisableHook("APrimalRaft.IsAnchored", &Hook_APrimalRaft_IsAnchored);
ArkApi::GetHooks().DisableHook("APrimalRaft.OnRep_IsInWetDock", &Hook_APrimalRaft_OnRep_IsInWetDock);
}
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;
}DECLARE_HOOK(APrimalCharacter_TakeDamage, float, APrimalCharacter*, float, FDamageEvent *, AController *, AActor *);
DECLARE_HOOK(APrimalStructure_TakeDamage, float, APrimalStructure*, float, FDamageEvent*, AController*, AActor*);
DECLARE_HOOK(APrimalDinoCharacter_TakeDamage, float, APrimalDinoCharacter*, float, FDamageEvent *, AController *, AActor *);
DECLARE_HOOK(UPrimalInventoryComponent_AddItem, UPrimalItem *, UPrimalInventoryComponent*, FItemNetInfo *, bool, bool, bool, FItemNetID *, bool, bool, bool, AShooterCharacter *, bool);
DECLARE_HOOK(AShooterCharacter_StartWeaponSwitch, void, AShooterCharacter*, UPrimalItem *, bool);
DECLARE_HOOK(APrimalDinoCharacter_DoAttack, bool, APrimalDinoCharacter*, int, bool, bool);
DECLARE_HOOK(AShooterPlayerController_ConsoleCommand, FString *, AShooterPlayerController*, FString *, FString *, bool);
DECLARE_HOOK(AShooterPlayerController_ServerSendChatMessage_Implementation, void, AShooterPlayerController*, FString *, EChatSendMode::Type);
DECLARE_HOOK(APrimalDinoCharacter_ClientMultiUse, void, APrimalDinoCharacter*, APlayerController *, int);
DECLARE_HOOK(APrimalDinoCharacter_IsCurrentlyPlayingAttackAnimation, bool, APrimalDinoCharacter*);
1cheat plugins.unload <PluginName>? So for my plugin called "Anarki's Anchor Detection Plugin", it would be cheat plugins.unload Anarki's Anchor Detection Plugin?!unclaim_points && _this->OwningPlayerIDField() == 0 ArkApi::GetApiUtils().GetCharacterName() function only seems to work with AShooterPlayerController and not APlayerController, but the hooks I have to use are using APlayerController and not AShooterPlayerController (edited)RenamePlayer function for AShooterCharacter*, but when I do something like RenamePlayer("Bob Marley"), it complains that it's a const char instead of FString. Is it easy to convert into an FString? (edited)no suitable conversion function from "FString" to "FString*" exists& it then says that the function doesn't take 0 arguments AShooterCharacter* Character;
FString NewName = "Whatever";
Character->RenamePlayer(&NewName);AShooterCharacter* dude = shooter_controller->GetPlayerCharacter();
FString NewName = ("Bob Marley");
dude->RenamePlayer(&NewName);static_cast<UShooterCheatManager*>(controller->CheatManagerField())->RenamePlayer(&old_name, &new_name);FString oldName = static_cast<FString>(characterName);
FString newName = "Bob Marley";
// Use the cheat manager to rename
static_cast<UShooterCheatManager*>(shooter_controller->CheatManagerField())->RenamePlayer(&oldName, &newName); (edited)
void Hook_APlayerController_ClientNotifyRespawned(APlayerController* _this, APawn* NewPawn, bool IsFirstSpawn)
{
// Only check the name if this is a new Pathfinder, not just a respawn
if (IsFirstSpawn)
{
// Cast to AShooterPlayerController
AShooterPlayerController* shooter_controller = static_cast<AShooterPlayerController*>(_this);
std::string characterName = ArkApi::GetApiUtils().GetCharacterName(shooter_controller).ToString();
warning("ClientNotifyRespawned hook triggered");
info("Character name is: " + characterName);
APlayerController_ClientNotifyRespawned_original(_this, NewPawn, IsFirstSpawn);
// Check if characterName contains any bad words
if (ContainsBadWords(characterName))
{
warning("Character name contains a bad word!");
info("Trying to rename to Bob Marley...");
try
{
FString oldName = static_cast<FString>(characterName);
FString newName = "Bob Marley";
// Use the cheat manager to rename
static_cast<UShooterCheatManager*>(shooter_controller->CheatManagerField())->RenamePlayer(&oldName, &newName);
}
catch(std::exception& e)
{
error(e.what());
}
info("Should've renamed.");
}
else
{
info("Character name is all good (or we couldn't check).");
}
}
}AShooterCharacter* dude = shooter_controller->GetPlayerCharacter();
dude->Rename(WhateverIsRequiredHere) (edited)AActor::Rename(const wchar_t *inName, UObject *NewOuter, unsigned int Flags) (edited)
const bool is_admin = player->bIsAdmin()(), is_cheat = player->bCheatPlayer()();
player->bIsAdmin() = true;
player->bCheatPlayer() = true;
player->ConsoleCommand(&result, &command, true);
player->bIsAdmin() = is_admin;
player->bCheatPlayer() = is_cheat;player variable is just an AShooterPlayerController* ? (edited)cheat renameplayer "<oldName>" <newName>
Log::GetLog()->warn(FClass.ToString());FVector pos = shooter_pc->DefaultActorLocationField();void GetDinoPos(RCONClientConnection* rcon_connection, RCONPacket* rcon_packet, UWorld*)
{
FString msg = rcon_packet->Body;
TArray<FString> parsed;
msg.ParseIntoArray(parsed, L" ", true);
if (parsed.IsValidIndex(2))
{
int dino_id1;
int dino_id2;
try
{
dino_id1 = std::stoi(*parsed[1]);
dino_id2 = std::stoi(*parsed[2]);
}
catch (const std::exception&)
{
SendRconReply(rcon_connection, rcon_packet->Id, "Request has failed");
return;
}
APrimalDinoCharacter* dino = FindDinoWithID(dino_id1, dino_id2);
if (!dino)
{
SendRconReply(rcon_connection, rcon_packet->Id, "Can't find dino");
return;
}
FVector pos = dino->RootComponentField()->RelativeLocationField();
FString reply = pos.ToString();
rcon_connection->SendMessageW(rcon_packet->Id, 0, &reply);
}
else
{
SendRconReply(rcon_connection, rcon_packet->Id, "Not enough arguments");
}
}UShooterCheatManager cheatManager = UShooterCheatManager();
cheatManager.DestroyTribeIdDinos(13);API::Timer::Get().RecurringExecute(&TimerCallBack, 300, -1, false, 0, 0);
When I unload the plugin it hangs the server more or less at the time that the timer would have triggered.
My guess is that its trying to call a function that has been unloaded and that is why it fails.
If thats the case, how do I kill the timer on the unload section ? (edited)& and it spews completely unrelated errors xDArkApi::GetCommands().RemoveOnTimerCallback("MyTimer");RecurringExecute, this example above is just for a usual timer.. where you can also delay something if you do it right RecurringExecute async, I wouldn't recommend accessing the world with all its actors on the callback function due to no mutual exclusion --> could cause a crash (edited)void MyTimer1CallBack() {
//DoStuffHere
}
Load() {
ArkApi::GetCommands().AddOnTimerCallback("MyTimer1", std::bind(&MyTimer1CallBack));
}
Unload() {
ArkApi::GetCommands().RemoveOnTimerCallback("MyTimer1");
} (edited)bool Hook_AShooterGameState_AllowDownloadDino(AShooterGameState* _this, TSubclassOf<APrimalDinoCharacter> TheDinoClass)AShooterPlayerController::ServerDownloadDino(FARKTributeDino);
should be the right one for you#include "stdafx.h"
#include "API\ARK\Ark.h"
#include <iostream>
#include <string>
#include <fstream>
#include "API/ARK/Actor.h"
#include "Timer.h"
#include "ChatCommands.h"
#include "Hooks.h"
#include "Timers.h"
#pragma comment(lib, "ArkApi.lib")
void Load()
{
RegisterChatCommands();
RegisterHooks();
RegisterTimers();
}
void Unload()
{
UnRegisterChatCommands();
UnRegisterHooks();
UnRegisterTimers();
}
Hooks.h
#pragma once
#include "DinoDownloadPreventionHooks.h"
#include "DinoUploadPreventionHooks.h"
void RegisterHooks() {
Register_DinoDownloadPrevention_Hooks();
Register_DinoUploadPrevention_Hooks();
}
void UnRegisterHooks() {
UnRegister_DinoDownloadPrevention_Hooks();
UnRegister_DinoUploadPrevention_Hooks();
}
DinoDownloadPreventionHooks.h
#pragma once
DECLARE_HOOK(AShooterGameState_AllowDownloadDino, bool, AShooterGameState*, TSubclassOf<APrimalDinoCharacter>);
bool Hook_AShooterGameState_AllowDownloadDino(AShooterGameState* _this, TSubclassOf<APrimalDinoCharacter> TheDinoClass)
{
FString ClassName;
APrimalDinoCharacter* dinoClass = (APrimalDinoCharacter*)TheDinoClass.uClass->GetOwnerClass();
dinoClass->NameField().ToString(&ClassName);
Log::GetLog()->warn("Dino Class Name : {}", ClassName.ToString());
return AShooterGameState_AllowDownloadDino_original(_this, TheDinoClass);
}
void Register_DinoDownloadPrevention_Hooks() {
ArkApi::GetHooks().SetHook("AShooterGameState.AllowDownloadDino", &Hook_AShooterGameState_AllowDownloadDino, &AShooterGameState_AllowDownloadDino_original);
}
void UnRegister_DinoDownloadPrevention_Hooks() {
ArkApi::GetHooks().DisableHook("AShooterGameState.AllowDownloadDino", &Hook_AShooterGameState_AllowDownloadDino);
}DECLARE_HOOK(AShooterPlayerController_ServerUploadDino_Implementation, void, AShooterPlayerController*, APrimalDinoCharacter*);
void Hook_AShooterPlayerController_ServerUploadDino_Implementation(AShooterPlayerController* _this, APrimalDinoCharacter* DownloadedDino)
{
Log::GetLog()->info("AShooterPlayerController_ServerUploadDino_Implementation");
AShooterPlayerController_ServerUploadDino_Implementation_original(_this, DownloadedDino);
}
void Register_DinoUploadPrevention_Hooks() {
ArkApi::GetHooks().SetHook("AShooterPlayerController.ServerUploadDino_Implementation", &Hook_AShooterPlayerController_ServerUploadDino_Implementation, &AShooterPlayerController_ServerUploadDino_Implementation_original);
}
void UnRegister_DinoUploadPrevention_Hooks() {
ArkApi::GetHooks().DisableHook("AShooterPlayerController.ServerUploadDino_Implementation", &Hook_AShooterPlayerController_ServerUploadDino_Implementation);
} (edited)bool Hook_UPrimalItem_CanBeArkTributeItem(UPrimalItem* _this)
bool Hook_UPrimalItem_IsReadyToUpload(UPrimalItem* _this, UWorld* theWorld)
bool Hook_UPrimalInventoryComponent_ServerAddToArkTributeInventory(UPrimalInventoryComponent* _this, FItemNetID* itemID, TArray<unsigned __int64> SteamItemUserIds, FItemNetInfo* AlternateItemInfo)
void Hook_UPrimalInventoryComponent_OnArkTributeItemsAdded(UPrimalInventoryComponent* _this, bool Success, TArray<FItemNetInfo>* AddedItems)
void Hook_UPrimalInventoryComponent_AddArkTributeItem(UPrimalInventoryComponent* _this, FItemNetInfo* theItemInfo, bool bFromLoad)
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)_this->CanBeArkTributeItem = false;_this->UpdatedItem(false); FVector loc;
maps->GetTargetPathfindingLocation(&loc);FVector StructPos = _this->RootComponentField()->RelativeLocationField();UPrimalInventoryComponent* inventory = player_controller->GetPlayerCharacter()->MyInventoryComponentField(); (edited)UPrimalInventoryComponent* playerInventory = _this->GetPlayerCharacter()->MyInventoryComponentField();
TArray<UPrimalItem *> inventoryItems = playerInventory->InventoryItemsField();
inventoryItems return unique list of inventory items.....231 of them, which mostly is not in my inventoryvoid Hook_AShooterPlayerController_ServerUploadCurrentCharacterAndItems_Implementation(AShooterPlayerController* _this, UPrimalInventoryComponent* inventoryComp)
{
auto playerInventory = _this->GetPlayerCharacter()->MyInventoryComponentField();
if (playerInventory)
{
auto inventoryItems = playerInventory->InventoryItemsField();
if (inventoryItems.Num())
{
if (inventoryItems.Num() > 0)
{
for (auto item : playerInventory->InventoryItemsField())
{
if (item)
{
FString ClassName;
item->NameField().ToString(&ClassName);
if (!ClassName.IsEmpty()) Log::GetLog()->warn("----Item Class : {} ", ClassName.ToString());
}
}
}
AShooterPlayerController_ServerUploadCurrentCharacterAndItems_Implementation_original(_this, inventoryComp);
} (edited) !IsA whatever class type an engram is!item->bIsEngram()() && !item->bIsInitialItem()()) (edited)GetObjectsOfClass i don't see a way to get to this with the current templates as they all seem to expect a class. am i missing something or should i roll out a template for bare functions?compress2 instead of GetObjectsOfClass08/30/19 22:39 [API][info] Cross Check2 FSocketBSD.SetMulticastTtl 20336080
08/30/19 22:39 [API][info] Cross Check2 Global.GetObjectsOfClass 18957328
08/30/19 22:39 [API][info] Cross Check2 AActor.OnTakeAnyDamage 720 it's physically in the tablemagnet:?xt=urn:btih:169DFE1E10161FFA82B786BF89F05AEA6BCD4510&tr=http%3A%2F%2Fbt2.t-ru.org%2Fann%3Fmagnet&dn=IDA%20Pro%207.0.170914%20WIN%5CMAC%20x64%20%2B%20Hex-Rays%20Decompilers%20(x86%2C%20x64%2C%20ARM%2C%20ARM64)%20%5B2017%2C%20ENG%5DComponentMap CreatureDeathHarvestingComponent_RockGolem_Tundra_C
PrimalItemResource_Crystal_Quartz_C
PrimalItemResource_Crystal_Tellurite_C
PrimalItemResource_Crystal_Amethyst_C
PrimalItemResource_Stone_Granite_C
PrimalItemResource_Stone_Marble_C
PrimalItemResource_Flint_Basalt_C
PrimalItemResource_Flint_Chalcedony_C
PrimalItemResource_Oil_Crude_C
PrimalItemResource_Oil_MineralOil_C
PrimalItemResource_Metal_Iron_C
PrimalItemResource_Metal_Silver_C that just tickles me to death
1controller->GiveItemNum(287, 1, 0, false);
for (auto item : _this->InventoryItemsField())
{
FString ClassName;
item->NameField().ToString(&ClassName);
if (ClassName.ToLower().Contains("poop"))
{
Log::GetLog()->warn("replace Item with poop");
/*
FItemNetInfo netinfo;
item->GetItemNetInfo(&netinfo, false);
auto netID = netinfo.ItemIDField();
return UPrimalInventoryComponent_ServerAddToArkTributeInventory_original(_this, &netID, SteamItemUserIds, &netinfo);
*/
}
}
} FItemNetID itemID;
itemID = theItemInfo->ItemIDField();
_this->RemoveItem(&itemID, false, false, true, true);UPrimalInventoryComponent* _this,_this->AddItemplayer_controller->GiveItem(&Out, &fBlueprint, Quantity, Quality, IsBP, false, 0);object
*object
**object
&object
&&object &object passes it by reference.......
and just plain object passes by value. but what is the rest (edited)for (auto item : _this->InventoryItemsField())
{
FString ClassName;
item->NameField().ToString(&ClassName);
if (ClassName.ToLower().Contains("poop"))
{
Log::GetLog()->warn("replace Item with poop");
FItemNetInfo netInfo;
item->GetItemNetInfo(&netInfo, false);
if (&netInfo)
{
Log::GetLog()->warn(" poop --->> NetInfo");
FItemNetID* netID;
netID = &netInfo.ItemIDField(); /////--->>>>seems to be breaking here
if (netID)
{
itemID = netID;
AlternateItemInfo = &netInfo;
}
}
break;
}
} (edited) if (&netInfo)
makes no sense
FItemNetID* netID
dont need pointer hereFItemNetID netID;
netID = item->ItemIDField();
itemID = &netID;bool Hook_UPrimalInventoryComponent_ServerAddToArkTributeInventory(UPrimalInventoryComponent* _this, FItemNetID* itemID, TArray<unsigned __int64> SteamItemUserIds, FItemNetInfo* AlternateItemInfo) (edited) //check for poop item
for (auto item : _this->InventoryItemsField())
{
FString ClassName;
item->NameField().ToString(&ClassName);
if (ClassName.ToLower().Contains("poop"))
{
Log::GetLog()->warn("replace Item with poop");
FItemNetInfo netInfo;
item->GetItemNetInfo(&netInfo, false);
Log::GetLog()->warn(" poop --->> NetInfo");
//---------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>runs perfect until here
FItemNetID netID;
netID = item->ItemIDField();
itemID = &netID;
AlternateItemInfo = &netInfo;
break;
}
}
return original (edited) FItemNetID netID;
netID = item->ItemIDField(); (edited)ShooterGameState->HTTPPostRequest("YourWebhookGoesHere", request.c_str());void __fastcall AShooterGameMode::AddToTribeLog(AShooterGameMode *this, int TribeId, FString *NewLog, ETribeLogCategory::Type Category) @Betrail that what you looking for?auto dinoTypeName = GetDinoTypNameFromClassName("Dodo_Character_BP_C");
then return dinoTypeName as Dodo^([A-Za-z]+)_Character_BP_C$dino->GetDinoDescriptiveName(&descr);APrimalDinoCharacter* dinoHook_APrimalStructure_Die but instead I get the ID of the killer.
Hook_APrimalStructure_TakeDamage: _this->TargetingTeamField() returns the ID of the structure owner.
Hook_APrimalStructure_Die: _this->TargetingTeamField() returns the ID of the killer.
Hook_APrimalStructure_Destroyed: _this->TargetingTeamField() returns the ID of the killer.
What could be the reason for that? (edited)bool Hook_APrimalStructure_Die(APrimalStructure* _this, float KillingDamage, FDamageEvent* DamageEvent, AController* Killer, AActor* DamageCauser)
{
if (_this->OwningPlayerIDField() == 0) // tribe
{
if (Killer && Killer->IsA(APlayerController::StaticClass())) {
AShooterPlayerController* player = (AShooterPlayerController*)Killer;
int killerTeamId = player->TargetingTeamField();
int structureTeamId = _this->TargetingTeamField();
ArkApi::GetApiUtils().SendChatMessage(player, "TestPlugin", *FString("[Structure Death] StructureTeamId: " + std::to_string(structureTeamId)));
ArkApi::GetApiUtils().SendChatMessage(player, "TestPlugin", *FString("[Structure Death] KillerTeamId: " + std::to_string(killerTeamId)));
}
}
return APrimalStructure_Die_original(_this, KillingDamage, DamageEvent, Killer, DamageCauser);
}APrimalStructureExplosive
Is it good way?
float Hook_APrimalStructure_TakeDamage(APrimalStructure* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (EventInstigator && EventInstigator->IsA(APlayerController::StaticClass())) {
AShooterPlayerController* player = (AShooterPlayerController*)EventInstigator;
APrimalStructure_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
if (_this->HealthField() <= 0) {
// Structure Died
}
// or
if (_this->IsDead()) {
// Structure Died
}
return 0;
}
} APrimalStructure_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);FString getWeaponName(AController* AttackerController)
{
FString WeaponName = "";
AShooterPlayerController* AttackerShooterController = static_cast<AShooterPlayerController*>(AttackerController);
if (AttackerShooterController && AttackerShooterController->PlayerStateField() && AttackerShooterController->GetPlayerCharacter() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField() && AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField())
{
AttackerShooterController->GetPlayerCharacter()->CurrentWeaponField()->AssociatedPrimalItemField()->GetItemName(&WeaponName, false, true, nullptr);
}
return WeaponName;
}void RemoveItem(AShooterPlayerController* controller, UPrimalInventoryComponent* inventoryComp, UPrimalItem* item)
{
FItemNetInfo info;
item->GetItemNetInfo(&info, false);
Log::GetLog()->warn("netinfo collected");
FVector location;
FVector direction;
bool fromCrosshair;
controller->GetPlayerCharacter()->GetCharacterViewLocationAndDirection(&location, &direction, &fromCrosshair, 0);
Log::GetLog()->warn("locationinfo collected");
Log::GetLog()->warn("Attempt a drop");
FRotator r = FRotator(0);
inventoryComp->DropItem(&info, true, &location, &r, false, false, false, true);
Log::GetLog()->warn("Dropped !!!!");
} (edited)bool Hook_APrimalStructure_Die(APrimalStructure* _this, float KillingDamage, FDamageEvent* DamageEvent, AController* Killer, AActor* DamageCauser)
{
if (_this->IsA(APrimalStructureExplosive::GetPrivateStaticClass()))
ArkApi::GetApiUtils().SendChatMessageToAll("TestPlugin", *FString("[Structure Death] APrimalStructureExplosive"));
return APrimalStructure_Die_original(_this, KillingDamage, DamageEvent, Killer, DamageCauser);
} (edited)_this->IsA(APrimalStructureExplosive::GetPrivateStaticClass()) doesn't return true when I use c4 to destroy the structure.static UClass* GetPrivateStaticClass()
"wchar_t" is not requiredFString descr;
DamageCauser->GetHumanReadableName(&descr);
const float C4Multiplier = config["WeaponDamageMultipliers"]["C4DamageMultiplier"];
if (descr.Contains(L"C4")) Damage = Damage * C4Multiplier; (edited)API::Requests::Get().CreateGetRequest(url, callback, GetHeaders());1>ProjectCCC.cpp
1>apiCalls.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: bool __cdecl API::Requests::CreatePostRequest(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class std::function<void __cdecl(bool,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)> const &,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > const &,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > > const &,class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >)" (__imp_?CreatePostRequest@Requests@API@@QEAA_NAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV?$function@$$A6AX_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z@4@AEBV?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@4@2V64@@Z) (edited)DECLARE_HOOK(AShooterPlayerState_NotifyPlayerLeftTribe, void, FString*);
void Hook_AShooterPlayerState_NotifyPlayerLeftTribe(AShooterPlayerState* aShooterPlayerState, FString* ThePlayerName, FString* TribeName)
{
AShooterPlayerState_NotifyPlayerLeftTribe_original(aShooterPlayerState, ThePlayerName, TribeName);
} (edited)#pragma comment(lib,"cpprest141_2_10") to the top of main instead of in the class file. I have checked the references to the directories where the files are. more than that I have no idea. everything compiles, but when loading the plugin, I get error 126. Any ideas ?may we get an update to the ATLAS shop api, its currently broken after mega patch, its no longer logging players in by their steam64 id, its making a random account number and is doing so on every login. im sure permissions may also need an update (edited)the atlas shop plugin is not correctly calculating points. We need a hot fix soon please. (edited)TArray<FCraftingResourceRequirement,FDefaultAllocator> BaseCraftingResourceRequirements; looks like it is thisPrimalItemConsumable_DragonsTongue_C /Game/Atlas/AtlasCoreBP/Items/Recipes/PrimalItemConsumable_DragonsTongue.Default__PrimalItemConsumable_DragonsTongue_C
PrimalItemConsumableEatable_WaterContainer_C 1
PrimalItemConsumable_Vegetable_MaizeOrWheat_C 20
PrimalItemConsumable_Meat_Marrow_C 1
PrimalItemResource_Sap_BASE_C 10
PrimalItemConsumable_Herb_BASE_C 20
PrimalItemConsumable_Berry_Base_C 10
PrimalItemConsumable_Fruit_Lime_C 5
PrimalItemConsumable_Vegetable_Chilli_C 5
PrimalItemConsumable_Vegetable_Beet_C 5 yup Eatable_WaterContainer :triggered:void SpawnSetupDino(FString* DinoBlueprintPath, FString* SaddleBlueprintPath, float SaddleQuality, int DinoLevel, FString* DinoStats, float SpawnDistance, float YOffset, float ZOffset) { NativeCall<void, FString*, FString*, float, int, FString*, float, float, float>(this, "UShooterCheatManager.SpawnSetupDino", DinoBlueprintPath, SaddleBlueprintPath, SaddleQuality, DinoLevel, DinoStats, SpawnDistance, YOffset, ZOffset); }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)
{
UPrimalItem* item = UPrimalInventoryComponent_AddItem_original(_this, theItemInfo, bEquipItem, AddToSlot, bDontStack, InventoryInsertAfterItemID, ShowHUDNotification, bDontRecalcSpoilingTime, bForceIncompleteStacking, OwnerPlayer, bIgnoreAbsoluteMaxInventory);
if (item)
{
FName ItemName = item->NameField();
FString FItemName;
ItemName.ToString(&FItemName);
if (FItemName.Contains("WeaponHandcuffs") && item->bEquippedItem()() == true && item->OwnerInventoryField()->GetOwner())
{
AActor* Actor = item->OwnerInventoryField()->GetOwner();
if (Actor && Actor->IsA(AShooterCharacter::GetPrivateStaticClass()))
{
AShooterCharacter* Character = static_cast<AShooterCharacter*>(Actor);
AddToHandcuffsArray(Character, nullptr);
}
}
}
return item;
}
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNINGGlobals::GetObjectsOfClass? I'm getting very weird crashes when trying to use it. Callstack goes into a hook of different pluginTArray<AActor*> actors = ArkApi::GetApiUtils().GetWorld()->PersistentLevelField()->GetActorsField(); works fine, then just need to find required entities.
I don't use multi-threading in this this pluginGetObjectsOfClass, which returns nothing. GetActorsField returns array by reference, yes.
Other plugin is also my plugin, and it is single-threaded tooGlobals::GetObjectsOfClass static function, but, say, GetActorsField() works fine with the same environment (edited)ACharacter* character = player->GetCharacterField();
APrimalCharacter* primalCharacter = static_cast<APrimalCharacter*>(character);void Hook_AShooterCharacter_StartWeaponSwitch(AShooterCharacter* _this, UPrimalItem* aPrimalItem, bool bDontClearLastWeapon) (edited)FString ItemString;
aPrimalItem->GetFullName(&ItemString, nullptr); (edited)https://wiki.garrysmod.com/page/Global/AccessorFuncnamespace Enum
{
enum class Zone
{ ... }
}
But now I'm getting a lot of enum type errors, for example:
'EPrimalEquipmentType::Type': 'enum' type redefinition
'EPrimalItemStat::Type': 'enum' type redefinition
etc. (a lot more of the same kind)'FItemCraftQueueEntry::ItemID' uses undefined struct 'FItemNetID'[...]APrimalStructure* _this[...]
int tribeId = _this->TargetingTeamField();
if (tribeId >= 50000)
[...]
I get that checking tribeId != 0 so you know there's a tribe involved. But why the 50000 ? (_this could might as well been an AActor*) (edited)float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
[...] <- This area gets triggered
if (Damage != 0)
{
[...] <- Nothing in here ever gets triggered ?
}
} (edited)FString descr;
DamageCauser->GetHumanReadableName(&descr);
if (descr.Contains("Turret"))
{
[...] <- Never triggered
}auto Turrets_array = config["TurretAdjustements"];
APrimalStructure* Structure = static_cast<APrimalStructure*>(DamageCauser);
//APrimalStructureTurret* Turret = static_cast<APrimalStructureTurret*>(DamageCauser);
//if (DamageCauser->IsA(APrimalStructureTurret::ClassField())) Log::GetLog()->warn("Is Turret");
FString NameField = Structure->DescriptiveNameField();
//Log::GetLog()->warn("Turret BP = {}", NameField.ToString());
if (!Turrets_array.empty())
{
for (const auto &Turret : Turrets_array)
{
std::string CheckType = Turret["CheckType"];
std::string SConfigTurretName = Turret["TurretName"];
FString FConfigTurretName = SConfigTurretName.c_str();
std::string DamageAdjustmentType = Turret["DamageAdjustType"];
const float DamageMultiplier = Turret["DamageMultiplier"];
if (DamageAdjustmentType == "All"
|| (DamageAdjustmentType == "Dino" && _this->IsA(APrimalDinoCharacter::GetPrivateStaticClass()))
|| (DamageAdjustmentType == "Player" && _this->IsA(AShooterCharacter::GetPrivateStaticClass())))
{
if ((CheckType == "Contains" && NameField.Contains(FConfigTurretName)) || (CheckType == "Equals" && NameField == FConfigTurretName))
{
Damage = Damage * DamageMultiplier;
}
}
}
}"TurretAdjustements": [{
"CheckType": "Equals",
"TurretName": "Tek Turret+",
"DamageMultiplier": 10,
"DamageAdjustType": "Dino"
},
{
"CheckType": "Equals",
"TurretName": "Tek Turret",
"DamageMultiplier": 10,
"DamageAdjustType": "All"
},
{
"CheckType": "Equals",
"TurretName": "S+ Tek Turret",
"DamageMultiplier": 10,
"DamageAdjustType": "All"
},
{
"CheckType": "Equals",
"TurretName": "Heavy Automated Turret",
"DamageMultiplier": 10,
"DamageAdjustType": "All"
},
{
"CheckType": "Equals",
"TurretName": "S+ Heavy Auto Turret",
"DamageMultiplier": 10,
"DamageAdjustType": "All"
},
{
"CheckType": "Equals",
"TurretName": "Automated Turret",
"DamageMultiplier": 10,
"DamageAdjustType": "All"
},
{
"CheckType": "Equals",
"TurretName": "S+ Automated Turret",
"DamageMultiplier": 10,
"DamageAdjustType": "All"
}
],if (_this && DamageCauser)
{
if (DamageCauser->IsA(APrimalStructure::GetPrivateStaticClass()))// Update player positions
not related to notifications

AutoPluginsReload entry, i searched all the text files inside the server folder and checked out ShooterGame/Config folder and cant seem to find it ?ShooterGame\Binaries\Win64\config.json entry "AutomaticPluginReloading"AShooterGameMode* aShooterGameMode = ArkApi::GetApiUtils().GetShooterGameMode();
I was gonna call it in the Load()-method (DLL_PROCESS_ATTACH), but it returns null ? Is shootergamemode only active from within a player "call" ?ArkApi::GetApiUtils().GetShooterGameMode()->KickPlayerController(who, &FString::Format("Kicked by SALT AC, Reason: {0}", (int)why));FString fPort;
ArkApi::GetApiUtils().GetShooterGameMode()->GetNetworkNumber(&fPort);Hook_AShooterGameMode_InitGame
compress2() (edited)

(edited)UPrimalCharacterStatusComponent* defaultComp = _this->GetDefaultCharacterStatusComponent();Actor.hc++
UPrimalCharacterStatusComponent* GetDefaultCharacterStatusComponent() { return NativeCall<UPrimalCharacterStatusComponent*>(this, "UPrimalCharacterStatusComponent.GetDefaultCharacterStatusComponent"); }GetDefaultObject<T>? (edited)GetDefaultCharacterStatusComponent just gets a new instance of the UPrimalCharacterStatusComponent with default data I believestd::map<long, long> Foo;
Foo.insert(std::pair<long, long>(123, 456));
if (Foo.find(123) != Foo.end())
{
[...] <- shouldnt this be activated if there's a match ?
} (edited)Foo[123] = 456;
looks better btwFoo.emplace(123, 456);Foo.erase(123) first then ?TMap<int32, FString> Map;
Map.Add(teamID, characterName);
is this ok? (edited)Map.Contains(Key) if that helps and worksUPrimalCharacterStatusComponent*Map<long, long> Foo;
Foo[1] = 2;
Foo[2] = 3;
Foo[3] = Foo[3] + 4;
cout << Foo[3};
Will I get a 4 or an error ?libmysql.lib
mysqlclient.lib (edited)'GetOwnerController': is not a member of 'AShooterPlayerState' (edited)AShooterCharacter* player_character = static_cast<AShooterCharacter*>(player_controller->CharacterField());
if (player_character)
{
FString char_name = ArkApi::GetApiUtils().GetCharacterName(player_controller);
uint64 data_id = player_character->GetPlayerData()->MyDataField()->PlayerDataIDField();
if (!char_name.IsEmpty() && data_id > 0)
{
dino_spawn->UpdateImprintingDetails(&char_name, data_id);
dino_spawn->UpdateImprintingQuality(imprint_amount / 100.0f);
}
}
This code works fine but sometimes (it seems that absolutely randomly) causes crashes on dino_spawn->UpdateImprintingDetails(&char_name, data_id);dino_spawn pointer isn't null, I check it aboveUPrimalCharacterStatusComponent* defaultComp = static_cast<UPrimalCharacterStatusComponent*>(static_cast<UClass*>(_this)->GetDefaultObject(true));UPrimalCharacterStatusComponent is a child of UActorComponentUPrimalCharacterStatusComponent* defaultComp = static_cast<UPrimalCharacterStatusComponent*>(_this->ClassField()->GetDefaultObject(true));FPrimalCharacterStatusValueDefinition structstruct AAA { ... };
struct BBB { ... };
struct CCC { ... };
Instead of needing these:
std::vector<AAA> db_callback_AAA(...) { ... };
std::vector<BBB> db_callback_BBB(...) { ... };
std::vector<CCC> db_callback_CCC(...) { ... };
I would like just one:
std::vector<T> db_callback(...) { ... };
It's probably called something fancy and thats why i cant find it on google... ? (edited)template<typename T>
FORCEINLINE static TWeakObjectPtr<const T> ToWeak(const T* object)
{
return TWeakObjectPtr<const T>(object);
};
TWeakObjectPtr<const UPrimalInventoryComponent> a = ToWeak<UPrimalInventoryComponent>(comp);
who->RemoteViewingInventoriesField().AddUnique(a);struct FPrimalPlayerCharacterConfigStructReplicated
{
uint8 bIsFemale : 1;
FLinearColor BodyColors[4];
FString PlayerCharacterName;
float RawBoneModifiers[22];
int32 PlayerSpawnRegionIndex;
};FPrimalPlayerCharacterConfigStruct * operator=(FPrimalPlayerCharacterConfigStruct * __that) { return NativeCall<FPrimalPlayerCharacterConfigStruct *, FPrimalPlayerCharacterConfigStruct *>(this, "FPrimalPlayerCharacterConfigStruct.operator=", __that); }
static UScriptStruct * StaticStruct() { return NativeCall<UScriptStruct *>(nullptr, "FPrimalPlayerCharacterConfigStruct.StaticStruct"); }
void FScriptStruct_ShooterGame_StaticRegisterNativesFPrimalPlayerCharacterConfigStruct() { NativeCall<void>(this, "FPrimalPlayerCharacterConfigStruct.FScriptStruct_ShooterGame_StaticRegisterNativesFPrimalPlayerCharacterConfigStruct"); }
you need this?FPrimalPlayerCharacterConfigStruct * GetPlayerCharacterConfig(FPrimalPlayerCharacterConfigStruct * result) { return NativeCall<FPrimalPlayerCharacterConfigStruct *, FPrimalPlayerCharacterConfigStruct *>(this, "FPrimalPlayerCharacterConfigStructReplicated.GetPlayerCharacterConfig", result); }
static UScriptStruct * StaticStruct() { return NativeCall<UScriptStruct *>(nullptr, "FPrimalPlayerCharacterConfigStructReplicated.StaticStruct"); }
FPrimalPlayerCharacterConfigStructReplicated * operator=(FPrimalPlayerCharacterConfigStructReplicated * __that) { return NativeCall<FPrimalPlayerCharacterConfigStructReplicated *, FPrimalPlayerCharacterConfigStructReplicated *>(this, "FPrimalPlayerCharacterConfigStructReplicated.operator=", __that); }
void OnRep_MountedDino()if (ArkApi::GetApiUtils().IsRidingDino(AttackerShooterController))
{
auto character = AttackerShooterController->GetPlayerCharacter();
auto dino = character->GetRidingDino();
if (dino)
dino->ServerClearRider_Implementation(0);
} (edited)NewPlayer->NetConnectionField()->bSharedConnectionField()_this->bIsBossDino()() == true_this->bIsBossDino() = falseif (PlayerNetConnection->bSharedConnectionField()() == true)bool& bSharedConnectionField() { return *GetNativePointerField<bool*>(this, "UNetConnection.bSharedConnection"); }bool& bSharedConnectionField() { return *GetNativePointerField<bool*>(this, "UNetConnection.bSharedConnection"); }UPrimalInventoryComponent* inventoryComponent = [...]
UPrimalItem* item = [...]
item->AddToInventory(inventoryComponent, false, false, nullptr, false, true, false);
It doesnt put anything in the inventory. InventoryComponent is based on APrimalStructureItemContainer->MyInventoryComponentField().m_SteamID != m_OwnerSteamID (edited)void ShooterGameModeHooks::Hook_AShooterGameMode_PostLogin(AShooterPlayerState* _this, APlayerController* NewPlayer)
{
AShooterGameMode_PostLogin_original(NewPlayer); return;
}} for the sake of having it be "complete" in the sample)AShooterGameMode_IsPlayerAllowedToJoinNoCheck is oneAActor* actor = player_controller->GetPlayerCharacter()->GetAimedActor
const long double nNow = ArkApi::GetApiUtils().GetWorld()->GetTimeSeconds();
class "UWrold" has no member "GetTimeSeconds"ArkApi::GetApiUtils().GetWorld()->GetTimeSeconds(); does not work for you?NewPlayer->GetActorForwardVector(nullptr); induce a crashGetActorForwardVector in one line?FVector* GetZero()
{
auto a = FVector{ 0,0,0 };
return &a;
}
FVector* myFWD = NewPlayer->GetActorForwardVector(GetZero());GetZero returnedFVector myFWD;
NewPlayer->GetActorForwardVector(&myFWD);
looks fine for meauto myFWD = NewPlayer->GetActorForwardVector()FVector* myFwd = NewPlayer->GetActorForwardVector(calloc(1, sizeof(FVector)));
not clean thoughFVector myFWD;NewPlayer->GetActorForwardVector(&myFWD);
[API][warning] (API::PluginManager::LoadAllPlugins) Plugin Release does not exist (edited)
love evolved event for custom servers ?-activeevent option-activeevent setSendServerDirectMessage
SendServerChatMessage
SendServerNotification (edited)
FString inventoryName;
inventoryComponent->GetInventoryName(&inventoryName, false);
Log::GetLog()->info(*inventoryName);` (edited)'fmt::BasicWriter<char>::operator <<': cannot access private member declared in class 'fmt::BasicWriter<char>' (edited)ULevel uLevel;
TArray<AActor*> actors = uLevel.GetActorsField();
Im guessing I somehow need to instantiate uLevel ?UWorld* uWorld = ArkApi::GetApiUtils().GetWorld();
TArray<ULevel*> uLevels = (*uWorld).LevelsField();
for (ULevel* uLevel : uLevels)
{
TArray<AActor*> actors = uLevel->GetActorsField();
for (AActor* actor : actors)
{
[...]
}
}
But on the 2nd itertion of uLevel the uLevel->GetActorsField(); throws an error. any idsea why ?UGameplayStatics::GetAllActorsOfClass(world, APrimalStructure::GetPrivateStaticClass(), &FoundActors);UWorld* world = ArkApi::GetApiUtils().GetWorld();item->MaxItemQuantityField() = 1000;
item->BaseItemWeightField() = 0.01f;
item->InventoryRefreshCheckItem();
item->UpdatedItem(false);
It updates the max quantity but not the weight. any1 knows what to call to change an items base weight ?config.json file. Since this field doesn't exist in all items my code will generate an error when it does not exist. Surely there must be a better way to deal with it than my way.. se pic. (edited)std::string GetSetting_string(const std::string& str)
{
return Foo::config["Settings"].value(str, "");
}const int tribe_id = game_mode->GetTribeIDOfPlayerID(player_id);
I need to pull the tribe name instead, i've looked threw gamemode.h and didn't find it. Is the tribename just as easy? What am i missing?FString GetTribeName(AShooterPlayerController* playerController)
{
std::string tribeName;
auto playerState = reinterpret_cast<AShooterPlayerState*>(playerController->PlayerStateField());
if (playerState)
{
auto tribeData = playerState->MyTribeDataField();
tribeName = tribeData->TribeNameField().ToString();
}
return tribeName.c_str();
} (edited)FNetControlMessage isFNetControlMessage<6>.Send<> to specific overrides in C++?FnetControlMessage<NMT_Failure>::Send -> { NativeCall<void, UNetConnection*, FString*>(nullptr, "FNetControlMessage<6>.Send", Conn, ParamA); }<> instead of an actual parameterint value"FNetControlMessage<6>.Send""FNetControlMessage<The Templated Value>.Send"c++
RT NativeCall(nullptr_t, const std::string& funcName, Args&&... args)
{
return static_cast<RT(__fastcall*)(ArgsTypes ...)>(GetAddress(funcName))(std::forward<Args>(args)...);
}GetAddress?item->ItemStatValuesField()()[7] = 1000.f;
like thisGenericQuality = 0x0,
Armor = 0x1,
MaxDurability = 0x2,
WeaponDamagePercent = 0x3,
WeaponClipAmmo = 0x4,
HypothermalInsulation = 0x5,
Weight = 0x6,
HyperthermalInsulation = 0x7,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
}item->ItemStatValuesField()()[item_stat_type]
is better than doing pointer arithmetic?*(item->ItemStatValuesField()() + 0x6) *= 0.5f;
didnt work. now trying
item->ItemStatValuesField()()[6] = 0.1f; TArray<AActor*> OutActors;
UVictoryCore::ServerOctreeOverlapActors(
&OutActors,
ArkApi::GetApiUtils().GetWorld(),
ArkApi::GetApiUtils().GetPosition(shooter_controller),
5000.0f,
EServerOctreeGroup::STRUCTURES,
false
);
for (auto&& actor : OutActors)
{
if (!actor->IsA(APrimalStructureTurret::GetPrivateStaticClass()))
continue;
} (edited) if (!actor->IsA(APrimalStructureTurret::GetPrivateStaticClass()))
continue; there's no crashtemplate <typename T>
class NextConfig
{
static T* instance;
public:
static T& Get();
};
template <typename T>
T* NextConfig<T>::instance;
template <typename T>
T& NextConfig<T>::Get()
{
if (instance == nullptr) { instance = new T(); }
return *instance;
}
class BaseConfig
{
std::string Filename;
json data;
protected:
json Value(); //raw json object
public:
void Init(std::string FileName);
void Reload();
virtual void Load();
};
class ConfigBody : public BaseConfig //the thing to load from disk
{
private:
static FString kickmessage;
static std::vector<uint64> whitelist;
public:
void Load();
FString KickMessage();
bool WhiteListed(uint64 steamID);
};NextConfig<ConfigBody>::Get().Init("/ArkApi/Plugins/AntiFamilyShare/config.json");
...
&NextConfig<ConfigBody>::Get().KickMessage()ConfigBody would be the custom "config" type the user would supply and they would override Load to map the valuesvoid ConfigBody::Load()
{
//Create mappings here
__super::Load();
kickmessage = FString(ArkApi::Tools::Utf8Decode(__super::Value()["Message"]));
whitelist = __super::Value()["Whitelist"].get<std::vector<uint64>>();
std::string steamIDs = "";
for (auto steamID : whitelist) { steamIDs += steamID + ", "; }
steamIDs = steamIDs.substr(0, steamIDs.length() - 2);
Log::GetLog()->debug("[Config Values] Kick Message: " + kickmessage.ToString());
Log::GetLog()->debug("[Config Values] Whitelist: " + steamIDs);
}// MAC SHIT#include <Timer.h>

AController *controller = _this->ControllerField();ArkApi::GetApiUtils().GetSteamIdFromController(_this->GetOwnerController());auto PC = _this->GetOwnerController();
if (PC)
{
ArkApi::GetApiUtils().GetSteamIdFromController(PC);
} (edited)if ((_this->GetOwnerController() != nullptr)) {
Log::GetLog()->warn("getOwnerController worked?");
}UPrimalInventoryComponent* inventoryComponent = player->GetPlayerCharacter()->MyInventoryComponentField()
inventoryComponent->MaxInventoryItemsField() -> -1
inventoryComponent->InventoryItemsField().Num() -> 225
inventoryComponent->ItemSlotsField().Num() -> 10
inventoryComponent->NumSlotsField() -> 10
Im only using 1 slot. player is a shooter player controller.FString MapName;
ArkApi::GetApiUtils().GetShooterGameMode()->GetMapName(&MapName);
MapName = MapName.Replace(L"_P", L"");FString MapName;
ArkApi::GetApiUtils().GetShooterGameMode()->GetMapName(&MapName);
MapName = MapName.Replace(L"_P", L"");
Log::GetLog()->info("The name of the map is {}", MapName);
Tosses out a error Error C2338 Cannot format argument. To enable the use of ostream operator<< include fmt/ostream.h. Otherwise provide an overload of format_arg this has happened a few times before so what would a correct version on the console logging look like ? 
Log::GetLog()->info("The name of the map is {}", MapName.ToString());long or other types as so in c++long varies in lengthlong long (edited)int64 and uint64, instead of worring to use unsigned long long or unsigned longunordered_map looks to be the fastest with O(1) (edited)map is always O(log n) public void insert(T a)
{
if (isFull())
Grow();
int i = 0;
for(; i < count; i++)
{
contents[count-i] = contents[count-1-i];
if (a.compareTo(contents[count-i]) < 0) {break;}
}
contents[count++-i] = a;
}
public T remove() {
T t = contents[--count];contents[count] = null;
if (isOversized())
Shrink();
return t;
} public void push(T a)
{
if (isFull())
Grow();
contents[count++] = a;
}
public T pop() {
T t = contents[--count];contents[count] = null;
if (isOversized())
Shrink();
return t;
}Collection base class protected void Grow() { Resize(capacity<<=1); }
protected void Shrink() { Resize(capacity>>=1); }
private void Resize(int size)
{
T[] next = newArray(size);
Arrays.CopyTo(contents, 0, next, 0, count);
contents = next;
}Arrays is also another class I wrotepublic T[] Create(int length) { return (T[]) new Object[length]; }'FMicrosoftPlatformString::Stricmp': none of the 2 overloads could convert all the argument types
I'm using VS and that is all I'm getting. It points to the FString.h at line 1010 but that's it. I'm getting that it's probably an FString compare somewhere, but I have dozens of those. Any1 know how I can narrow this one down ?struct Foo
{
uint64 A;
uint64 B;
};
void SomeOtherName(Foo* _bar)
{
_bar = &{ 456, 789 };
}
void main_here()
{
Foo* bar = new Foo{};
(bar->A) = 123;
SomeOtherName(bar);
cout << bar->B;
}
It compiles fine, but output is 0 where I was expecting 789 ?? (edited)malloc are used. (edited)x and do x = malloc .... and then later do x = whatever, without clearing the previously allocated memory, it will remain used, with no reference to where it isvoid SomeOtherName(Foo* _bar)
{
_bar = &{ 456, 789 };
}void SomeOtherName(Foo* _bar)
{
_bar.A = 456;
_bar.B = 789;
}Foo was a struct @Michidu.field syntaxPriority<Country>[] queues = (Priority<Country>[]) new Priority<?>[5]; ? ?? public static async Task GetAsync(string file, string dest)
{
using (Stream writeTo = System.IO.File.OpenWrite(dest))
using (Stream readFrom = await IO.File.GetAllAsync(file))
{
await readFrom.CopyToAsync(writeTo);
}
} public static void Get(string file, string dest) => GetAsync(file, dest).GetAwaiter().GetResult();commandMap.Add($"{owner.PluginName()}.{name}", callback);private Dictionary<string, Func<PluginManager, string[], bool>> commandMap = new Dictionary<string, Func<PluginManager, string[], bool>>();PreLogin to see if people can even get that far once the server enters the it's weird state but then every time u restart, it will reset that timer
the timer is not the problem at allAllActors Call During Gameplay:...-spam. Classic Flyershaving serious problems. (edited)GetShooterControllerGetOwnerController() and cast?FNetControl::Send needs to be implemented in a way to be called.DEFINE_CONTROL_CHANNEL_MESSAGE(Hello, 0, uint8, uint32, FString); // initial client connection message
DEFINE_CONTROL_CHANNEL_MESSAGE(Welcome, 1, FString, FString, FString); // server tells client they're ok'ed to load the server's level
DEFINE_CONTROL_CHANNEL_MESSAGE(Upgrade, 2, uint32); // server tells client their version is incompatible#define DEFINE_CONTROL_CHANNEL_MESSAGE_ZEROPARAM(Name, Index) \
enum { NMT_##Name = Index }; \
template<> class FNetControlMessage<Index> \
{ \
public: \
static uint8 Initialize() \
{ \
} \
/** sends a message of this type on the specified connection's control channel */ \
static void Send(UNetConnection* Conn) \
{ \
} \
};
#define DEFINE_CONTROL_CHANNEL_MESSAGE_ONEPARAM(Name, Index, TypeA) \
enum { NMT_##Name = Index }; \
template<> class FNetControlMessage<Index> \
{ \
public: \
static uint8 Initialize() \
{ \
} \
static void Send(UNetConnection* Conn, TypeA& ParamA) \
{ \
NativeCall<void, UNetConnection*, TypeA>(nullptr, "FNetControlMessage<" + std::to_string(Index) + ">.Send", Conn, ParamA); \
} \
};DEFINE_CONTROL_CHANNEL_MESSAGE_ONEPARAM(Failure, 6, FString);FNetControlMessage<NMT_Failure>::Send(PlayerNetConnection, NextConfig<ConfigBody>::Get().KickMessage());#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) \
{ \
static_assert(Index < FNetControlMessageInfo::MaxNames, "Control channel message must be a byte."); \
checkSlow(!Conn->IsA(UChildConnection::StaticClass())); /** control channel messages can only be sent on the parent connection */ \
if (Conn->Channels[0] != NULL && !Conn->Channels[0]->Closing) \
{ \
FControlChannelOutBunch Bunch(Conn->Channels[0], false); \
uint8 MessageType = Index; \
Bunch << MessageType; \
FNetControlMessageInfo::SendParams(Bunch, Params...); \
Conn->Channels[0]->SendBunch(&Bunch, true); \
} \
} \
};NativeCall<void, UNetConnection*, TypeA>(nullptr, "FNetControlMessage<" + std::to_string(Index) + ">.Send", Conn, ParamA); \ "FNetControlMessage<" + std::to_string(Index) + ">.Send" a compile time constDEFINE_CONTROL_CHANNEL_MESSAGE_ONEPARAM(Failure, 6, FString);#define DEFINE_CONTROL_CHANNEL_MESSAGE_ONEPARAM(Name, Index, TypeA) \
enum { NMT_##Name = Index }; \
template<> class FNetControlMessage<Index> \
{ \
public: \
static void Send(UNetConnection* Conn, TypeA& ParamA) \
{ \
NativeCall<void, UNetConnection*, TypeA>(nullptr, "FNetControlMessage<" #Index ">.Send", Conn, ParamA); \
} \
};defeatboss command#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...); \
} \
};FNetControlMessage<NMT_Failure>::Send(PlayerNetConnection, NextConfig<ConfigBody>::Get().KickMessage());APrimalDinoCharacter* _this) _this->NameField().ToString(&ClassName); returns Allo_Character_BP_C_52 instead of just Allo_Character_BP ? (edited)
_C_ remove everything after that/**
* @brief Get the Entity ID of a given dino
* @param dino The dino to fetch the Entity ID of
**/
FString GetDinoEntityID(APrimalDinoCharacter* dino)
{
FString entityID;
dino->NameField().ToString(&entityID);
int startPos = entityID.Find("_C_");
if (startPos != -1);
{
return entityID.Left(startPos + 2); // +2 is the _C string from the match
}
return entityID;
}print hello world
hello worldUKismetSystemLibrary::SphereOverlapActors_NEW() (edited)UVictoryCore::SphereOverlapFastconst int MinFoundations = config["FireBreathFix"]["MinimumEnemyStructureDistanceInFoundations"];
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>((MinFoundations * 300)), &types,
APrimalStructure::GetPrivateStaticClass(), &actors_ignore,
&new_actors);TArray<TEnumAsByte<enum EObjectTypeQuery>> types
what is this?&types,
APrimalStructure::GetPrivateStaticClass(), &actors_ignore,
&new_actorsUKismetSystemLibrary::SphereOverlapActors_NEW(world, _this->RootComponentField()->RelativeLocationField(), static_cast<float>((MinFoundations * 300)), &types,APrimalStructure::GetPrivateStaticClass(), &actors_ignore, &new_actors);/protection set - Sets the location of your PvE base
/protection get - Checks if your inside your protection areaArkApi::GetCommands().AddChatCommand
when this adds a command, is it automatically after a /? (pos.x-x)^2 + (pos.y-y)^2+(pos.z-z)^2<radius^2) may be faster.player.TargetingTeamField() would work?asdf.field in c++->ISafeZoneManager.herror LNK2001: unresolved external symbol "class SafeZones::ISafeZoneManager & __cdecl SafeZones::GetSafeZoneManager(void)" (?GetSafeZoneManager@SafeZones@@YAAEAVISafeZoneManager@1@XZ)
1>C:\Users\????\source\repos\ForcedArkPlugin\x64\Release\ForcedBaseProtection.dll : fatal error LNK1120: 1 unresolved externalsC:\Users\????\Desktop\Ark Plugin Dev\ARK-Server-API-master\out_lib\ArkApi.lib
C:\Users\????\Desktop\Ark Plugin Dev\SafeZone\x64\Release\SafeZone.lib (edited)C:\Users\????\Desktop\Ark Plugin Dev\SafeZone\SafeZone\Public
C:\Users\????\Desktop\Ark Plugin Dev\ARK-Server-API-master\version\Core\Public (edited)player->ShowTribeManager()
does this get the tribe leader?DECLARE_HOOK(AShooterGameMode_GetOrLoadTribeData, bool, AShooterGameMode*, int, FTribeData*);
void AShooterGameMode_GetOrLoadTribeData(AShooterGameMode* _this, int TribeID, FTribeData* LoadedTribeData) {
uint64 tribeLeaderID = LoadedTribeData->OwnerPlayerDataIDField();
AShooterGameMode_GetOrLoadTribeData_original(_this, TribeID, LoadedTribeData);
}
void Load() {
ArkApi::GetHooks().SetHook("AShooterGameMode.GetOrLoadTribeData", &Hook_AShooterGameMode_GetOrLoadTribeData, &AShooterGameMode_GetOrLoadTribeData_original);
}
void Unload() {
ArkApi::GetHooks().DisableHook("AShooterGameMode.GetOrLoadTribeData", &Hook_AShooterGameMode_GetOrLoadTribeData);
} (edited)AShooterPlayerController* player;
AShooterPlayerState* State = static_cast<AShooterPlayerState*>(player->PlayerStateField());
FTribeData* tribeData = State->MyTribeDataField();
uint64 tribeLeaderID = tribeData->OwnerPlayerDataIDField(); (edited)c++
FString tribe_name = tribeData->TribeNameField();Log::GetLog()->info(tribe_name.ToString());c++
if (player->PlayerStateField()->PlayerIdField() == tribeLeaderID) {AShooterPlayerState* State = static_cast<AShooterPlayerState*>(player->PlayerStateField());
State->IsTribeAdmin();State->IsTribeOwner(State->PlayerIdField());GetPrivateStaticClassAPrimalStructureTurret does notPrimalStructureXXYY classes have the function too.GetPrivateStaticClassBody@VAPrimalStructureTurret if (a->IsA(APrimalStructureTurret::GetPrivateStaticClass()))
{
//we found it
Log::GetLog()->debug("Found Turret");
}c++
std::vector<std::vector<std::string>> GetAllProtectionZones() override
{
std::vector<std::vector<std::string>> protection_zones;
try
{
db_ << "select tribe_id,position_x,position_y,position_z,last_updated from protection_zone;"
>> [&](std::string tribe_id, float position_x, float position_y, float position_z, std::string last_updated) {
std::vector<std::string> protection_zone = { tribe_id, std::to_string(position_x), std::to_string(position_y), std::to_string(position_z), last_updated};
protection_zones.push_back(protection_zone);
};
return protection_zones;
}
catch (const sqlite::sqlite_exception & exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
return protection_zones;
}
}
?


C++ is experiencing a renaissance because power is king again. Languages like Java and C# are good when programmer productivity is important, but they show their limitations when power and performance are paramount. For high efficiency and power, especially on devices that have limited hardware, nothing beats modern C++.
by Microsoft
might give you some motivation heh./configure && make && sudo make installC:\Users\????\Desktop\Ark Plugin Dev\Permissions\Permissions\Public
C:\Users\????\Desktop\Ark Plugin Dev\ARK-Server-API-master\version\Core\Public
C:\Users\????\source\repos\ForcedBaseProtection\ForcedBaseProtection\DataBase
C:\Users\????\source\repos\ForcedBaseProtection\ForcedBaseProtection\hdr

Log::GetLog()->debug(msg); supposed to print to the server console? (edited)c++
player->RootComponentField()->RelativeLocationField()API::Timer::Get().DelayExecute(&CallBack, 120);FTribeData tribeData;
ArkApi::GetApiUtils().GetShooterGameMode()->GetOrLoadTribeData(123, &tribeData); (edited)FTribeData* tribeData;
ArkApi::GetApiUtils().GetShooterGameMode()->GetOrLoadTribeData(123, tribeData);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);void*template<typename... args>
class UE4FunctionParameters
{
public:
std::tuple<args &...> params;
};
#define DEFINE_UE4_Function_Parameters(name, ...) \
class name : public UE4FunctionParameters<__VA_ARGS__> { };DEFINE_UE4_Function_Parameters(LoadedWorld, UWorld*); LoadedWorld* myParameters;
std::get<UWorld*>((*myParameters).params);bool* stopFunc = false;
void MyFunc(bool* stopFunc)
{
if (!stopFunc)
{
[... do something...]
API::Timer::Get().DelayExecute(&MyFunc, 30, stopFunc);
}
}
API::Timer::Get().DelayExecute(&MyFunc, 30, stopFunc);
[... do something for some time...]
stopFunc = true; (edited)stopFunc points to a bool pointerif (!(*stopFunc))
my func is waiting on the inner my func which is waiting on its inner my funcvoid Hook_AShooterGameMode_InitGame(AShooterGameMode* a_shooter_game_mode, FString* map_name, FString* options, FString* error_message)
{
AShooterGameMode_InitGame_original(a_shooter_game_mode, map_name, options, error_message);
// do stuff here
} (edited)
c++
ArkApi::GetApiUtils().SendChatMessage(player, "ForcedBaseProtection", FString::Format("Base protection on cooldown {0} seconds remaining.", FString::FromInt(secondsLeft)));c++
std::string narrow_string("");
std::wstring wide_string = std::wstring(narrow_string.begin(), narrow_string.end());
const wchar_t* result = wide_string.c_str();ArkApi::GetApiUtils().SendChatMessage(asdf, "ForcedBaseProtection", *FString("Base protection on cooldown {0} seconds remaining."), secondsLeft);ArkApi::GetApiUtils().SendChatMessage(asdf, "ForcedBaseProtection", "Base protection on cooldown {0} seconds remaining.", secondsLeft);char* const T* msgTT is a type that is supplied by the template template <typename T, typename... Args>
void SendChatMessage(AShooterPlayerController* player_controller, const FString& sender_name, const T* msg,
Args&&... args)
{
if (player_controller)
{
const FString text(FString::Format(msg, std::forward<Args>(args)...));
FChatMessage chat_message = FChatMessage();
chat_message.SenderName = sender_name;
chat_message.Message = text;
player_controller->ClientChatMessage(chat_message);
}
}c++
API::Timer::Get().DelayExecute(&ActivateSafeZone, secondsLeft);int * to intAPI::Timer::Get().DelayExecute(&ActivateSafeZone, *secondsLeft); (edited)c++
int secondsLeft = config["SafeZoneActivationDelayInSeconds"];
API::Timer::Get().DelayExecute(&ActivateSafeZone, *secondsLeft);this json config;
int secondsLeft = config["SafeZoneActivationDelayInSeconds"];
API::Timer::Get().DelayExecute(asdf, secondsLeft);static void asdf() {}c++
static void ActivateSafeZone(AShooterPlayerController* player) {
AShooterPlayerState* State = static_cast<AShooterPlayerState*>(player->PlayerStateField());
FTribeData* tribeData = State->MyTribeDataField();
int tribeid = tribeData->TribeIDField();
const auto& zone = SafeZoneManager::Get().FindZoneByName(FString::FromInt(tribeid));
if (!zone) {
zone->active = true;
cooldowns.Add(tribeid, std::chrono::system_clock::now());
if (player != nullptr) {
ArkApi::GetApiUtils().SendChatMessage(player, "ForcedBaseProtection", "Base protection has activated.");
}
}
}
int secondsLeft = config["SafeZoneActivationDelayInSeconds"];
API::Timer::Get().DelayExecute(ActivateSafeZone, secondsLeft);static void ActivateSafeZone(AShooterPlayerController* player) {
//stubbed code.
}
void HandleEvent(AShooterPlayerController* player)
{
json config = {}; //stub
int secondsLeft = config["SafeZoneActivationDelayInSeconds"];
API::Timer::Get().DelayExecute(ActivateSafeZone, secondsLeft, player);
}c++
API::Timer::Get().DelayExecute(&ActivateSafeZone, secondsLeft, player);() is a pointerc++
void DelayedMessage(AShooterPlayerController* new_player)
{
if (new_player)
{
ArkApi::GetApiUtils().SendNotification(new_player, FColorList::Green, 2.0f, 15.0f, NULL, L"Hello player!");
}
}
[...]
API::Timer::Get().DelayExecute(&DelayedMessage, 30, new_player);_this parameterc++
*FString("Base protection will activate in {0} seconds."), std::to_string(secondsLeft) potentially be the cause of an error?ArkApi::GetApiUtils().SendChatMessage(asdf, "ForcedBaseProtection", "Base protection on cooldown {0} seconds remaining.", secondsLeft); template <typename T, typename... Args>
void SendChatMessage(AShooterPlayerController* player_controller, const FString& sender_name, const T* msg,
Args&&... args)
{
if (player_controller)
{
const FString text(FString::Format(msg, std::forward<Args>(args)...));
FChatMessage chat_message = FChatMessage();
chat_message.SenderName = sender_name;
chat_message.Message = text;
player_controller->ClientChatMessage(chat_message);
}
}char* -> FString (edited)FNetControlMessage<NMT_Failure>::Send(PlayerNetConnection, NextConfig<ConfigBody>::Get().KickMessage());FNetControlMessage (edited)_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING#define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNINGc++
if(player){} would work right?c++
FString command = L"some text";
std::wstring_convert<std::codecvt_utf16<char16_t>> converter;
uint32 commandSize = command.Len();
TArray<uint8> commandData;
commandData.AddUninitialized(commandSize);
std::wstring wcmd = converter.from_bytes(StringToBytes(command, commandData.GetData(), commandSize));
SQLWCHAR* cmd = (SQLWCHAR*)wcmd.c_str();
I'm trying to convert an FString into SQLWCHAR. I get this error:
'std::codecvt_base::result std::codecvt<char16_t,char,mbstate_t>::in(mbstate_t &,const char *,const char *,const char *&,char16_t *,char16_t *,char16_t *&) const': cannot convert argument 5 from '_Elem *' to 'char16_t *'callback(bool* isHandled)void*void callback(void* _this, int* myGuy, bool* otherGuy)
{
printf("got my data :), %d %d", *myGuy, *otherGuy);
}
void functionCalled(void* _this, void* param1, void* param2)
{
((void(*)(void*, void*, void*))callback)(_this, param1, param2);
}
int main()
{
int a = 20;
bool b = true;
functionCalled(nullptr, &a, &b);
}
void callback(void* _this, int* myGuy, bool* otherGuy)
{
printf("got my data :), %d %d", *myGuy, *otherGuy);
}
void functionCalled(void* _this, void* param1, void* param2)
{
void* data[] = { _this, param1, param2 };
((void(*)(void**))callback)(data);
}
int main()
{
int a = 20;
bool b = true;
functionCalled(nullptr, &a, &b);
}((void(*)(void**))callback)(data);
that line is kinda awful to read...void callback(void* _this, int myGuy, bool otherGuy)
{
printf("got my data :), %d %d", myGuy, otherGuy);
}
void functionCalled(void* data...)
{
((void(*)(void**))callback)(&data);
}
int main()
{
functionCalled(nullptr, 20, true);
}
void callback(void* _this, int myGuy, int otherGuy)
{
printf("got my data :), %d %d\n", myGuy, otherGuy);
}
void functionCalled(void* data...)
{
((void(*)(void**))callback)(&data);
}
int main()
{
functionCalled(nullptr, 27, 58);
}
does properly send the args from the """hook""" to the callback.
player->bIsAdmin() = true;
player->bCheatPlayer() = true;
player->ConsoleCommand(&res, &bluep, true); (edited)int killerTeam = EventInstigator->TargetingTeamField(); (edited)API::Timer::Get().RecurringExecute(...)
after a while the server crashes. takes down all maps at once. this is the only thing implemented after that started happening (along side other code ofc, but this is the only "new"-ish code added, i havnt used be4)API::Timer::Get().RecurringExecute(...) just executes the function over and over it'd be pretty hard to cause a memory leak with this 
magnet:?xt=urn:btih:169DFE1E10161FFA82B786BF89F05AEA6BCD4510&tr=http%3A%2F%2Fbt2.t-ru.org%2Fann%3Fmagnet&dn=IDA%20Pro%207.0.170914%20WIN%5CMAC%20x64%20%2B%20Hex-Rays%20Decompilers%20(x86%2C%20x64%2C%20ARM%2C%20ARM64)%20%5B2017%2C%20ENG%5D std::wstring arg = cmd.substr(wcslen(L"settime "));
int idx = arg.find(L":");
if (idx != std::string::npos)
{
int hours = _wtoi(arg.substr(0, idx).c_str());
int minutes = _wtoi(arg.substr(idx + 1, arg.size() - 1).c_str());
float seconds = hours * 3600.0f + minutes * 60.0f;
sdk::TAActorArray OutActors;
GetGameplayStatics().GetAllActorsOfClass(GetWorld(), sdk::AMatineeActor::StaticClass(), &OutActors);
for (auto&& Actor : OutActors)
{
auto Matinee = (sdk::AMatineeActor*)Actor;
if (Matinee->bForceStartPos && Matinee->bIsGameplayRelevant && Matinee->bPlayOnLevelLoad && Matinee->bLooping && Matinee->bDedicatedServerUpdateInterpolations)
{
Matinee->SetPosition((seconds / 86400.0f) * Matinee->MatineeData->InterpLength, false, false, false);
}
}
} and that''s how you'd set the time of day using c++__fastcall? The hook generator program doesn't include it, but I'm getting compile errors when trying to build because of it.__fastcallLoad():
Log::GetLog()->info("Your plugin has been loaded there, bud!");
Is it not possible to log things in the Load() function?Log::Get().Init("PLUGIN NAME HERE");Get() versus GetLog()? Is there documentation on the logger anywhere?c++
UPrimalItem* item = playerController->GetInventoryUISelectedItemRemote();
But it crashes every time ? (edited)FItemNetID& LastEquipedItemNetIDField() { return *GetNativePointerField<FItemNetID*>(this, "AShooterPlayerController.LastEquipedItemNetID"); }bool Hook_APrimalStructureItemContainer_TryMultiUse(APrimalStructureItemContainer* _this, APlayerController* ForPC, int UseIndex)API::Requests::Get().CreatePostRequest(url, std::bind(&GetResult, placeholders::_1, placeholders::_2), message, headers);
void GetResult(bool success, string response)
{
cout << "success: " << success << endl;
cout << "response: " << response << endl;
cout << "responseLength: " << response.length() << endl;
}
This Post Request sometimes gives a success=1 and response={"message": "400: Bad Request", "code": 0}
However when response contains information like this I want to retry the Post that was called from inside the AddToTribeLog Hook. It seems like the first time I do a Post Request after starting the server I get back this response so trying to find a workaround so events aren't missed.
For instance if I start the server and kill myself the event will be missed. But if I immediately respawn and kill myself again the event is sent properly along with all other events I do. Any ideas?void BPDoHarvestAttack(int harvestIndex) { NativeCall<void, int>(this, "APrimalDinoCharacter.BPDoHarvestAttack", harvestIndex); }float Hook_APrimalStructure_TakeDamage(APrimalStructure* _this, float Damage, FDamageEvent* DamageEvent,
AController* EventInstigator, AActor* DamageCauser)
Does the EventInstigator point to the user of the c4?
I'm having an issue where I'm using the EventInstigator, eventually casting it as a player controller and using that team field to update the damaged structures to join the EventInstigator's team. This works fine with rockets, tek rifles, swords, but does not work for c4. It causes server crash. I haven't tried grenades just yet. (edited)if (DamageCauser)
{
FString descr;
DamageCauser->GetHumanReadableName(&descr);
FString StructureDescr;
_this->GetHumanReadableName(&StructureDescr);
const float C4Multiplier = config["WeaponDamageMultipliers"]["C4DamageMultiplier"];
if (descr.Contains(L"C4")) Damage = Damage * C4Multiplier;
else if (!StructureDescr.Contains("C4") && descr.Contains(L"Turret"))return 0;
} (edited)DamageCauser->OwnerField()DamageCauser->GetOwnerController()float damagecap = _this->GetHealth() - 1;
FString desc;
DamageCauser->GetHumanReadableName(&desc);
if (!desc.Contains("C4"))
{
//This section works when i use rockets/tek rifle
SafeZoneManager::Get().CaptureBaseFromController(_this, EventInstigator);
}
else
{
//When C4 is used, I believe I am arriving here, but it is crashing.
AController* player = DamageCauser->GetOwnerController();
SafeZoneManager::Get().CaptureBaseFromController(_this, player)
}
That is the code snippet I am running. I get the human readable name of the DamageCauser, see if it contains "C4". If it doesn't I process using the EventInstigator Controller Class.
If it does contain the word "C4", I then try to get the owner controller class of that DamageCauser and pass it into the same function. I am assuming the DamageCauser Controller would still be the Player Controller.. ? (edited)c++
UKismetSystemLibrary::SphereOverlapActors_NEW(
world,
_this->RootComponentField()->RelativeLocationField(),
static_cast<float>((1500)),
&types,
APrimalWorldSettings::GetPrivateStaticClass(),
&actors_ignore,
&new_actors);
for (AActor* actor : new_actors)
{
if (actor && actor->IsA(APrimalWorldSettings::GetPrivateStaticClass()))
{
APrimalWorldSettings* worldSetting = static_cast<APrimalWorldSettings*>(actor);
if (worldSetting)
{
FString fullName;
worldSetting->GetFullName(&fullName, NULL);
if (fullName.StartsWith(L"InstancedFoliageActor"))
{
// Do stuff with eg. rock, metal node etc here
}
}
}
}ArkApi::GetApiUtils().SendNotification(); template <typename T, typename... Args>
void SendNotification(AShooterPlayerController* player_controller, FLinearColor color, float display_scale,
float display_time, UTexture2D* icon, const T* msg, Args&&... args)
{
if (player_controller)
{
FString text(FString::Format(msg, std::forward<Args>(args)...));
player_controller->ClientServerSOTFNotificationCustom(&text, color, display_scale, display_time, icon,
nullptr);
}
}player_controller->ClientServerSOTFNotificationCustom is likely the function that is failedAShooterPlayerController.ClientServerSOTFNotificationCustom to see whyAShooterPlayerController.ClientServerNotification template <typename T, typename... Args>
void SendNotification(AShooterPlayerController* player_controller, FLinearColor color, float display_scale,
float display_time, UTexture2D* icon, const T* msg, Args&&... args)
{
if (player_controller)
{
FString text(FString::Format(msg, std::forward<Args>(args)...));
player_controller->ClientServerNotification(&text, color, display_scale, display_time, icon,
nullptr);
}
}c++
/* public: void __cdecl APrimalDinoCharacter::BPDoAttack(int) __ptr64 */
void __thiscall BPDoAttack(APrimalDinoCharacter *this,int param_1)
{
UFunction *pUVar1;
PrimalDinoCharacter_eventBPDoAttack_Parms Parms;
Parms = param_1;
pUVar1 = FindFunctionChecked((UObject *)this,SHOOTERGAME_BPDoAttack);
(**(code **)(*(longlong *)this + 0x1d8))(this,pUVar1,&Parms);
return;
}
This is, I hope, what will attack and cause damage to rock even with no rider. But... what next ? void __fastcall APrimalDinoCharacter::BPDoAttack(APrimalDinoCharacter *this, int AttackIndex)
{
UFunction *v2; // rax
int v3; // [rsp+20h] [rbp-18h]
APrimalDinoCharacter *v4; // [rsp+40h] [rbp+8h]
v4 = this;
v3 = AttackIndex;
v2 = UObject::FindFunctionChecked((UObject *)&this->vfptr, SHOOTERGAME_BPDoAttack);
((void (__fastcall *)(APrimalDinoCharacter *, UFunction *, int *))v4->vfptr[9].ShouldInstance)(v4, v2, &v3);
}void __fastcall APrimalDinoCharacter::BPDoHarvestAttack(APrimalDinoCharacter *this, int harvestIndex)
{
UFunction *v2; // rax
int v3; // [rsp+20h] [rbp-18h]
APrimalDinoCharacter *v4; // [rsp+40h] [rbp+8h]
v4 = this;
v3 = harvestIndex;
v2 = UObject::FindFunctionChecked((UObject *)&this->vfptr, SHOOTERGAME_BPDoHarvestAttack);
((void (__fastcall *)(APrimalDinoCharacter *, UFunction *, int *))v4->vfptr[9].ShouldInstance)(v4, v2, &v3);
}FString damageStr = FString(to_string(Damage));float Hook_APrimalStructure_TakeDamage(APrimalStructure* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float damageTaken = APrimalStructure_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
//Your additional code/checks
//Your additional code/checks
//Your additional code/checks
return damageTaken;
}
This will allow you to do additional processing after the damage calculation but before the value is returned. (edited)vector<queue<DiscordMessage>> vDM;
void DoSomething(){
vDM[Index].pop();
}std::unordered_map<std::string, std::queue<std::string>> uM;c++
reinterpret_cast<AShooterPlayerController*>(some_AController)
the AController is from here, so it should be the right class:
c++
void Hook_AShooterGameMode_Logout(AShooterGameMode* _this, AController* exiting) {...} (edited)void Hook_AShooterGameMode_Logout(AShooterGameMode* _this, AController* Exiting)
{
if (Exiting && Exiting->GetOwnerController())
{
APlayerController* APC = Exiting->GetOwnerController();
AShooterPlayerController* PC = static_cast<AShooterPlayerController*>(APC);ArkApi::GetCommands().AddConsoleCommand(...), and I see that the function I define for the command has to have 3 arguments (APlayerController*, FString*, and bool).
Is there documentation to say what each of these 3 parameters do/mean? I assume the first is the player invoking the command and the second is the (rest of?) the command text as invoked, but idk what the 3rd is.
Or should I just keep asking in here, or is it educated guesses for most of these things? I would like to be able to get answers through documentation so I don't have to keep bugging people here... I looked through the API code and it describes the API function calls, but not the structure of the underlying function.AddConsoleCommand only has 2 args.APlayerController*, FString*, and boolAShooterPlayerController*, FString*, EChatSendMode::Type is the actual argsvoid Commands::ReloadConfig(APlayerController* player_controller, FString*, bool)
{
Log::GetLog()->debug("Reloading Config");
NextConfig<ConfigBody>::Get().Load();
}AddChatCommandAddConsoleCommmand virtual void AddConsoleCommand(const FString& command,
const std::function<void(APlayerController*, FString*, bool)>& callback) = 0; void ArkBaseApi::LoadPluginCmd(APlayerController* player_controller, FString* cmd, bool /*unused*/)
{
auto* shooter_controller = static_cast<AShooterPlayerController*>(player_controller);
ArkApi::GetApiUtils().SendServerMessage(shooter_controller, FColorList::Green, *LoadPlugin(cmd));
} bool Commands::CheckConsoleCommands(APlayerController* a_player_controller, FString* cmd, bool write_to_log)
{
return CheckCommands<ConsoleCommand>(*cmd, console_commands_, a_player_controller, cmd, write_to_log);
}
void Commands::ReloadConfig(APlayerController* player_controller, FString*, bool)
{
Log::GetLog()->debug("Reloading Config");
NextConfig<ConfigBody>::Get().Load();
}
to
void Commands::ReloadConfig(APlayerController* player_controller, FString*, bool doLog)
{
if (doLog)
Log::GetLog()->debug("Reloading Config");
NextConfig<ConfigBody>::Get().Load();
}ArkApi::GetCommands().AddConsoleCommand("Plugin.SetDamage", &SetDamage); any player that types Plugin.SetDamage into the console will call the SetDamage(...) function, right? I'm not getting anything happening when I try to use it in-game.void SetDamage(APlayerController* player, FString* command, bool /*unused*/) {
Log::GetLog()->info("Inside of function body");
}
But nothing is showing up in logs. (edited)cheat mycommand if i rememberPlugin.SetDamage work, or will it need to be cheat Plugin.SetDamage? (edited)cheat UWorld* world = ArkApi::GetApiUtils().GetWorld();
string currentDay = to_string((int)(((world->TimeSecondsField() / 60) / 60) + 1));error LNK2001: unresolved external symbol "__declspec(dllimport) class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl ArkApi::Tools::GetCurrentDir(void)" (__imp_?GetCurrentDir@Tools@ArkApi@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ)
error LNK2001: unresolved external symbol "__declspec(dllimport) class std::vector<class std::shared_ptr<class spdlog::sinks::sink>,class std::allocator<class std::shared_ptr<class spdlog::sinks::sink> > > & __cdecl GetLogSinks(void)" (__imp_?GetLogSinks@@YAAEAV?$vector@V?$shared_ptr@Vsink@sinks@spdlog@@@std@@V?$allocator@V?$shared_ptr@Vsink@sinks@spdlog@@@std@@@2@@std@@XZ)
fatal error LNK1120: 2 unresolved externalsint& DayNumberField() { return *GetNativePointerField<int*>(this, "AShooterGameState.DayNumber"); }
float& DayTimeField() { return *GetNativePointerField<float*>(this, "AShooterGameState.DayTime"); }DECLARE_HOOK(APrimalStructure_BPOnStructurePickup, void, APrimalStructure*, APlayerController*, TSubclassOf<UPrimalItem>, UPrimalItem*, bool);
void Hook_APrimalStructure_BPOnStructurePickup(APrimalStructure* _this, APlayerController* PlayerController, TSubclassOf<UPrimalItem> ItemType, UPrimalItem* NewlyPickedUpItem, bool bIsQuickPickup)
{
APrimalStructure_BPOnStructurePickup_original(_this, PlayerController, ItemType, NewlyPickedUpItem, bIsQuickPickup);
}
ArkApi::GetHooks().SetHook("APrimalStructure.BPOnStructurePickup", &Hook_APrimalStructure_BPOnStructurePickup, &APrimalStructure_BPOnStructurePickup_original);
ArkApi::GetHooks().DisableHook("APrimalStructure.BPOnStructurePickup", &Hook_APrimalStructure_BPOnStructurePickup);
probablyAActor::TakeDamage but it doesn't seem to be the one. For that matter, what class is the player?c++
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{}APrimalCharacter a subclass of AActor? In which case, overloading AActor::TakeDamage would also overload APrimalCharacter::TakeDamage?c++
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass())) {...}DECLARE_HOOK(APrimalCharacter_TakeDamage, float, APrimalCharacter*, float, FDamageEvent*, AController*, AActor*);
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass())) {
//Player taking damage
Log::GetLog()->info("Player is taking " + std::to_string(Damage * plugin.dmg_mult) + " points of damage");
}
else {
...
}
And got hit by a dino, with no log about it. (edited)if (EventInstigator->TargetingTeamField() > 10000)
{
if (_this->IsA(APrimalDinoCharacter::GetPrivateStaticClass()))
{
if (_this->TargetingTeamField() > 10000)
Damage = Damage * TamedToTamed;
else if (_this->TargetingTeamField() < 10000)
Damage = Damage * TamedToWild;
}
else if (_this->IsA(AShooterCharacter::GetPrivateStaticClass()))
Damage = Damage * TamedToPlayer;
}DECLARE_HOOK(APrimalCharacter_TakeDamage, float, APrimalCharacter*, float, FDamageEvent*, AController*, AActor*);
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->IsA(AShooterCharacter::GetPrivateStaticClass())) {
//Player taking damage
Log::GetLog()->info("Player is taking " + std::to_string(Damage * plugin.dmg_mult) + " points of damage");
}
else {
FString dinoName;
_this->GetDescriptiveName(&dinoName);
Log::GetLog()->info("A " + dinoName.ToString() + " is taking " + std::to_string(Damage * plugin.dmg_mult) + " points of damage");
}
return APrimalCharacter_TakeDamage_original(_this, Damage * config.dmg_mult, DamageEvent, EventInstigator, DamageCauser);
}
void Load()
{
Log::Get().Init("ARK-test-plugin");
ReadConfig();
ArkApi::GetHooks().SetHook("APrimalDinoCharacter.TakeDamage", &Hook_APrimalCharacter_TakeDamage, &APrimalCharacter_TakeDamage_original);
}
void Unload()
{
ArkApi::GetHooks().DisableHook("APrimalDinoCharacter.TakeDamage", &Hook_APrimalCharacter_TakeDamage);
}
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_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Unload();
break;
}
return TRUE;
}
Anything wrong here?AShooterGameMode.HandleNewPlayer_Implementationvoid PostToDiscord(FString MSG)
{
nlohmann::json Webhook;
Webhook["username"] = ArkApi::Tools::Utf8Encode(*ServerName);
Webhook["content"] = ArkApi::Tools::Utf8Encode(*MSG);
AShooterGameState* ShooterGameState = static_cast<AShooterGameState*>(ArkApi::GetApiUtils().GetShooterGameMode()->GameStateField());
ShooterGameState->HTTPPostRequest(WebhookURL.c_str(), FString(ArkApi::Tools::Utf8Decode(Webhook.dump())));
}void sendDiscordMessage(string message, string webHookURL) {
nlohmann::json j;
try {
j["content"] = message;
const string jsonMessage = j.dump();
static_cast<AShooterGameState*>(ArkApi::GetApiUtils().GetWorld()->GameStateField())->HTTPPostRequest(FString(webHookURL), FString(ArkApi::Tools::Utf8Decode(jsonMessage).c_str()));
}
catch (exception ex) {
Log::GetLog()->error(ex.what());
}
}
Mine is very similar (edited)using namespace std; btw?if (structures[index]->IsA(APrimalStructure::GetPrivateStaticClass()))
{
structuretoflip = static_cast<APrimalStructure*>(structures[index]);
int killerTeam = Killer->TargetingTeamField();
structuretoflip->ChangeActorTeam(killerTeam);
structuretoflip->BPChangedActorTeam();
}c++
void BPAttachedRootComponent() { NativeCall<void>(this, "AActor.BPAttachedRootComponent"); }
void BPChangedActorTeam() { NativeCall<void>(this, "AActor.BPChangedActorTeam"); }c++
std::string GetSystemDatetimeNow(long addedSeconds)
{
char buffer[32];
time_t now = time(0) + addedSeconds;
tm ltm;
localtime_s(<m, &now);
std::strftime(buffer, 32, "%Y-%m-%d %H:%M:%S", <m);
std::string bufferStr(buffer);
return bufferStr.substr(0, 19);
}void Hook_AShooterGameMode_SendServerNotification(AShooterGameMode* _this, FString* MessageText, FLinearColor MessageColor, float DisplayScale, float DisplayTime, UTexture2D* MessageIcon, USoundBase* SoundToPlay, int ReceiverTeamId, int ReceiverPlayerID, bool bDoBillboard) ArkApi::GetApiUtils().GetShooterGameMode()->SendServerNotification();c++
UPrimalHarvestingComponent::GiveHarvestResource(
UPrimalHarvestingComponent *this,
UPrimalInventoryComponent *param_1,
float param_2,
TSubclassOf<class_UDamageType> param_3,
AActor *param_4,
TArray<struct_FHarvestResourceEntry,
class_FDefaultAllocator> *param_5)
Am I accessing it wrong or should it be in the api ?struct FOnlineSubsystemSteam
{
FString& BanListURLField() { return *GetNativePointerField<FString*>(this, "FOnlineSubsystemSteam.BanListURL"); }
};c++
struct UPrimalHarvestingComponent : UActorComponent
{
void GiveHarvestResource(UPrimalInventoryComponent* param_1, float param_2, TSubclassOf<UDamageType> param_3, AActor* param_4, TArray<FHarvestResourceEntry, FDefaultAllocator>* param_5) { NativeCall<void, UPrimalInventoryComponent*, float, TSubclassOf<UDamageType>, AActor*, TArray<FHarvestResourceEntry, FDefaultAllocator>*>(this, "UPrimalHarvestingComponent.GiveHarvestResource", param_1, param_2, param_3, param_4, param_5); }
};c++
struct UPrimalHarvestingComponent;
Is there anything else i need to add ?c++
struct UPrimalHarvestingComponent : UActorComponent
{
// Functions
static UClass* GetPrivateStaticClass(const wchar_t* Package) { return NativeCall<UClass*, const wchar_t*>(nullptr, "UPrimalHarvestingComponent.GetPrivateStaticClass", Package); }
void GiveHarvestResource(UPrimalInventoryComponent* param_1, float param_2, TSubclassOf<UDamageType> param_3, AActor* param_4, TArray<FHarvestResourceEntry, FDefaultAllocator>* param_5) { NativeCall<void, UPrimalInventoryComponent*, float, TSubclassOf<UDamageType>, AActor*, TArray<FHarvestResourceEntry, FDefaultAllocator>*>(this, "UPrimalHarvestingComponent.GiveHarvestResource", param_1, param_2, param_3, param_4, param_5); }
};
Is that not the right way to do it ? (edited)c++
const wchar_t* Package = L"x";
if (actor->IsA(UPrimalHarvestingComponent::GetPrivateStaticClass(Package)))
{ ... }
what to put in Package ?c++
TSubclassOf<UDamageType> dinoDamage;
float outputMultiplier = 5.0f;
dino->BlueprintOverrideHarvestDamageType(&dinoDamage, &outputMultiplier);
TArray<FHarvestResourceEntry, FDefaultAllocator>* param_5;
harvestComponent->GiveHarvestResource(dino->MyInventoryComponentField(), 5.0f, dinoDamage, dino, param_5);
I need to define param_5 / fill it with something, otherwise call to GiveHarvestResource(...) goes straight to return according to this (from Ghidra):
c++
if ((((param_5 != (TArray<struct_FHarvestResourceEntry,class_FDefaultAllocator> *)0x0) &&
(cVar5 = (**(code **)(*(longlong *)param_5 + 0x830))(param_5), cVar5 != '\0')) &&
(50000 < *(int *)(param_5 + 0x214))) &&
(bVar6 = DisableHarvesting((APrimalDinoCharacter *)param_5), bVar6 != false))
goto LAB_140695f6a;
(the LAB_140695f6a is the end of code)
HELP c++
struct UPrimalHarvestingComponent : UActorComponent {
static UClass* GetPrivateStaticClass(const wchar_t* Package) { return NativeCall<UClass*, const wchar_t*>(nullptr, "UPrimalHarvestingComponent.GetPrivateStaticClass", Package); }
static void StaticRegisterNativesUPrimalHarvestingComponent() { NativeCall<void>(nullptr, "UPrimalHarvestingComponent.StaticRegisterNativesUPrimalHarvestingComponent"); }
bool TemplateCheckForHarvestRepopulation(bool bForceReinit, UWorld* world, FVector* where) { NativeCall<bool, UWorld*, FVector*>(this, "UPrimalHarvestingComponent.TemplateCheckForHarvestRepopulation", world, where); }
TArray < FHarvestResourceEntry, FDefaultAllocator>& HarvestResourceEntries() { return *GetNativePointerField< TArray<FHarvestResourceEntry, FDefaultAllocator>*>(this, "UPrimalHarvestingComponent.HarvestResourceEntries"); }
TArray < FHarvestResourceEntry, FDefaultAllocator>& BaseHarvestResourceEntries() { return *GetNativePointerField< TArray<FHarvestResourceEntry, FDefaultAllocator>*>(this, "UPrimalHarvestingComponent.BaseHarvestResourceEntries"); }
[...]
which is just what I need (HarvestResourceEntries). but its not in Ark and Ghidra can't find it either APrimalDinoCharacter* Hook_APrimalDinoCharacter_StaticCreateBabyDino(APrimalDinoCharacter* _this, UWorld* theWorld, TSubclassOf<APrimalDinoCharacter> EggDinoClassToSpawn, FVector* theGroundLoc, float actorRotationYaw, char* EggColorSetIndices, char* EggNumberOfLevelUpPointsApplied, float EggTamedIneffectivenessModifier, int NotifyTeamOverride, TArray<FDinoAncestorsEntry>* EggDinoAncestors, TArray<FDinoAncestorsEntry>* EggDinoAncestorsMale, int EggRandomMutationsFemale, int EggRandomMutationsMale)
{
APrimalDinoCharacter* newBaby = APrimalDinoCharacter_StaticCreateBabyDino_original(_this, theWorld, EggDinoClassToSpawn, theGroundLoc, actorRotationYaw, EggColorSetIndices, EggNumberOfLevelUpPointsApplied, EggTamedIneffectivenessModifier, NotifyTeamOverride, EggDinoAncestors, EggDinoAncestorsMale, EggRandomMutationsFemale, EggRandomMutationsMale);
//DO STUFF HERE
return newBaby;
}
This errored out on the line that assigns to "newBaby". What am I doing wrong there? (edited)return APrimalDinoCharacter_StaticCreateBabyDino_original(_this, theWorld, EggDinoClassToSpawn, theGroundLoc, actorRotationYaw, EggColorSetIndices, EggNumberOfLevelUpPointsApplied, EggTamedIneffectivenessModifier, NotifyTeamOverride, EggDinoAncestors, EggDinoAncestorsMale, EggRandomMutationsFemale, EggRandomMutationsMale);
Doesn't cause the error. (edited)ArkApi::GetApiUtils().GetShooterGameMode()->LoadTribeData(TribeId, tribe_data, false, false); (edited)struct FArkTributePlayerData : FArkTributeEntity
{
unsigned __int64 PlayerDataID;
TArray<unsigned char, FDefaultAllocator> PlayerDataBytes;
FString PlayerName;
FString PlayerStats[12];
FString UploadingServerMapName;
bool bWasAllowDPCUpload;
bool bWithItems;
unsigned int ItemCount;
bool bForServerTransfer;
float Version;
};
struct FArkTributeEntity
{
int UploadTime;
}; (edited)_this->bIsBaby();
_this->bReceivedDinoAncestors();if (_this->bIsBaby()()) { //is never true for (auto item : Items)
{
}
but it doesn't like it (edited)FItemNetInfo item = Items[0][0];
but it doesn't make sense to me (edited)TArray<FItemNetInfo> Items
or
TArray<FItemNetInfo*> Items
but not
TArray<FItemNetInfo>* Items
but I am sure someone here can point ( if (_this->TargetingTeamField() != EventInstigator->TargetingTeamField())
{
FVector StructPos = _this->RootComponentField()->RelativeLocationField();
AGameState* aGameState = ArkApi::GetApiUtils().GetWorld()->GameStateField();
AShooterGameState* GameState = static_cast<AShooterGameState*>(aGameState);
GameState->NetAddFloatingDamageText(StructPos, ConfigDamage, TeamField, 0);
GameState->ForceNetUpdate(true);
}magnet:?xt=urn:btih:169DFE1E10161FFA82B786BF89F05AEA6BCD4510&tr=http%3A%2F%2Fbt2.t-ru.org%2Fann%3Fmagnet&dn=IDA%20Pro%207.0.170914%20WIN%5CMAC%20x64%20%2B%20Hex-Rays%20Decompilers%20(x86%2C%20x64%2C%20ARM%2C%20ARM64)%20%5B2017%2C%20ENG%5Dfor (auto item : Items)
{
}TArray<FItemNetInfo>* Items;
Items->Num();
for (int i; i < Items->Num; i++)
{
}auto outerTotal = Items->Num();
for (int i = 0; i < outerTotal; i++) {
auto innerTotal = Items[i].Num();
for (int j = 0; j < innerTotal; j++) {
auto item = Items[i][j];
}
} (edited)c++
ArkApi::GetApiUtils().GetWorld()->SpawnActor(...) (edited)success: 1
response: {"message": "400: Bad Request", "code": 0}if (item_stat_type == EPrimalItemStat::Armor || item_stat_type == EPrimalItemStat::MaxDurability)
{
*(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);
if (item_stat_type == EPrimalItemStat::MaxDurability)
{
if (item->bUseItemDurability()())
item->ItemDurabilityField() = item->GetItemStatModifier(item_stat_type);
}
}c++
this->field_0x498
And "this" is APrimalDinoCharacter. U have any idea how i can find out what the code is referring to ?
1AShooterPlayerController::StaticClass()->GetDefaultObject(true);NativeCall use __fastcall*?__fastcall x)
(edited)c++
!item->bIsEngram()()FString name = "";
AShooterPlayerController* controller = ArkApi::GetApiUtils().FindPlayerFromSteamId(steam_id);
if (controller && controller->GetPlayerCharacter())
name = controller->GetPlayerCharacter()->PlayerNameField(); (edited)const auto player_controller = ArkApi::GetApiUtils().FindControllerFromCharacter(reinterpret_cast<AShooterCharacter*>(OnlinePlayer));
but it fails for offline players as I think it does not exists when player is offline.
but since Ark can display an offline players name ......there must be a way to access it (edited)FString characterName = (reinterpret_cast<AShooterCharacter*>(_this))->PlayerNameField(); (edited)
(edited)




Patch Notes: v310.29 - 15/4/2020
- Fixed multiple server crashes
might be a reason, heh
1c++
ArkApi::IApiUtils :
template <typename T, typename... Args>
void SendNotification(AShooterPlayerController* player_controller, FLinearColor color, float display_scale, float display_time, UTexture2D* icon, const T* msg, Args&&... args)
{
if (player_controller)
{
FString text(FString::Format(msg, std::forward<Args>(args)...));
-> Crashed here -> player_controller->ClientServerSOTFNotificationCustom(&text, color, display_scale, display_time, icon, nullptr);
}
}c++
void __thiscall
AddArkTributeItem(UPrimalInventoryComponent *this,FItemNetInfo *param_1,bool param_2)AddArkTributeItem ( or RequestAddArkTributeItem ) (edited)MarkTribeNameChanged , hook onto it and see if it's called if not you might need to IDA it in which case if you dont know what that even is start here https://youtu.be/bYDK5IJphPU



UnknownModule!UnknownFunction (0x00007ffbf9555d50) + 0 bytes [UnknownFile:0] your plugin (?)UnknownModule!UnknownFunction (0x00007ffbf9555d50) + 0 bytes [UnknownFile:0] to see what the crash could be if it is your own plugin.1>d:\projects\goglootbox\goglootbox\include\api\atlas\actor.h(251): error C2011: 'FSpawnPointInfo': 'struct' type redefinition
1>d:\projects\goglootbox\goglootbox\include\api\base.h(167): note: see declaration of 'FSpawnPointInfo'
1>d:\projects\goglootbox\goglootbox\include\api\atlas\actor.h(5905): error C2011: 'UShooterDamageType': 'struct' type redefinition
1>d:\projects\goglootbox\goglootbox\include\api\base.h(202): note: see declaration of 'UShooterDamageType'
1>d:\projects\goglootbox\goglootbox\include\api\atlas\actor.h(5982): error C2011: 'UPrimalDinoSettings': 'struct' type redefinition
1>d:\projects\goglootbox\goglootbox\include\api\base.h(197): note: see declaration of 'UPrimalDinoSettings'
Actually, FSpawnPointInfo defined in base.h as follow:
struct FSpawnPointInfo {};
and, actually, redefined in atlas\actor.h:
struct FSpawnPointInfo
{
unsigned int& EntityIDField() { return *GetNativePointerField<unsigned int*>(this, "FSpawnPointInfo.EntityID"); }
...
}; (edited)ark\actor.h
Do I misunderstand something or it's the Api problem? FString msg = "hello çàûéèï";
std:string msg_str = msg.ToString();
std::wstring msg_ws = ArkApi::Tools::ConvertToWideStr(msg.ToString());
cout << ArkApi::Tools::Utf8Encode(msg_ws) << '\n';
cout << ws2s(ArkApi::Tools::Utf8Decode(msg_str)) << '\n';
cout << ws2s(msg_ws) << '\n';
Log::GetLog()->info(ArkApi::Tools::Utf8Encode(msg_ws));
Log::GetLog()->info(ws2s(ArkApi::Tools::Utf8Decode(msg_str)));
Log::GetLog()->info(ws2s(msg_ws));
They all display "hello ??????" FString msg = "hello çàûéèï";
std::wstring msg_ws = ArkApi::Tools::ConvertToWideStr(msg.ToString());
wcout << msg_ws << '\n';FString msg = "hello çàûéèï";bool UpdatePlayerName(uint64 steam_id, const FString& player_new_name) override
{
try
{
return db_.query("UPDATE ShopRewards SET Name = '%s' WHERE SteamId = %I64u;", ArkApi::Tools::Utf8Encode(*player_new_name),
steam_id);
}
catch (const std::exception& exception)
{
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, exception.what());
return false;
}
} (edited)daotk::mysql::connect_options options;
options.charset = "utf8";c++
std::string GetServerPort()
{
// Get port number (format is <value>:<port>)
FString fPort;
ArkApi::GetApiUtils().GetShooterGameMode()->GetNetworkNumber(&fPort);
// Regex port from string
std::string port = fPort.ToString();
try
{
std::regex re(":(.*)");
std::smatch match;
if (std::regex_search(port, match, re) && match.size() > 1)
{
return match.str(1);
}
}
catch (std::regex_error & error)
{
Log::GetLog()->error(error.what());
}
return port;
}05/14/20 08:58 [API][warning] (API::PluginManager::LoadAllPlugins) Failed to load plugin - TestPlugin
Error code: 1114Log::Get().Init("")plugins.load xx worksif (ArkApi::GetApiUtils().GetStatus() == ArkApi::ServerStatus::Ready)void Hook_AShooterGameMode_InitGame(AShooterGameMode* a_shooter_game_mode, FString* map_name, FString* options,
FString* error_message)plugins.load was working because port was always available, plugin on server setup was failing because I was trying to get the port on init, and the port wasn't availablec++
void Hook_AShooterGameMode_InitGame(AShooterGameMode* a_shooter_game_mode, FString* map_name, FString* options, FString* error_message)
{
AShooterGameMode_InitGame_original(a_shooter_game_mode, map_name, options, error_message);
Zones::ServerId = fmt::format(L"{0}:{1}", Helper::GetSetting_string("ServerIP").c_str(), Helper::GetServerPort().c_str());
} (edited).c_str() does, I'm struggling with the FString and such types a littleKiller->IsLocalController() does ?bool _cdecl Hook_AShooterCharacter_Die(AShooterCharacter* _this, float KillingDamage, FDamageEvent* DamageEvent, AController* Killer, AActor* DamageCauser)bool __fastcall AController::IsLocalController(AController *this)
{
AController *v1; // rbx
v1 = this;
return TEnumAsByte<enum ESlateColorStylingMode::Type>::operator enum ESlateColorStylingMode::Type((TEnumAsByte<enum ETickingGroup> *)&this->RemoteRole) != 2
&& TEnumAsByte<enum EMovementMode>::operator==((TEnumAsByte<enum EWorldType::Type> *)&v1->Role, Zeros);
}magnet:?xt=urn:btih:169DFE1E10161FFA82B786BF89F05AEA6BCD4510&tr=http%3A%2F%2Fbt2.t-ru.org%2Fann%3Fmagnet&dn=IDA%20Pro%207.0.170914%20WIN%5CMAC%20x64%20%2B%20Hex-Rays%20Decompilers%20(x86%2C%20x64%2C%20ARM%2C%20ARM64)%20%5B2017%2C%20ENG%5D->GetRidingDino() returns?...->GetDinoDescriptiveName() which seems to return name (Dino)FString GetDinoBlueprint(UObjectBase* dino)
{
if (dino && dino->ClassField())
{
FString path_name;
dino->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("");
}const int dino_level = char_comp->BaseCharacterLevelField() + char_comp->ExtraCharacterLevelField();*ArkApi::GetApiUtils().GetCharacterName(Player).Replace(L"{}", L"").Replace(...), is this essentially the same as .toString() ? (edited)*ArkApi::GetApiUtils().GetCharacterName(Player).Replace(L"{}", L"") for (TWeakObjectPtr<APlayerController> PlayerCon : player_controllers)
{
AShooterPlayerController* Player = static_cast<AShooterPlayerController*>(PlayerCon.Get());
if (Player) Players += Counter++ == 0 ? FString::Format(L"{} ({})", *ArkApi::GetApiUtils().GetCharacterName(Player).Replace(L"{}", L""), ArkApi::GetApiUtils().GetShooterGameMode()->GetSteamIDForPlayerID(Player->LinkedPlayerIDField())) : FString::Format(L", {} ({})", *ArkApi::GetApiUtils().GetCharacterName(Player).Replace(L"{}", L""), ArkApi::GetApiUtils().GetShooterGameMode()->GetSteamIDForPlayerID(Player->LinkedPlayerIDField()));
}c++
bool Hook_AShooterCharacter_Die(AShooterCharacter* _this, float KillingDamage, FDamageEvent* DamageEvent, AController* Killer, AActor* DamageCauser)
{
// ...
const uint64 killer_steam_id = ArkApi::IApiUtils::GetSteamIdFromController(Killer);
AShooterPlayerController* killer_controller = ArkApi::GetApiUtils().FindPlayerFromSteamId(killer_steam_id);
auto* killer_primal_character = static_cast<APrimalCharacter*>(killer_controller->CharacterField());
UPrimalCharacterStatusComponent* killer_char_component = killer_primal_character->MyCharacterStatusComponentField();
// The bit below is wrong if the player is riding a Dino...
int KillerPlayerLevel = killer_char_component->BaseCharacterLevelField() + killer_char_component->ExtraCharacterLevelField();
} (edited)throw; statementAShooterPlayerController_ServerRequestDownloadPlayerCharacter_Implementation , AShooterPlayerController_IsValidArkTributePlayerDownloadForThisServer , AShooterPlayerController_ClientPlayerIsValidToDownload_Implementation are all not even called before, during, or after the server travelFArkTributePlayerData param in themUPrimalLocalProfile::AddArkTributeItemUPrimalLocalProfile::AddArkTributePlayerData is for player character
ArkItem correct ? (edited)/* 24665 */
struct __cppobj FArkInventoryData
{
TArray<FArkTributeInventoryItem,FDefaultAllocator> ArkItems;
TArray<FARKTributeDino,FDefaultAllocator> ArkTamedDinosData;
TArray<FArkTributePlayerData,FDefaultAllocator> ArkPlayerData;
};
I created a header file containing all the structs that's the only place it's defined as "ArkItems"FMemory classres->Data = FMemory::Realloc(res->Data, size, 0); template <typename T>
static T Realloc(T Original, size_t Count, unsigned int Alignment)
{
return (T) Realloc(Original, Count, Alignment);
}
2.dll into the plugin directoryC++
struct ABiomeZoneVolume {};
struct ADroppedItemEgg : ADroppedItem {
TSubclassOf<APrimalEmitterSpawnable> SpawnDinoEmitter;
float IndoorsHypoThermalInsulation;
float IndoorsHyperThermalInsulation;
float EggThermalInsulationTemperatureMultiplier;
unsigned __int32 bIsEggTooHot : 1;
unsigned __int32 bIsEggTooCold : 1;
ABiomeZoneVolume* MyBiomeZone;
long double LastInsulationCalcTime;
float HyperThermalInsulation;
float HypoThermalInsulation;
};
DECLARE_HOOK(ADroppedItemEgg_Tick, void, ADroppedItemEgg*, float);
void Hook_ADroppedItemEgg_Tick(ADroppedItemEgg* _this, float deltaSeconds)
{
Log::GetLog()->info("Called egg tick!");
ADroppedItemEgg_Tick_original(_this, deltaSeconds);
}
ArkApi::GetHooks().SetHook("ADroppedItemEgg.Tick", &Hook_ADroppedItemEgg_Tick, &ADroppedItemEgg_Tick_original);
ArkApi::GetHooks().DisableHook("ADroppedItemEgg.Tick", &Hook_ADroppedItemEgg_Tick); (edited)PVOID ownsDLC = DetourFindFunction("ShooterGame.exe", "ADroppedItemEgg::Tick");#include "detours.h"
, if i get it to work il see if i cant make a google doc#pragma once
#include "detour.h"
bool Detour::OnFailure(std::string message)
{
DetourTransactionAbort(); //Force abortion of any possible detour transaction.
#if _DEBUG
printfn("Unable to create detour, %s!", message);
#endif
return false;
}
bool Detour::Create(void* function, void* callback)
{
if (DetourTransactionBegin() != NO_ERROR)
return Detour::OnFailure("Begin Failure.");
if (DetourUpdateThread(GetCurrentThread()) != NO_ERROR)
return Detour::OnFailure("Unable to get Thread.");
if (DetourAttach((PVOID*)function, callback) != NO_ERROR)
return Detour::OnFailure("Unable to Attach.");
if (DetourTransactionCommit() != NO_ERROR)
return Detour::OnFailure("Unable to Commit.");
#if _DEBUG
printfn("Successfully Created Detour.");
#endif
return true;
}CPP file to make a detour easily.#pragma once
#define printfn(format, ...) \
printf(format"\n", ##__VA_ARGS__)printfn("Unable to create detour, %s!", message); should be printfn("Unable to create detour, %s!", message.c_str()); Detour::Create(&FunctionToBeHooked, YourCallback);#pragma once
#include <vector>
#include <Windows.h>
#include <detours.h>
#include <string>
#include "macro.h"
class Detour
{
static bool OnFailure(std::string);
public:
static bool Create(void* function, void* callback);
};#include "macro.h" is the printfn, you can remove it.

endscene/present is then used as the version (and the others are unloaded)DX<DXX>::initialize(); for any vesion
DX<D9>::initialize(); for D9 (edited)DX<T> is a template to get a static context of the system.
this parameter

C++
struct ABiomeZoneVolume {};
struct ADroppedItemEgg : ADroppedItem {
TSubclassOf<APrimalEmitterSpawnable> SpawnDinoEmitter;
float IndoorsHypoThermalInsulation;
float IndoorsHyperThermalInsulation;
float EggThermalInsulationTemperatureMultiplier;
unsigned __int32 bIsEggTooHot : 1;
unsigned __int32 bIsEggTooCold : 1;
ABiomeZoneVolume* MyBiomeZone;
long double LastInsulationCalcTime;
float HyperThermalInsulation;
float HypoThermalInsulation;
};
DECLARE_HOOK(ADroppedItemEgg_Tick, void, ADroppedItemEgg*, float);
void Hook_ADroppedItemEgg_Tick(ADroppedItemEgg* _this, float deltaSeconds)
{
Log::GetLog()->info("Called egg tick!");
ADroppedItemEgg_Tick_original(_this, deltaSeconds);
}
void Testing(RCONClientConnection* cl, RCONPacket* pckt, UWorld*)
{
try
{
Log::GetLog()->info("Called!");
Detour::Create(&ADroppedItemEgg_Tick_original, &Hook_ADroppedItemEgg_Tick);
}
catch (const std::exception & error)
{
Log::GetLog()->error(error.what());
}
}
// These 2 functions are in Load&Unload just dropped in here for example sake
ArkApi::GetHooks().SetHook("ADroppedItemEgg.Tick", &Hook_ADroppedItemEgg_Tick, &ADroppedItemEgg_Tick_original);
ArkApi::GetHooks().DisableHook("ADroppedItemEgg.Tick", &Hook_ADroppedItemEgg_Tick);C++
PVOID ownsDLC = DetourFindFunction("ShooterGame.exe", "ADroppedItemEgg::Tick");
std::cout << ownsDLC prints just a bunch of zerosPdbConfig.json
{
"structures": [
"ADroppedItemEgg"
]
}
without that defined inside the root of the plugin you are working on or inside ShooterGame\Binaries\Win64\config.json it wont let you hook onto it for reasons i dont yet know; Once that was added in it started to spit out log messages. Special thanks to @Lethal wouldn't have figured it out without him 
UShooterCheatManager* cheatManager = ArkApi::GetApiUtils().GetShooterGameMode()->GlobalCommandsCheatManagerField();
But it always returns a nullptrC++
APlayerController* apc = _this->GetOwnerController();
AShooterPlayerController* shooter_controller = static_cast<AShooterPlayerController*>(apc);
Would fail to cast correctly ? (edited)TArray<TSubclassOf<UPrimalItem>> all_items = static_cast<UPrimalGlobals*>(Globals::GEngine()()->GameSingletonField())->PrimalGameDataOverrideField()->MasterItemListField();PrimalGameDataOverrideFieldPrimalGameDataFieldcheat GFI bed_modern 1 0 0
cheat giveitemnum 128 1 0 0giveitemnum searches in the MasterItemListField
and GFI works with the Blueprint system of Unreal Engine itself somehow UObject* object = Globals::StaticLoadObject(UObject::StaticClass(), nullptr, *path_name, nullptr, 0, 0, true);
TSubclassOf<UPrimalItem> archetype;
archetype.uClass = reinterpret_cast<UClass*>(object);
UPrimalItem* UPI = (UPrimalItem*)archetype.uClass->GetDefaultObject(true);MasterItemList ? Is it for performance reason?AShooterCharacter::RefreshTribeName(AShooterCharacter *this)APrimalCharacter::NetUpdateTribeName(APrimalCharacter *this, FString *NewTribeName)GameState->ForceNetUpdate(false, true, false);
FString mapName;
ArkApi::GetApiUtils().GetWorld()->GetMapName(&mapName);void* but how will you know the type of the pointer?UObject is the base type.

L is a keyword for creating a wchar_t* literal. (edited)"hello" is char*L"hello" is wchar_t*
1
u8"hello" for Unicode (utf-8) (edited)TEXT macroPermissions::Hooks::Hook_AShooterGameMode_HandleNewPlayer) Couldn't add player error?ArkApi::IApiUtils::GetSteamIdFromController(player_controller);/// A 64-bit unsigned integer.
typedef FPlatformTypes::uint64 uint64;
This is how the API currently is sending it.16140901064495857664 Their old ID — 7656119806358167418446744073709551615 /**
* \brief Returns Steam ID from player controller
*/
static uint64 GetSteamIdFromController(AController* controller)
{
uint64 steam_id = 0;
if (controller != nullptr)
{
APlayerState* player_state = controller->PlayerStateField();
if (player_state != nullptr)
{
auto* steam_net_id = static_cast<FUniqueNetIdSteam*>(player_state->UniqueIdField()
.UniqueNetId.Get());
steam_id = steam_net_id->UniqueNetId;
}
}
return steam_id;
}FUniqueNetIdSteamFUniqueNetIdauto* steam_net_id = static_cast<FUniqueNetIdString*>(player_state->UniqueIdField()
.UniqueNetId.Get());
const FString steam_id_str = steam_net_id->UniqueNetIdStr;
try
{
steam_id = std::stoull(*steam_id_str);
}
catch (const std::exception&)
{
return 0;
}16140901064495857664 being reported by 2 separate plugins, which is close to but not the max bigint unsigned... playerId/tribeId seem fine... @substitute determined that its caused by a bit of code in the plugin API1 600 000 000 000 000 000 000
static uint64 get_steam_id_from_controller(AController* controller)
{
uint64 steam_id = 0;
if (controller != nullptr)
{
APlayerState* player_state = controller->PlayerStateField();
if (player_state != nullptr)
{
auto* steam_net_id = static_cast<FUniqueNetIdString*>(player_state->UniqueIdField().UniqueNetId.Get());
const FString steam_id_str = steam_net_id->UniqueNetIdStr;
try
{
steam_id = std::stoull(*steam_id_str);
}
catch (const std::exception&)
{
return 0;
}
}
}
return steam_id;
}111111 followed by some zeros (edited)static uint64 get_steam_id_from_controller(AController* controller)
{
uint64 steam_id = 0;
if (controller != nullptr)
{
APlayerState* player_state = controller->PlayerStateField();
if (player_state != nullptr)
{
auto* steam_net_id = static_cast<FUniqueNetIdString*>(player_state->UniqueIdField().UniqueNetId.Get());
const FString steam_id_str = steam_net_id->UniqueNetIdStr;
try
{
if (*steam_id_str == nullptr) {
Log::GetLog()->info("is Null");
}
steam_id = std::stoull(*steam_id_str);
Log::GetLog()->info("Chat Steam Id {}", steam_id_str.ToString());
}
catch (const std::exception& ex)
{
Log::GetLog()->info("exception {}", ex.what());
return 0;
}
}
}
return steam_id;
}static uint64 get_steam_id_from_controller(AController* controller)
{
uint64 steam_id = 0;
if (controller != nullptr)
{
APlayerState* player_state = controller->PlayerStateField();
if (player_state != nullptr)
{
auto* steam_net_id = static_cast<FUniqueNetIdString*>(player_state->UniqueIdField().UniqueNetId.Get());
const FString steam_id_str = steam_net_id->UniqueNetIdStr;
try
{
if (*steam_id_str == nullptr) {
Log::GetLog()->info("is Null");
}
Log::GetLog()->info("Chat 1 Steam Id '{}'", steam_id_str.ToString());
Log::GetLog()->info("Chat 2 Steam Id '{}'", steam_id_str.ToString().c_str());
steam_id = std::stoull(*steam_id_str);
}
catch (const std::exception& ex)
{
Log::GetLog()->info("exception {}", ex.what());
return 0;
}
}
}
return steam_id;
}FUniqueNetIdReplFUniqueNetIdRepl& UniqueIdField() { return *GetNativePointerField<FUniqueNetIdRepl*>(this, "APlayerState.UniqueId"); }auto* steam_net_id = (player_state->UniqueIdField().UniqueNetId.Get());template <typename RT>
RT GetNativePointerField(const void* _this, const std::string& field_name)
{
return reinterpret_cast<RT>(GetAddress(_this, field_name));
}static uint64 get_steam_id_from_controller2(AController* controller)
{
uint64 steam_id = 0;
if (controller != nullptr)
{
APlayerState* player_state = controller->PlayerStateField();
if (player_state != nullptr)
{
// auto* steam_net_id = static_cast<FUniqueNetIdString*>(player_state->UniqueIdField().UniqueNetId.Get());
auto* steam_net_id = (player_state->UniqueIdField().UniqueNetId.Get());
Log::GetLog()->info("Chat 1 Steam Id '{}'", typeid(steam_net_id).name());
}
}
}FUniqueNetId*static uint64 get_steam_id_from_controller3(AShooterPlayerController* pc)
{
uint64 steam_id = 0;
if (pc != nullptr)
{
FString s2 = "";
auto steamId = pc->GetUniqueNetIdAsString(&s2);
Log::GetLog()->info("Chat 1 uq '{}'", s2.ToString());
Log::GetLog()->info("Chat 2 uq '{}'", steamId->ToString());
try
{
const uint64 steam_id = stoull(steamId->ToString());
Log::GetLog()->info("Chat 3 uq '{}'", steam_id);
}catch (const std::exception& ex)
{
Log::GetLog()->info("exception {}", ex.what());
return 0;
}
}
return 0;
}8002257547803181846
7792121212714308622
8756058525359577470
76561198971508214
110111100001101101110101101011110001001111111110100001100010110
110110000100011001011001111010101100010100111110101010000001110
111100110000011110001001101011001010100100101101001100101111110
000000100010000000000000000000100111100010001100101010111110110Example Epic ID's
8002257547803181846
7792121212714308622
8756058525359577470
7557390344006069269
76561198971508214
64 bit representtations:
0110111100001101101110101101011110001001111111110100001100010110
0110110000100011001011001111010101100010100111110101010000001110
0111100110000011110001001101011001010100100101101001100101111110
0110100011100001001111100111101000100011011100101110110000010101
0000000100010000000000000000000100111100010001100101010111110110-crossplay with steam mods thought? surely notstatic uint64 get_steam_id_from_controller3(AShooterPlayerController* pc)
{
uint64 steam_id = 0;
if (pc != nullptr)
{
FString s2 = "";
auto steamId = pc->GetUniqueNetIdAsString(&s2);
Log::GetLog()->info("Chat 1 uq '{}'", s2.ToString());
Log::GetLog()->info("Chat 2 uq '{}'", steamId->ToString());
try
{
const uint64 steam_id = stoull(steamId->ToString());
Log::GetLog()->info("Chat 3 uq '{}'", steam_id);
}catch (const std::exception& ex)
{
Log::GetLog()->info("exception {}", ex.what());
return 0;
}
}
return 0;
}c++
static uint64 GetSteamIdFromController(AController* controller)
{
uint64 steam_id = 0;
if (controller != nullptr)
{
AShooterPlayerController* pc = static_cast<AShooterPlayerController*>(controller->GetOwnerController());
if (pc != nullptr)
{
steam_id = pc->GetUniqueNetIdAsUINT64();
}
}
Log::GetLog()->info("SteamID: {}", steam_id);
return steam_id;
}
I'm testing this version GetUniqueNetIdAsString(&s2);
so this is the way to go now?c++
FindPlayerFromSteamId()
Will be broken if you use the string version.static uint64 get_steam_id_from_pc(AController* ctrl)
{
uint64 steam_id = 0;
if (ctrl && ctrl->IsA(AShooterPlayerController::GetPrivateStaticClass())) {
AShooterPlayerController* pc = (AShooterPlayerController*)ctrl;
FString szsteam_id = "";
try
{
pc->GetUniqueNetIdAsString(&szsteam_id);
const uint64 steam_id = stoull(szsteam_id.ToString());
return steam_id;
}
catch (const std::exception& ex)
{
Log::GetLog()->info("exception {}", ex.what());
}
}
return 0;
}
AShooterPlayerController* find_pc_steam_id(uint64 steam_id)
{
AShooterPlayerController* result = nullptr;
const auto& player_controllers = ArkApi::GetApiUtils().GetWorld()->PlayerControllerListField();
for (TWeakObjectPtr<APlayerController> player_controller : player_controllers)
{
const uint64 current_steam_id = get_steam_id_from_pc((AController*)player_controller.Get());
if (current_steam_id == steam_id)
{
auto* shooter_pc = static_cast<AShooterPlayerController*>(player_controller.Get());
result = shooter_pc;
break;
}
}
return result;
}version.dll installed ?version.dllversion.dll to compile your code, and version.dll contains no exports.version.dll only loads your pluginversion.dll (edited)
.obj files#if DEBUG_PLUGIN
Log::GetLog()->log(spdlog::level::info, "Plugin is in Debug mode!");
#else
Log::GetLog()->log(spdlog::level::info, "Plugin is in Release mode!");
#endifDEBUG_PLUGIN), but will be useful.d:\programs\projects\ etc when we don't even run a D: drive 

version.dllDECLARE_HOOK to help tie the two features together./* 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) (edited)master:207, open solution, compile.. this works ok for 3.2, not ok for 3.4/5DetourFindFunction function. DetourFindFunction would reduce/remove the need for PDB parsing.version.dll was compiled with
DECLARE_HOOK(setAutoAdmin, void, AShooterGameMode*, APlayerController*, bool, bool, const FPrimalPlayerCharacterConfigStruct*, UPrimalPlayerData*);
BOOL Load()
{
INIT_LOG("All Admins");
SET_HOOK("AShooterGameMode.StartNewShooterPlayer", setAutoAdmin);
LOG->info("All Admins Loaded!");
#if DEBUG_PLUGIN
LOG->debug("Debugging is enabled.");
#endif
return TRUE;
}
BOOL Unload()
{
DISABLE_HOOK("AShooterGameMode.StartNewShooterPlayer", setAutoAdmin);
return TRUE;
}SET_HOOK (and DISABLE_HOOK) are macros to compliment DECLARE_HOOKvoid Hook_setAutoAdmin(AShooterGameMode* _this, APlayerController* NewPlayer, bool bForceCreateNewPlayerData, bool bIsFromLogin, const FPrimalPlayerCharacterConfigStruct* charConfig, UPrimalPlayerData* ArkPlayerData)
{
//dostuff
}C++
ArkApi::GetHooks().DisableHook("ADroppedItemEgg.PerformanceThrottledTick_Implementation", &Hook_ADroppedItemEgg_PerformanceThrottledTick_Implementation); ?PerformanceThrottledTick is on parent class AActorfunc_Implmentation
Severity Code Description Project File Line Suppression State
Error C4996 'std::result_of<callable (AShooterPlayerController *&)>': warning STL4014: std::result_of and std::result_of_t are deprecated in C++17. They are superseded by std::invoke_result and std::invoke_result_t. You can define _SILENCE_CXX17_RESULT_OF_DEPRECATION_WARNING or _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS to acknowledge that you have received this warning. ArkAdvert D:\VisualStudio\Repository\ArkAdvert\ArkAdvert\Tools.h 9 
#ifndef _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS
#define _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS
#endif (edited)PreprocessorDefinitions
is it wise to use depreciated stuff though?\version\Core\Public\Timer.h i cant find anything that uses it to use as an exampel (edited)Timer.h uses two functions DelayExecute and RecurringExecute
i figure, if there is already a timer implementation in the API, why am i using my own thread instead of the API stuff (edited)

unknownfunction on crash logs. (searching linux ark server crashstack) (edited)
1


8997470993440060352
8218251314968812020DECLARE_HOOK(UUI_ClusterServersListSessions_ClickedButton, void, UUI_ClusterServersListSessions*, UWidget*);
void Hook_UUI_ClusterServersListSessions_ClickedButton(UUI_ClusterServersListSessions* _this, UWidget* clickedWidget)
{
UUI_ClusterServersListSessions_ClickedButton_original(_this, clickedWidget);
}
ArkApi::GetHooks().DisableHook("UUI_ClusterServersListSessions.ClickedButton", &Hook_UUI_ClusterServersListSessions_ClickedButton);
ArkApi::GetHooks().SetHook("UUI_ClusterServersListSessions.ClickedButton", &Hook_UUI_ClusterServersListSessions_ClickedButton, &UUI_ClusterServersListSessions_ClickedButton_original); (edited)local_4c8 = (wchar_t**)LoadStringCacheProperty(L"Items Not Allowed", 9);
This message comes from the client side UUI clicked function.06/25/20 00:22 [API][error] Failed to create hook for RCONClientConnection.ProcessRCONPacketShooterCharacter, but the PlayerPawnTest is all in BPScript.FName(L"your string here", EFindName::FNAME_Add, false);TerminateThread and keeping a list of active timers
GameThread::Enqueue(std::function here)createThread("my updater", updatingFunction)endThread("my updater")Hook_APrimalStructure_IsAllowedToBuild
Is called for C4 placement on structures and ground but is not called for placing on dinos. What hook am I missing for dinos? I've been looking for a bit now.APrimalStructure::BPPreventPlacementOnPawn but I guess it doesn't hook because its a "BP" function?DECLARE_HOOK(APrimalStructureExplosive_CanDetonateMe, bool, APrimalStructureExplosive*, AShooterCharacter*, bool);bool Hook_APrimalStructureExplosive_CanDetonateMe(APrimalStructureExplosive *_this, AShooterCharacter* Character, bool bUsingRemote)
{
if (ProtectExplosives)
{
const auto& NowTime = ArkApi::GetApiUtils().GetWorld()->GetTimeSeconds();
if (NowTime >= LastTime && Character)
{
AShooterPlayerController* aspc = ArkApi::GetApiUtils().FindControllerFromCharacter(Character);
if (aspc)
{
LastTime = NowTime + 1;
ArkApi::GetApiUtils().SendNotification(aspc, { 1,0,0,1 }, 2, 5, nullptr, ArkApi::Tools::Utf8Decode(PVPMessage[2]).c_str());
}
}
return false;
}
return APrimalStructureExplosive_CanDetonateMe_original(_this, Character, bUsingRemote);
} (edited)_this->ExplosionDamageField() = 0;
_this->Destroyed();
/***
Basic wrapper to call a BPFunction safely.
Please see proper usages on the template guide.
***/
void* callBlueprintFunction(UObject* object, const wchar_t* function, void* parameters)
{
if (!object || !function)
return parameters; //There's nothing to do!
UFunction* bpFunction = object->FindFunctionChecked(FName(function, EFindName::FNAME_Find, false));
if (!bpFunction)
return parameters; //There's nothing to do!
object->ProcessEvent(bpFunction, parameters);
return parameters;
} (edited)parameterscallBlueprintFunction(myPawn, L"SetNumChibiLevelUps", ¶ms);
is how easy it is to call.template<typename ...Ts> Packed f(Ts&&... args)
{
Packed packed;
packed.size = 0;
packed.size = ((sizeof(Ts) + packed.size % sizeof(Ts)) + ...);
printf("size is %i\n", packed.size);
char* memoryBlock = (char*)calloc(1, packed.size);
packed.parameters = memoryBlock;
int written = 0;
auto pack = [&memoryBlock, &packed, &written](auto& item)
{
memoryBlock += written % sizeof(item);
printf("moving %i forward...\n", written % sizeof(item));
memcpy(memoryBlock, &item, sizeof(item));
printf("wrote data to %p for a total of %i bytes.\n", memoryBlock, sizeof(item));
packed.returnValue = memoryBlock;
memoryBlock += sizeof(item); //move pointer forward
written += sizeof(item);
};
(pack(args), ...);
return packed;
}template<typename ...Ts> Packed packParameters(int returnValues, Ts&&... args)
{
Packed packed = { nullptr,nullptr, 0 };
packed.size = ((sizeof(Ts) + packed.size % sizeof(Ts)) + ...); //calculate total size with alignment.
char* memoryBlock = (char*)calloc(1, packed.size);
packed.parameters = memoryBlock; //get the block of memory for this.
int written = 0;
int maxCount = sizeof...(Ts) - returnValues;
int itemCount = 0;
/*
Function to pack the structure.
*/
auto pack = [&memoryBlock, &packed, &written, &maxCount, &itemCount](auto& item)
{
written += written % sizeof(item);
memcpy(memoryBlock+written, &item, sizeof(item));
if (itemCount++ == maxCount)
packed.returnValue = memoryBlock + written;
written += sizeof(item);
};
(pack(args), ...);
return packed;
} Packed block = packParameters(2, 65, 10., 1337, 1., nullptr, 0, 0);
((void(*)(void*))test)(block.parameters); //just to call by a function pointer
printf("Returned value %d and %d\n", *((int*)block.returnValue), *((int*)(block.returnValue + 4)));void test(MyStruct* data)
{
std::cout << "my data is " << data->a << " and " << data->b << " and " << data->c << "\n";
data->ret = 69;
data->ret2 = 420;
}struct MyStruct
{
char a;
double b;
int c;
double d;
void* e;
int ret;
int ret2;
};
(structure that it is essentially packing into)callBlueprintFunction(myPawn, L"SetNumChibiLevelUps", packParameters(0, value).parameters);packParameter(0, value) works perfectNone_Int when using an FName with itNone_181815 vs EelBossstruct inner
{
char inside_char;
double inside;
};
struct asdf
{
int a = 0;
inner b;
char c;
}; for (int i = 0; i < 100; i++)
{
inner in;
in.inside = 66. + i;
in.inside_char = 'Z' - i;
block = packParameters(0, i, in, 'A');
((void(*)(void*))test2)(block.parameters); //just to call by a function pointer
}{
"DisallowedNames":{
"BlockedList":["Human", "123", "Admin"]
}
}DisallowedNames.Reload is a console command
TEnumAsByte<EGrappleState> GrappleState_Current;DECLARE_HOOK(AShooterCharacter_AuthPostSpawnInit, void, AShooterCharacter*);ShowDebug physics ingame in the cheat menu to see positionShowDebug physics ingame in the cheat menu to see position
TArray<FString> groups = Permissions::GetPlayerGroups( steam_id );
It only returns Admins and Default, but my player is definitely part of other groups which I can list in game through the Permissions commands.
I let Permissions use its local sqlite DB too, no fancy setup here.
I assumed that loading and using Permissions would automatically "connect" to the Permissions DB, but maybe not? I feel like it's not looking at the right place.{
"Database":"sqlite",
"MysqlHost":"localhost",
"MysqlUser":"root",
"MysqlPass":"pass",
"MysqlDB":"arkdb",
"MysqlPort":3306,
"DbPathOverride":""
}/*
Fixes the selected color to be bound between 0-7.
This is for when the game transitions from the character select
to the level select menu.
*/
__declspec(naked) void correctColor()
{
__asm
{
mov al, [esi + 0x3A]
mov localVariable, al
}
pushStack();
localVariable %= 8;
ComputeRET(CorrectColor);
popStack();
__asm
{
mov al, localVariable
cmp al, 07
jmp[retJMP]
}
RET();
}APrimalStructure::GetFromID(UWorld *World, unsigned int TheStructureID) apparently there is if you use the right search termsAShooterGameState.ClusterId and AShooterGameState.IsClusterServer and see what happens but i suspect nothing as the API is not run client side. if (!Engram->bCanBeManuallyUnlocked().Get()) { return false; }
Can be manually unlocked means the player can click on it to unlock, and this makes engrams that players can't unlock not elegible for being unlocked. You could remove that line if you want tek engrams to be unlocked (edited) UPrimalPlayerData* data = (static_cast<AShooterCharacter*>(playerController->PawnField()))->GetPlayerData();
/* Find the bp Function and run it. */
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);DefeatedBoss nodestruct DefeatedBoss_Params
{
APrimalDinoCharacter* boss;
int DifficultyIndex;
FName tagOverride;
AShooterPlayerController* PC;
};struct getWorldPositionDetails_Params
{
AActor* Actor
float LatScale
float LonScale
float LatOrigin
float LonOrigin
}inline float trunc_decs(float f, int decs) {
float i1 = floor(f);
float rmnd = f - i1;
float i2 = static_cast<float>(rmnd * pow(10, decs));
float f1 = static_cast<float>(i2 / pow(10, decs));
return i1 + f1;
}
inline FVector2D GetMapCoordsFromLocation(const FVector& Pos) {
FString Map;
ArkApi::GetApiUtils().GetShooterGameMode()->GetMapName(&Map);
int divider = Map.Equals("Ragnarok") ? 13100 : 8000;
return FVector2D(Pos.X > -1 ? trunc_decs(50 + Pos.X / divider, 1) : trunc_decs(50 + Pos.X / divider, 1),
Pos.Y > -1 ? trunc_decs(50 + Pos.Y / divider, 1) : trunc_decs(50 + Pos.Y / divider, 1));
} (edited)%.2fint divider = Map.Equals("Ragnarok") ? 13100 : 8000 this is also problematicbAllowCustomName in a child of Primal Structure Item Container. I'm not sure you will find it in the dev kit.AWorldSettings* WorldSettings = ArkApi::GetApiUtils().GetWorld()->GetWorldSettings(false, true);
But I'm not clear on casting in the api yet. How do I get from AWorldSettings to APrimalWorldSettings?APrimalDinoCharacter* dino = static_cast<APrimalDinoCharacter*>(character);APrimalWorldSettings* ws = static_cast<APrimalWorldSettings*>(ArkApi::GetApiUtils().GetWorld()->GetWorldSettings(false, true));APrimalWorldSettings.h to my API source code, and was able to find LatitudeScaleField, LongitudeScaleField, LatitudeOriginField and LongitudeOriginField that I needed in APrimalWorldSettings, but when I print them to console I get these values:
Lat Scale: 5.67151e-24
Lon Scale: 5.67151e-24
Lat Origin: 5.67151e-24
Lon Origin: 5.67151e-24
Code is:
AWorldSettings* WS = ArkApi::GetApiUtils().GetWorld()->GetWorldSettings(false, true);
APrimalWorldSettings* PrimalWS = static_cast<APrimalWorldSettings*>(WS);
std::cout << "Lat Scale: " << PrimalWS->LatitudeScaleField() << "\n";
std::cout << "Lon Scale: " << PrimalWS->LongitudeScaleField() << "\n";
std::cout << "Lat Origin: " << PrimalWS->LatitudeOriginField() << "\n";
std::cout << "Lon Origin: " << PrimalWS->LongitudeOriginField() << "\n";
Anyone know what I might be doing wrong? (edited)Blueprint'/Game/PrimalEarth/Structures/Metal/Floor_Metal.Floor_Metal' where you can see Descriptive Name which sets the name of the item as shown in the HUD, as well as in the log when it's destroyed, and a couple of other places I think. (edited)
1APrimalWorldSettings. I used Lethal's structs, but and it compiles and runs fine, but when I try and read any of LatitudeScaleField, LongitudeScaleField, LatitudeOriginField and LongitudeOriginField I just get the value -0.000022 from all of them, no matter what map I'm running.
I assume it's because those structs are somehow missing from the standard API? Obviously I can't be having a custom API build just for my plugin.
Anyone else know how I might work around this?void SetChibi(AShooterPlayerController* playerController, int value)
{
AShooterCharacter* myPawn = static_cast<AShooterCharacter*>(playerController->PawnField());
UPrimalPlayerData* data = myPawn->GetPlayerData();
callBlueprintFunction(myPawn, L"SetNumChibiLevelUps", packParameters(0, value).parameters);
(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;
};0x0C70 bytes of padding should be what you need (edited)bMapSupportsMissions (edited)int b
char a
is only 5 bytes
1new operator ?static_cast<FItemNetInfo*>(FMemory::Malloc(sizeof(FItemNetInfo))) auto myItems = pc->GetPlayerInventory()->InventoryItemsField();
for (UPrimalItem* item : myItems)
{
if (item->bIsEngram()()) continue;
FString name;
item->GetItemName(&name, true, false, pc);
int amount = item->GetItemQuantity();
item->IncrementItemQuantity(-amount, true, false, false, false, false);
FItemNetID itemId = item->ItemIDField();
LOG->info(name.ToString());
LOG->info(itemId.ItemID1);
LOG->info(itemId.ItemID2);
LOG->info("------------------------------------------------------------------------------------------");
item->GenerateItemID(&itemId);
item->ItemIDField() = itemId;
item->BaseItemWeightField() = 0.f;
item->IncrementItemQuantity(amount, true, false, false, false, false);
item->AddToInventory(pc->GetPlayerInventory(), false, false, nullptr, true, false, true);
}
This is how I was doing it
1
ProcessEventUFunction for a name (and get the internal index so you don't have to keep checking name)


Hook_APrimalStructure_TakeDamage(APrimalStructure* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
EventInstigator is nullptr
DamageCauser is the C4 structure08/26/20 15:04 [Permission][error] (d:\programs\ark\plugins\permissions\permissions\private\hooks.cpp Permissions::Hooks::Hook_AShooterGameMode_HandleNewPlayer) Couldn't add player FunctionArgs args = FunctionArgs::Create()
.Add(L"some bool", false)
.Add(L"some int", 5)
.Add<int>(L"out arg");template<typename ...Rs, typename ...Ts, typename std::enable_if<sizeof...(Rs) >= 2, bool>::type = true> std::optional<std::tuple<Rs...>> ExecBP(UObject* object, std::wstring name, Ts&&... args)template<typename RT, typename ...Ts> std::optional<RT> ExecBP(UObject* object, std::wstring name, Ts&&... args)
and of course void return version
template<typename ...Ts> void ExecBP(UObject* object, std::wstring name, Ts&&... args)void ExecBP(UObject* object, std::wstring name, void* args)FString Playername;
AShooterPlayerController* shooter_pc = ArkApi::GetApiUtils().FindPlayerFromSteamId(steam_id);
shooter_pc->GetPlayerCharacterName(&Playername); 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();[Ausdrucksweise]"Ihr Lieben!!!. von Caleb"
LuL!- Solch ein Verhalten fürth zum Ausschluss..add().add().add()? template<typename T> UFunctionExec& add(std::string argName, T argValue)
{
//code
return *this;
} UFunctionExec& call()
{
//another
return *this;
}AShooterPlayerController_ClientAddFloatingDamageText but I'm not sure if that's correct or not.#include <API/Ark/Ark.h>
I installed the API as described but I don't think my Visual Studio knows where the file actually is (and I don't either ArkApi.lib library? I think I'm including it in my project so if I'm barking up the wrong tree that'd be good to know.
Also - does anyone know if there's an updated version of this video on compiling the plugins? There's a version here (https://ark-server-api.com/index.php?threads/tutorial-how-to-compile-the-plugins-your-self.628/) but it's been taken off YouTube
Again, realise I'm new and asking for help so if there's any way I can help in return let me know, I know a decent amount about C++ (although in Linux) so may be able to help there.
All the best,
Ash_Implementation is usually the actual functionClientAddFloatingText if you are adding textAShooterGameMode_HandleNewPlayer, or another hook, such as AShooterPlayerState_BeginPlay, AShooterPlayerState_NotifyPlayerJoined. Currently a little confused as to what hooks correspond to which eventsAShooterGameMode_HandleNewPlayer and AShooterGameMode_Logout"CREATE TABLE IF NOT EXISTS {} ("
"Id INT NOT NULL AUTO_INCREMENT,"
"SteamId BIGINT(11) NOT NULL DEFAULT 0,"
"PlayerId INT DEFAULT 0,"
"TribeId INT DEFAULT 0,"
"Level INT DEFAULT 0,",
"PRIMARY KEY(Id),"
"UNIQUE INDEX SteamId_UNIQUE (SteamId ASC));""CREATE TABLE IF NOT EXISTS {} ("
"Id INT NOT NULL AUTO_INCREMENT,"
"SteamId BIGINT(11) NOT NULL DEFAULT 0,"
"Kits VARCHAR(768) NOT NULL DEFAULT '{{}}',"
"Points INT DEFAULT 0,"
"TotalSpent INT DEFAULT 0,"
"PRIMARY KEY(Id),"
"UNIQUE INDEX SteamId_UNIQUE (SteamId ASC));"float Hook_AActor_TakeDamage(AActor* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
...
AShooterPlayerController* defender_aspc = static_cast<AShooterPlayerController*>(_this->GetOwnerController());
AShooterPlayerState* defender_asps = static_cast<AShooterPlayerState*>(defender_aspc->PlayerStateField()); <---- That line seems to cause the crash
But i don't know why and been trying to figure out why.AShooterPlayerController* defender_aspc = static_cast<AShooterPlayerController*>(_this->GetOwnerController()); (edited)_this->GetOwnerController() returns nullptr
UPrimalPlayerData to UPrimalPlayerDataBP_BaseTArray<float> GetAscensionDataArray(AShooterPlayerController* player_controller)
{
AShooterCharacter* shooter_char = static_cast<AShooterCharacter*>(player_controller->PawnField());
UPrimalPlayerData* data = shooter_char->GetPlayerData();
return (reinterpret_cast<UPrimalPlayerDataBP_Base*>(data))->AscensionData;
} (edited)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());
}
I'm just not sure what this part in the middle is doing.
UFunction* bpFunction = myPawn->FindFunctionChecked(FName(L"SetNumChibiLevelUps", EFindName::FNAME_Find, false));
int params[] = { value };
myPawn->ProcessEvent(bpFunction, ¶ms); (edited)(reinterpret_cast<UPrimalPlayerDataBP_Base*>(data))->NumChibiLevelUpsData = value; /* yolo */ (edited)NumChibiLevelUps variable is done one way and writing it another way. (edited) UProperty* prop = data->FindProperty(FName(L"NumChibiLevelUpsData", EFindName::FNAME_Find, false));
if (!prop) return;
prop->Set<int>(data, value);prop->Get<int>(data);data is UPrimalPlayerData* data = myPawn->GetPlayerData(); (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;
}UProperty* UObject::FindProperty(FName name)
{
for (UProperty* Property = this->ClassField()->PropertyLinkField(); Property = Property->PropertyLinkNextField();)
if (Property->NameField().Compare(&name) == 0)
return Property;
return nullptr;
}AShooterGameMode_HandleNewPlayer which runs before the player spawns?
prop->Set<int>(data, value); as you're setting a single int. I'm trying to get a TArray. I'm not sure how that works here? (edited)prop->Get<TArray<type>>(data);
Failed to load plugin - Error code 126. As soon as I remove the include for permissions and rebuild, the plugin loads normally again.
Anyone know what I might have done wrong? (edited)admincheat Broadcast <Message>, which is an example of a command we might want to run (edited)
1bool Hook_AShooterGameMode_HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* NewPlayer, UPrimalPlayerData* PlayerData, AShooterCharacter* PlayerCharacter, bool bIsFromLogin)
I'm trying to run some checks (based on server rules) on AShooterCharacter as a player transfers in to this server from another server, and either do nothing and allow them to continue, or kick them at that point.
When players try and connect to the server without transferring, then AShooterCharacter is null, so I kick them also as that doesn't meet the server rules.
It all works fine except for a couple of annoying situations where the player already has a character on the server, but when they log in AShooterCharacter still returns null so they get kicked.
This can happen, for example, if they are killed while offline, or if they die then log off without respawning.
I'm, hoping that someone will know of some way I can determine if the player is transferring in from another server or not, or perhaps some other possible way around this? (edited)Hook_AShooterGameMode_DownloadTransferredPlayer(AShooterGameMode* _this, AShooterPlayerController* NewPlayer)
Hook_AShooterPlayerController_ServerRequestDownloadPlayerCharacter_Implementation(AShooterPlayerController* _this, FArkTributePlayerData DownloadedCharacter, int spawnPointID, int spawnRegionIndex) (edited)void Hook_AShooterPlayerController_ServerCharacterUploadWithItems_Start(AShooterPlayerController* _this, unsigned __int64 PlayerDataId, FArkTributePlayerData PlayerData)
Then you'd return your copy of PlayerData with custom info inside. I'd do some Logging test to see if it prints the right info or notbool IsFirstSpawned(UPrimalPlayerData* myData)
{
FPrimalPlayerDataStruct* myDataStruct;
myDataStruct = myData->MyDataField();
return myDataStruct->bFirstSpawned().Get();
} (edited)bool val = a->bFirstSpawned()(); (edited)bFirstSpawned() returns BitFieldValue<bool, unsigned int>() on BitFieldValue<T,J> is overridden to return the value of T (edited) RT operator()() const
{
return GetNativeBitField<RT, T>(parent_, field_name_);
}BitFieldValue)And HandleNewPlayer almost never has valid Shooter Character at call but a few seconds later. How would I go about waiting those few seconds to grab ShooterCharacter without impacting performance? (edited)API::Timer::Get().DelayExecute(&callback, 10, params_PC, params_IsFromLogin);AGameMode_RemoveConnectedPlayer but I'm not sure how that one works.FUniqueNetId in the unreal engine source code on Github. It has a function ToString() that provides an FString of the Steam ID when used on the Steam platform.
Unfortunately that whole class seems to be missing from the dev kit, and instead we have
struct FUniqueNetId : IOnlinePlatformData
{
};
struct FUniqueNetIdSteam : FUniqueNetId
{
unsigned __int64 UniqueNetId;
// Functions
int GetSize() { return NativeCall<int>(this, "FUniqueNetIdSteam.GetSize"); }
FString* ToString(FString* result) { return NativeCall<FString*, FString*>(this, "FUniqueNetIdSteam.ToString", result); }
bool IsValid() { return NativeCall<bool>(this, "FUniqueNetIdSteam.IsValid"); }
FString* ToDebugString(FString* result) { return NativeCall<FString*, FString*>(this, "FUniqueNetIdSteam.ToDebugString", result); }
};
And so I'm really confused about how to get that Fstring. (edited)FUniqueNetIdSteam adds the actual steam id.FUniqueNetId, but I'm not sure how to cast it.static_cast<FUniqueNetIdSteam*>(&id);invalid type conversion error.
void Hook_AGameMode_PreLogin(AGameMode* _this, FString* Options, FString* Address, TSharedPtr<FUniqueNetId, 0>* UniqueId, FString* authToken, FString* ErrorMessage)
{
FUniqueNetId* netid = UniqueId->Get();
FUniqueNetIdSteam* steamid = static_cast<FUniqueNetIdSteam*>(&netid);
AGameMode_PreLogin_original(_this, Options, Address, UniqueId, authToken, ErrorMessage);
} (edited) FUniqueNetIdSteam* steamid = static_cast<FUniqueNetIdSteam*>(netid);FUniqueNetIdSteam? This gives me an empty string every time, even though an FUniqueNetIdSteam->IsValid() check returns true.
void Hook_AGameMode_PreLogin(AGameMode* _this, FString* Options, FString* Address, TSharedPtr<FUniqueNetId, 0>* UniqueId, FString* authToken, FString* ErrorMessage)
{
FUniqueNetIdSteam* SteamId;
FString SteamString;
SteamId = static_cast<FUniqueNetIdSteam*>(UniqueId->Get());
SteamId->ToString(&SteamString);
LogDebug("Hook_AGameMode_PreLogin -> Steam ID: " + SteamString.ToString());
AGameMode_PreLogin_original(_this, Options, Address, UniqueId, authToken, ErrorMessage);
} (edited)BeginPlay for a specific dino in a plugin, is there a proper way to do that in the api? Obviously I could hook Hook_APrimalDinoCharacter_BeginPlay and then check the supplied reference to see if it was the dino I wanted, but that seems inefficient. Is there a better way? (edited)PrimalDinoCharacter class, as it's defined in the api. Like this for example:
APrimalDinoCharacter* mydino;
float myval = mydino->GetCharacterStatusComponent()->FoodConsumptionMultiplierField();
But what if I want to deal with a specific variable that exists in the child class Ankylo_Character_BP_C that doesn't exist in the parent classes that are defined in the api? (edited)Ankylo_Character_BP_C for example.PrimalDinoCharacter rather than the actual child class.
void Hook_APrimalDinoCharacter_BeginPlay(APrimalDinoCharacter* _this)
{
UClass* myclass = _this->GetPrivateStaticClass();
FString ClassString{};
myclass->GetDescription(&ClassString);
std::cout << "BeginPlay Class: " << std::string(ClassString.ToString()) << std::endl;
APrimalDinoCharacter_BeginPlay_original(_this);
} (edited)BeginPlay Class: PrimalDinoCharacterFString 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("");
}?? in the example is supposed to be the buff class, but in what format do I provide it?
if(TestPrimalChar->HasBuff(TSubclassOf<APrimalBuff> ?? )) (edited)buff and I can see a lot of questions but no clear answers. Any suggestions on where to start?Blueprint'/Game/Aberration/CoreBlueprints/Buffs/Buff_Radiation_Sickness.Buff_Radiation_Sickness' to a UClass for that buff?void PrintBuffs(AShooterCharacter* MyChar)
{
TArray<APrimalBuff*> MyBuffs{};
if (MyChar != nullptr)
{
MyChar->GetAllBuffs(&MyBuffs);
std::cout << "Got total buffs: " << MyBuffs.Num() << std::endl;
for (auto& Element : MyBuffs)
{
UClass* BuffClass = Element->StaticClass();
if (BuffClass != nullptr)
{
UObject* MyCDO = BuffClass->ClassDefaultObjectField(); // <-- THIS CRASHES
FString DetailedInfo{};
BuffClass->GetDetailedInfo(&DetailedInfo); // <-- THIS ALSO CRASHES
}
}
}
} (edited)UClass::GetDefaultObject(true) crashes the server as well.
void PrintBuffs(AShooterCharacter* MyChar)
{
TArray<APrimalBuff*> MyBuffs{};
if (MyChar != nullptr)
{
MyChar->GetAllBuffs(&MyBuffs);
std::cout << "Got total buffs: " << MyBuffs.Num() << std::endl;
for (auto& Element : MyBuffs)
{
UClass* BuffClass = Element->StaticClass();
if (BuffClass != nullptr)
{
UObject* MyCDO = BuffClass->GetDefaultObject(true);
}
}
}
}Fatal error!
VERSION: 315.4
ShooterGameServer.exe!UClass::GetDefaultObject() (0x00007ff679a387f6) + 0 bytes [f:\build\live315\engine\source\runtime\coreuobject\public\uobject\class.h:1945]
ExtinctionBosses.dll!PrintBuffs() (0x00007ff9bbd92ecf) + 61 bytes [C:\Users\lachl\source\repos\ExtinctionBosses\Plugin\init.cpp:124]
ExtinctionBosses.dll!PrintPlayerBuffs() (0x00007ff9bbd93072) + 8 bytes [C:\Users\lachl\source\repos\ExtinctionBosses\Plugin\init.cpp:192]
VERSION.dll!ArkApi::Commands::CheckCommands<ArkApi::Commands::Command<void __cdecl(AShooterPlayerController *,FString *,enum EChatSendMode::Type)>,AShooterPlayerController * &,FString * &,enum EChatSendMode::Type &>() (0x00007ff97e336f26) + 84 bytes [I:\ARKServerAPI\version\Core\Private\Commands.h:115]
VERSION.dll!ArkApi::Hook_AShooterPlayerController_ServerSendChatMessage_Impl() (0x00007ff97e334203) + 0 bytes [I:\ARKServerAPI\version\Core\Private\Ark\HooksImpl.cpp:107]
ShooterGameServer.exe!AShooterPlayerController::execServerSendChatMessage() (0x00007ff67ad73fa7) + 343 bytes [f:\build\live315\projects\shootergame\source\shootergame\classes\shooterplayercontroller.h:309]int BuffType = Element->GetBuffType();
std::cout << "Buff Type: " << BuffType << std::endl;-2. Then the second time its run it still shows there is a single buff, but when it gets to GetBuffType() it crashes the server.{
"structures":{
"APrimalBuff"
}
} auto NetConnection = PlayerController->GetNetConnection();
auto IP = reinterpret_cast<FString*>(reinterpret_cast<char*>(NetConnection) + 0x341D8);
Log::GetLog()->info("IP: {}", IP->ToString());auto IP = *GetNativePointerField<FString*>(NetConnection, "UNetConnection.ClientGivenIP"); doesn't work, but above is a workaround for time being (edited)const FString& IPAddress = ArkApi::GetApiUtils().GetIPAddress(Player);
Where Player is AShooterPlayerController* (edited)/Script/ShooterGame.Default__PrimalBuff as the result from this.
UClass* BuffClass = MyBuff->StaticClass();
UObject* CDO = BuffClass->GetDefaultObject(true);
FString BuffBP{};
CDO->GetPathName(&BuffBP, nullptr);
std::cout << "Buff BP: " << BuffBP.ToString() << std::endl;
I can do the following and get part of the BP path for each buff, but not really enough.
FString DetailedInfo{};
BuffClass->GetDetailedInfo(&DetailedInfo);
std::cout << "Got Detailed Info: " << DetailedInfo.ToString() << std::endl; MyBuff->StaticClass(); is likely returning the static class of the base typestruct APrimalBuff put struct APrimalBuff : AActorGetAllBuffs, check if a player has a specific buff with HasBuff, remove a buff with DeactivateBuff.
The last thing I'd like to be able to do is add a buff. We use StaticAddBuff in the dev kit, which is available, but I first have to create a APrimalBuff with the correct class, which I'm not sure how to do?UClass* BuffClass = UVictoryCore::BPLoadClass(&ClassString);
APrimalBuff* TestBuff;
TestBuff->StaticAddBuff(BuffClass, ShooterCharacter, nullptr, nullptr, true);You have insufficient privileges to post threads here. if I try and post something to the plugins section.AllowPlayerToJoinNoCheck <SteamID>
It gives an error on the machine, but it adds him to the whitelist.Broacast in AGameMode but it is not.DECLARE_HOOK(UShooterCheatManager_Broadcast, void, UShooterCheatManager*, FString*);ArkApi::GetApiUtils().GetShooterCheatManager()inline AShooterGameState* GetGameState()
{
return static_cast<AShooterGameState*>(ArkApi::GetApiUtils().GetWorld()->GameStateField());
}
inline UShooterCheatManager* GetCheatManagerByPC(AShooterPlayerController* SPC)
{
if (!SPC) return nullptr;
UCheatManager* cheat = SPC->CheatManagerField();
if (cheat)
{
return static_cast<UShooterCheatManager*>(cheat);
}
return nullptr;
} (edited)ArkApi::GetApiUtils().GetGameState and ArkApi::GetApiUtils().GetShooterCheatManager()?
I think those kinds of helpers are really great for new starters and those less experienced members of the community.Hook_UGameEngine_Tick(). Am I the only one who would be very, very nervous about using that?TArray<unsigned int> tribeID = alliance.MembersTribeIDField();
although
alliance.MembersTribeIDField().Num() > 0
the second thing is true, in the case i testet, its 1, but why does my server crash when trying to get the array of the TribeIds?TArray<FTribeAlliance> tribeAlliances = tribe->TribeAlliancesField();MembersTribeIDField() returns a Array of unsigned int, so i need to or not? (edited)TArray<int> tribeID = alliance.MembersTribeIDField(); ? that doesnt work, no conversion existsTArray<int> tribeIDs
tribeIDs.Add(alliance.MembersTribeIDField())fmt, are causing conflicts with the API, which includes it's own version of that same library that is very different to the main version.
In \ARK-Server-API\version\Core\Public\Logger\spdlog\details\pattern_formatter_impl.h there calls to things like fmt::MemoryWriter and fmt::pad that don't exist in the main version of fmt that is installed by vcpkg.
It's actually the same problem in the other web libraries I've tried as well, as they all use the main fmt library. So is there any way to separate the two, so that the API uses its version and the web libraries use their version? (edited)return ((RT(*)(A...)) immutable_ptr)(args...);spdlog in the API kit with the current version, which also brought with it the current version of fmt. This allows other libraries using fmt to work correctly without conflict.std::thread([param_1, param_2]()
{
DoSomething(param_1, param_2);
}).detach(); (edited)struct VoteRewardCallback
{
uint64 steamid;
TArray<ItemReward> item_rewards;
};AShooterGameState* game_state = static_cast<AShooterGameState*>(ArkApi::GetApiUtils().GetWorld()->GameStateField());AShooterGameState* state = static_cast<AShooterGameState*>(ArkApi::GetApiUtils().GetShooterGameMode()->GameStateField());
LOG->info(state->ClusterIdField().ToString().c_str());#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) template<class = typename std::enable_if<std::is_same<VA, NO_VA>::value>::type>
RT operator()(A... args) {
if (!immutable_ptr) throw "Attempted to call null pointer.";
return ((RT(*)(A...)) immutable_ptr)(args...);
}
template<typename ...B, class = typename std::enable_if<std::is_same<VA, VA_ARGS>::value>::type>
RT operator()(A... args, B... va) {
if (!immutable_ptr) throw "Attempted to call null pointer.";
return ((RT(*)(A..., B...)) immutable_ptr)(args..., va...);
}

void loginPatch::callback(char* u, char* p)
{
isAuthenticating = true;
strcpy_s(username, 16 * sizeof(char), u);
strcpy_s(password, 16 * sizeof(char), p);
printf("User is authenticating to server...\n");
WOW::Auth::Login.original(u, p);
} DetourAttach(&WOW::Auth::Login, callback);std::string* sMsg = config["ChatCommands"]["Name"].get<std::string*>();
FString* sName = FString(sMsg.c_str());
how do i get this to work?std::string sMsg = config["ChatCommands"]["Name"];
FString sName = FString(sMsg.c_str());APrimalDinoCharacter.Die and send those details to thread for further processing because it could become quite heavy... If, for example, I need the steam id of the killer and I get an AController*, would you normally get those details in the hook function and send them to the thread, or would you send the AController ref to the thread and do everything there?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,
};
}APlayerController::ConsoleCommand() function, and it's crashing the server and throwing an error "Fatal error!", for some commands, does anyone know how to get it to fail more gracefully/give me some more info on it?APlayerController::ConsoleCommand() function, and it's crashing the server and throwing an error "Fatal error!", for some commands, does anyone know how to get it to fail more gracefully/give me some more info on it? API::Timer::Get().RecurringExecute is a really useful one. A timer callback on a loop, with a loop count limit and the option to launch the callback in a new thread. So many uses!Hook_UPrimalInventoryComponent_DropItem it triggeres, but the FItemNetInfo is empty DECLARE_HOOK(AShooterGameMode_HandleNewPlayer, bool, AShooterGameMode*, AShooterPlayerController*, UPrimalPlayerData*, AShooterCharacter*, bool);
bool Hook_AShooterGameMode_HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* NewPlayer, UPrimalPlayerData* PlayerData, AShooterCharacter* PlayerCharacter, bool bIsFromLogin)
{
return AShooterGameMode_HandleNewPlayer_original(_this, NewPlayer, PlayerData, PlayerCharacter, bIsFromLogin);
}
ArkApi::GetHooks().SetHook("AShooterGameMode.HandleNewPlayer", &Hook_AShooterGameMode_HandleNewPlayer, &AShooterGameMode_HandleNewPlayer_original);
ArkApi::GetHooks().DisableHook("AShooterGameMode.HandleNewPlayer", &Hook_AShooterGameMode_HandleNewPlayer); (edited)bool HandleNewPlayer_Implementation(AShooterPlayerController* NewPlayer, UPrimalPlayerData* PlayerData, AShooterCharacter* PlayerCharacter, bool bIsFromLogin) { return NativeCall<bool, AShooterPlayerController*, UPrimalPlayerData*, AShooterCharacter*, bool>(this, "AShooterGameMode.HandleNewPlayer_Implementation", NewPlayer, PlayerData, PlayerCharacter, bIsFromLogin); }bool HandleNewPlayer_Implementation(AShooterPlayerController* NewPlayer, UPrimalPlayerData* PlayerData, AShooterCharacter* PlayerCharacter, bool bIsFromLogin) { return NativeCall<bool, AShooterPlayerController*, UPrimalPlayerData*, AShooterCharacter*, bool>(this, "AShooterGameMode.HandleNewPlayer_Implementation", NewPlayer, PlayerData, PlayerCharacter, bIsFromLogin); } Permissions::Hooks::Hook_AShooterGameMode_HandleNewPlayer) Couldn't add player
so i tried manually adding myself into the players table and reconnected. it did the same thing but it at least let me add myself to a permission group, and i was also able to add a new group and add a permission to that group, but it's still throwing that error in console and not automatically populating the players table.ArkApi::GetApiUtils().SendNotification()
VERSION: 320.38
ShooterGameServer.exe!UClass::FindFunctionByName() (0x00007ff6cb11ec1b) + 59 bytes
[f:\build\live320\engine\source\runtime\coreuobject\private\uobject\class.cpp:3563]
ShooterGameServer.exe!UObject::FindFunctionChecked() (0x00007ff6cb145e2a) + 15 bytes [f:\build\live320\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:802]
ShooterGameServer.exe!AShooterPlayerController::ClientServerSOTFNotificationCustom() (0x00007ff6ca76191b) + 20 bytes [f:\build\live320\projects\shootergame\intermediate\build\win64\shootergameserver\inc\shootergame\shootergame.generated.1.cpp:5668]AShooterPlayerController is null checked before passing it to SendNotification(). UClass* some_class;
if (some_class != nullptr)
{
UPrimalItem* cdo_item = static_cast<UPrimalItem*>(some_class->GetDefaultObject(true));
TSubclassOf<APrimalStructure> structure_to_build = cdo_item->StructureToBuildField();
} (edited)ArkApi::GetApiUtils().SendNotification()
VERSION: 320.38
ShooterGameServer.exe!UClass::FindFunctionByName() (0x00007ff6cb11ec1b) + 59 bytes
[f:\build\live320\engine\source\runtime\coreuobject\private\uobject\class.cpp:3563]
ShooterGameServer.exe!UObject::FindFunctionChecked() (0x00007ff6cb145e2a) + 15 bytes [f:\build\live320\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:802]
ShooterGameServer.exe!AShooterPlayerController::ClientServerSOTFNotificationCustom() (0x00007ff6ca76191b) + 20 bytes [f:\build\live320\projects\shootergame\intermediate\build\win64\shootergameserver\inc\shootergame\shootergame.generated.1.cpp:5668] ArkApi::GetApiUtils().SendNotification()
VERSION: 320.38
ShooterGameServer.exe!UClass::FindFunctionByName() (0x00007ff6cb11ec1b) + 59 bytes
[f:\build\live320\engine\source\runtime\coreuobject\private\uobject\class.cpp:3563]
ShooterGameServer.exe!UObject::FindFunctionChecked() (0x00007ff6cb145e2a) + 15 bytes [f:\build\live320\engine\source\runtime\coreuobject\private\uobject\scriptcore.cpp:802]
ShooterGameServer.exe!AShooterPlayerController::ClientServerSOTFNotificationCustom() (0x00007ff6ca76191b) + 20 bytes [f:\build\live320\projects\shootergame\intermediate\build\win64\shootergameserver\inc\shootergame\shootergame.generated.1.cpp:5668] FindFunctionByName is internal in the game engine though, unsure why it's crashingShooterGameServer.exe!AShooterPlayerController::ClientServerSOTFNotificationCustom(). Is this running on SOTF?IApiUtils::SendNotification()UVictoryCore::BPLoadClass.
I used the test program below, and experimented with dozens of variations of BPString. With a few blueprints, like the one below, it worked fine. With most, it took several seconds to load the class successfully, but then later, once the server had finished starting up, it crashed.
I'm now wondering whether it's maybe due to it running too early, and maybe it needs to wait until after the server has finished starting up before using BPLoadClass...
#include <iostream>
#include <API/ARK/Ark.h>
#include <Logger/Logger.h>
#pragma comment(lib, "ArkApi.lib")
void ReadConfig()
{
FString TempBPString = ("Blueprint'/Game/PrimalEarth/CoreBlueprints/Resources/PrimalItemResource_Polymer.PrimalItemResource_Polymer'");
UClass* LoadedClass = UVictoryCore::BPLoadClass(&TempBPString);
FString TestClass;
LoadedClass->GetFullName(&TestClass, nullptr);
if (LoadedClass != nullptr)
{
std::cout << "CLASS LOADED: " << TestClass.ToString() << std::endl;
}
else {
std::cout << "CLASS NOT LOADED" << std::endl;
}
}
void Load()
{
try
{
ReadConfig();
}
catch (const std::exception& error)
{
Log::GetLog()->error(error.what());
throw;
}
}
void Unload()
{
}
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 giveRagnarokTekgrams(AShooterPlayerController* playerController)
{
const wchar_t* tekGrams[] = {
L"Blueprint'/Game/PrimalEarth/CoreBlueprints/Items/Structures/Misc/PrimalItemStructure_TekLight.PrimalItemStructure_TekLight'",
L"Blueprint'/Game/PrimalEarth/CoreBlueprints/Weapons/PrimalItem_WeaponTekSword.PrimalItem_WeaponTekSword'",
L"Blueprint'/Game/PrimalEarth/CoreBlueprints/Items/Armor/Shields/PrimalItemArmor_ShieldTek.PrimalItemArmor_ShieldTek'"
};
AShooterPlayerState* state = playerController->GetShooterPlayerState();
for (const wchar_t* gram : tekGrams)
{
TSubclassOf<UPrimalItem> tekGram;
tekGram.uClass = UVictoryCore::BPLoadClass(&FString(gram));
state->ServerUnlockEngram(tekGram, true, true);
}
}InitGame and it works fine now, at least from my first couple of tests. (edited)bool IsClassChildOf(UClass* this_class, UClass* parent_class_check)
{
if (!this_class || !parent_class_check) return false;
return this_class->IsChildOf(parent_class_check);
}APrimalStructure::GetPrivateStaticClass()APrimalStructure::GetPrivateStaticClass() doesn't work because APrimalStructure is the base class for the built structures. I'm looking for APrimalItemStructure, which is the base class for the PrimalItems for all structures. It doesn't seem to be defined anywhere in the API. (edited)UPrimalItem* new_item = UPrimalItem::AddNewItem(ItemClass, nullptr, false, false, quality, false, amount, is_bp, 0, false, nullptr, 0);
FItemNetInfo* net_info = static_cast<FItemNetInfo*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(net_info, 0x200);
new_item->GetItemNetInfo(net_info, false); (edited)DECLARE_HOOK(APrimalStructure_AllowPickupForItem, bool, APrimalStructure*, AShooterPlayerController*);
bool Hook_APrimalStructure_AllowPickupForItem(APrimalStructure* _this, AShooterPlayerController* ForPC)
{
return APrimalStructure_AllowPickupForItem_original(_this, ForPC);
}
ArkApi::GetHooks().SetHook("APrimalStructure.AllowPickupForItem", &Hook_APrimalStructure_AllowPickupForItem, &APrimalStructure_AllowPickupForItem_original);
ArkApi::GetHooks().DisableHook("APrimalStructure.AllowPickupForItem", &Hook_APrimalStructure_AllowPickupForItem);DECLARE_HOOK(APrimalStructure_AllowPickupForItem, bool, APrimalStructure*, AShooterPlayerController*);
bool Hook_APrimalStructure_AllowPickupForItem(APrimalStructure* _this, AShooterPlayerController* ForPC)
{
return APrimalStructure_AllowPickupForItem_original(_this, ForPC);
}
ArkApi::GetHooks().SetHook("APrimalStructure.AllowPickupForItem", &Hook_APrimalStructure_AllowPickupForItem, &APrimalStructure_AllowPickupForItem_original);
ArkApi::GetHooks().DisableHook("APrimalStructure.AllowPickupForItem", &Hook_APrimalStructure_AllowPickupForItem); UpdatePlayerDetailsAsync - Error: CreateAsync. The process cannot access the file 'C:\ARK\Servers\Server10\ShooterGame\Saved\SavedArks\7655211979816271.arkprofile' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.File.InternalReadAllBytes(String path, Boolean checkHost)
at ArkData.Parser.ParsePlayer(String fileName)
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at ArkData.DataContainer.<CreateAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at ServerManagerTool.Lib.ServerRCON.<UpdatePlayerDetailsAsync>d__71.MoveNext()
Its freezing our server as soon as one perticular person joins the server. BUT its not the person mentioned by the error.Size() that computes the actual size of the object in bytesClass::DefaultEmpty() and have it construct in place a char[] casted to the type.

loadlibrary the handler from the config file directly..sql files in a \SQL foldertemplate<typename T> constexpr std::tuple<T> unpackParameter(char* memoryBlock, int& offset)
{
alignMemory<T>(offset);
T item;
memcpy(&item, memoryBlock + offset, sizeof(T));
offset += sizeof(item);
return std::make_tuple(item);
}
template<typename T, typename ...Rs, typename std::enable_if<sizeof...(Rs) >= 1, bool>::type = true > constexpr std::tuple<T, Rs...> unpackParameter(char* memoryBlock, int& offset)
{
return std::tuple_cat(unpackParameter<T>(memoryBlock, offset), unpackParameter<Rs...>(memoryBlock, offset));
}
template<typename ...Rs> constexpr std::tuple<Rs...> unpackParameters(char* memoryBlock, int offset)
{
return unpackParameter<Rs...>(memoryBlock, offset);
}
template<typename ...Rs> constexpr std::tuple<Rs...> unpackParameters(char* memoryBlock)
{
return unpackParameters<Rs...>(memoryBlock, 0);
}
compile time, unpacks the struct pointed at by void* into a tuple of the supplied typestemplate<typename T> inline void alignMemory(int& offset)
{
int size = sizeof(T);
int align = alignof(T);
offset += (align - (offset % align)) % align;
}
(edited)void* unpacker using run-time reflection datastd::any that just makes a char[] the size of the propertyany castauto spongehax::process_event(sdk::UObject* who, sdk::UFunction* what, void* how) -> void
{
while(!tick_queue.empty())
{
tick_queue.front()();
tick_queue.pop();
}
const auto func = what->GetName();
auto handled = false;
for (auto [_, callback] : process_event_handlers[func])
{
handled = callback(who, how);
if (handled) break;
}
if (!handled)
process_event_.original(who, what, how);
}
1KismetSystemLibraryBPExec
shooter_pc->MulticastDrawDebugSphere(teleport.fromLoc, 300 * teleport.bubbleSizeInFoundations, 40, FLinearColor(1, 0, 0), duration, true);KismetSystemLibrary - Extra description when dino is cryos
- Configurable cryo sickness
- No sickness near base option
- auto cryo new babies in range
- optionally mature and imprint cryo babies when they are uncryod
- optionally add a not near enemy structure option
- optional no cryo after dmg/tame
- override time to cryo
- Toggle mating for area
ARK_API void AddPlayerPermissionCallback(FString CallbackName, bool onlyCheckOnline, bool cacheBySteamId, bool cacheByTribe, const std::function<TArray<FString>(uint64*, int*)>& callback);
ARK_API void RemovePlayerPermissionCallback(FString CallbackName);
FArray<FString> HasRaidProtection(uint64 steam_id, int tribeId) {
TArray<FString> result;
if (LethalORP::HasRaidProtection(tribeId))
result.add(FString("RaidProtected"));
return result;
}
FArray<FString> HasPvpCooldown(uint64 steam_id, int tribeId) {
TArray<FString> result;
if (LethalORP::HasPvpCooldown(steam_id))
result.add(FString("PvpCooldown"));
return result;
}
Permissions::AddPlayerPermissionCallback("RaidProtected", true, false, true, &HasRaidProtection);
Permissions::AddPlayerPermissionCallback("PvpCooldown", true, false, false, &HasPvpCooldown); (edited)ARK_API void AddPlayerPermissionCallback(FString CallbackName, bool onlyCheckOnline, bool cacheBySteamId, bool cacheByTribe, const std::function<TArray<FString>(uint64*, int*)>& callback);
ARK_API void RemovePlayerPermissionCallback(FString CallbackName);
FArray<FString> HasRaidProtection(uint64 steam_id, int tribeId) {
TArray<FString> result;
if (LethalORP::HasRaidProtection(tribeId))
result.add(FString("RaidProtected"));
return result;
}
FArray<FString> HasPvpCooldown(uint64 steam_id, int tribeId) {
TArray<FString> result;
if (LethalORP::HasPvpCooldown(steam_id))
result.add(FString("PvpCooldown"));
return result;
}
Permissions::AddPlayerPermissionCallback("RaidProtected", true, false, true, &HasRaidProtection);
Permissions::AddPlayerPermissionCallback("PvpCooldown", true, false, false, &HasPvpCooldown); (edited)const FString&

FUNCTION(string, append, void, const char* data)
{
unsigned int nextLength = _this->length + strlen(data);
if (!VALID(data) || nextLength == _this->length)
return;
if (nextLength >= _this->limit)
{
unsigned int nextLimit = _this->limit;
while (nextLength >= nextLimit)
nextLimit <<= 1;
_this->c_str = realloc(_this->c_str, nextLimit);
memset(_this->c_str + _this->length, 0, nextLimit - _this->limit);
_this->limit = nextLimit;
}
strcpy(_this->c_str + _this->length, data);
_this->length = nextLength;
}


auto recv(const SOCKET socket)
{
char message_buffer[1024] = { 0 };
::recv(socket, message_buffer, 1024, 0);
if (message_buffer[1023] != 0)
{
std::cout << "Message exceeds buffer and will be truncated!" << std::endl;
message_buffer[1023] = 0; //we must have a null terminator for safety.
}
return std::string(message_buffer);
}
auto send(const SOCKET socket, const std::string& message)
{
if(message.length() > 1023)
{
std::cout << "Message exceeds buffer and will be truncated!" << std::endl;
::send(socket, message.substr(0, 1023).c_str(), 1024, 0); //substr shall have a null terminator, 1023+1
}
else
{
::send(socket, message.c_str(), static_cast<int>(message.length() + 1u), 0); //1023+1
}
}char*
void Hook_UPrimalCharacterStatusComponent_AddExperience(UPrimalCharacterStatusComponent* _this, float HowMuch, bool bShareWithTribe, EXPType::Type XPType) For leveling
std::move#pragma once
#include <mutex>
#include <ostream>
#include <iostream>
class osyncstream_locked final : std::streambuf, public std::ostream
{
std::unique_lock<std::recursive_mutex> lock_;
std::ostream& stream_;
public:
osyncstream_locked(std::recursive_mutex& mtx, std::ostream& stream) : std::ostream(this), lock_(mtx), stream_(stream) {} //construct and lock the mutex from osyncstream.
osyncstream_locked(const osyncstream_locked& o) = delete;
/* A recursive mutex isn't great here (reference forwarding would be better except...only a recursive mutex can assure lock-before-release on ownership transfer */
template<typename T>
friend osyncstream_locked&& operator<<(osyncstream_locked&& os, const T& d)
{
std::cout << d;
return std::move(os); /* move semantics :( ... thanks Clang/GCC */
}
osyncstream_locked(osyncstream_locked&& o) noexcept : osyncstream_locked(*o.lock_.mutex(), o.stream_) {} //could be better... max depth 2, usual depth 1.
osyncstream_locked& operator=(osyncstream_locked&) = delete; //disallow
osyncstream_locked& operator=(osyncstream_locked&&) = delete; //disallow
~osyncstream_locked() = default;
};
class osyncstream final
{
std::recursive_mutex mutex_{};
std::ostream& stream_;
public:
explicit osyncstream(std::ostream& stream) : stream_(stream) {}
template<typename T>
friend osyncstream_locked operator<<(osyncstream& os, const T& d)
{
std::unique_lock<std::recursive_mutex> lock(os.mutex_);
os.stream_ << d;
return osyncstream_locked { os.mutex_, std::cout };
}
osyncstream& operator<<(const osyncstream_locked& d) = delete;
};
struct streams
{
static std::ostream& cout;
static std::ostream& cerr;
};
std::ostream& streams::cout = std::cout;
std::ostream& streams::cerr = std::cerr;
osyncstream sscout(streams::cout);
osyncstream sscerr(streams::cerr);<<friend osyncstream_locked operator<<(osyncstream& os, const T& d)<< std::vector<std::thread> threads;
for(int i = 0; i < 100; ++i)
{
threads.emplace_back(std::thread([&, i]()
{
for(int j = 0; j < 100; ++j)
{
sscout << "[" << (i % 10) << "]: " << "fuck" << "shit" << "up" << " " << j%10 << "\n";
}
}));
}
for (auto& thread : threads)
thread.join();
return 0;sscout is osyncstream. << on osyncstream returns osyncstream_locked which continues to keep the mutex locked
osyncstream_locked chains <<<< osyncstream_locked is destructed releasing the lock<< are output in orderstd::unique_lock<std::recursive_mutex> releases it's lock automatically via destructorstruct streams
{
static std::ostream& cout;
static std::ostream& cerr;
};
std::ostream& streams::cout = std::cout;
std::ostream& streams::cerr = std::cerr;
osyncstream sscout(streams::cout);
osyncstream sscerr(streams::cerr);sscout for safe stream cout

c++
class MapPlayer {
public:
std::wstring CharacterName, TribeName;
std::string ServerKey;
uint64 steamId;
int LastCharacterId;
};
TArray<MapPlayer>
I could make it avialable in public header from my chat (edited)c++
class MapPlayer {
public:
std::wstring CharacterName, TribeName;
std::string ServerKey;
uint64 steamId;
int LastCharacterId;
};
TArray<MapPlayer>
I could make it avialable in public header from my chat (edited)
TArray<UPrimalEngramEntry*> all_engrams_entries = static_cast<UPrimalGlobals*>(Globals::GEngine()()->GameSingletonField())->PrimalGameDataOverrideField()->EngramBlueprintEntriesField();
Thank you very much. (edited)TArray<UPrimalEngramEntry*> all_engrams_entries = static_cast<UPrimalGlobals*>(Globals::GEngine()()->GameSingletonField())->PrimalGameDataOverrideField()->EngramBlueprintEntriesField();
Thank you very much. (edited)
std::vector<AActor*> foundActors;
UGameplayStatics::GetAllActorsOfClass(
reinterpret_cast<UObject*>(ArkApi::GetApiUtils().GetWorld()),
APrimalDinoCharacter::GetPrivateStaticClass(),
&foundActors
);
for (auto* actor : foundActors) {
auto* dino = reinterpret_cast<APrimalDinoCharacter*>(actor);
if (!dino || dino->bIsVehicle().Get()) {
continue;
}
auto* inventoryComponent = dino->MyInventoryComponentField();
}
(edited)Cheat GiveItem "Blueprint'/Game/PrimalEarth/CoreBlueprints/Weapons/PrimalItemAmmo_AdvancedRifleBullet.PrimalItemAmmo_AdvancedRifleBullet'" 10 0 0
Cheat SpawnDino "Blueprint'/Game/PrimalEarth/Dinos/Tapejara/Tapejara_Character_BP.Tapejara_Character_BP'" 0 0 0 120 (edited)addpoints {steamid} 1000",
"Fixed": true,
"ForceBlueprint": false,
"Quality": 0
}
],
"Price": 1000
},points rowapi install <name>[] () {}?“You Can't Write Perfect Software. Did that hurt? It shouldn't. Accept it as an axiom of life. Embrace it. Celebrate it. Because perfect software doesn't exist. No one in the brief history of computing has ever written a piece of perfect software. It's unlikely that you'll be the first. And unless you accept this as a fact, you'll end up wasting time and energy chasing an impossible dream." - Andrew HuntUse cases , but perhaps you have other preferences. In case someone is unfamiliar with use cases, here are a couple examples:
developer i want the ability to easily dump API for development purposesapi user i want a central point to download all API plugins from3rd party i want an api for the website to pull all available plugins
, but with Windows Server Nano I might be able to get one working 
struct addrinfo_up_deleter { void operator()(addrinfo* ptr) const { ::freeaddrinfo(ptr); } };
typedef std::unique_ptr<addrinfo, addrinfo_up_deleter> addrinfo_up; /* Modern C++ shared pointer for addrinfo. */
struct popen_up_deleter { void operator()(FILE* ptr) const { pclose(ptr); } };
typedef std::unique_ptr<FILE, popen_up_deleter> popen_up; /* Modern C++ shared pointer for popen. */
static auto getaddrinfo(const std::string& address, const std::string& port) noexcept -> addrinfo_up
{
addrinfo* result{};
addrinfo hints{};
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
::getaddrinfo(address.c_str(), port.c_str(), &hints, &result); // NOLINT(bugprone-unused-return-value)
return addrinfo_up(result);
} // ReSharper disable All Just shut up resharperstd::cout << a << b << bstd::coutsscout#ifdef THREADED
std::thread(&server::accept_client_message, this, client).detach();
#else
std::thread(&server::accept_client_message, this, client).join();
#endif template<auto lb, typeof(lb) ub> [[maybe_unused]]
constexpr auto is_between(typeof(lb) x) -> bool { return (ub > x) && (x > lb); }xxmy_numbers.filter(is_between<0,100>) //numbers from 1-99



config.json as the default config file?config.json as the default config file? bool IsModLoaded()
{
FString LoadedMods;
ArkApi::GetApiUtils().GetShooterGameMode()->GetStringOption(&LoadedMods, "ServerSettings", "ActiveMods");
TArray<FString> ModsArray;
if (!LoadedMods.IsEmpty())
LoadedMods.ParseIntoArray(ModsArray, L",", true);
return ModsArray.Contains(L"1925654247");
}
Permissions that shipped with the base was using mysql as default?mysql as default. But i think that was with the old one@everyone announcement in #【📢】ᴀɴɴᴏᴜɴᴄᴇᴍᴇɴᴛꜱ to make sure everyone is aware? It's such an important release exceptions are intercepted before the application cycles comes to a halt.
I can't help but imagine there being a similar option available for the plugin framework.exceptions are intercepted before the application cycles comes to a halt.
I can't help but imagine there being a similar option available for the plugin framework. -stackonexitrequest-stackonexitrequest this would generate that, in most cases?mcr.microsoft.com/windows:1809-stackonexitrequest would cause issues? Like, i'm working with production environments here Windows Dockers using his GameServerApp program?
The .DMP files are useless for server owners who don't know the dev side of reading .DMPs. The goal would be making it more consumer friendly for server owners but how is that possible if windows dockers don't produce crashstacks when servers crash.plussuccess: 1
response: {"message": "400: Bad Request", "code": 0} AShooterGameState* ShooterGameState = static_cast<AShooterGameState*>(ArkApi::GetApiUtils().GetShooterGameMode()->GameStateField());
ShooterGameState->HTTPPostRequest(URL, CONTENT);?claim STEAM_ID64 but i dont know if it require a plugin on the server too?.
sry bad english.
just a reminder i know how to make a bot, like i have alot of knowledge in javascript and node.js so is easy for me to make discord bot. (edited)STEAM_ID64 (edited)addpoints {Id} 5000config.json has new fields for the individual tables. If those fields arent present, will it fallback to some default value?UEngine.Init fails to hook[bla bla] is left out at GSA. This should make it easier to add tags / info to your plugin name and be compatible with guidelines #include <iostream>
#define WIN32_LEANANDMEAN
#include <Windows.h>
#include <detours.h>
void asdf(int a, char b, int c)
{
printf("%d %c %d\n", a, b, c);
}
auto duh = &asdf;
void resolver()
{
printf("this is the hooked function\n");
}
__declspec(naked) void intermediate()
{
__asm {
pushad
pushfd
}
resolver();
__asm {
popfd
popad
jmp duh
}
}
int main()
{
asdf(420, 'f', 69);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)duh, intermediate);
DetourTransactionCommit();
asdf(420, 'f', 69);
std::cout << "Hello World!\n";
}
__declspec(naked) void memes()
{
__asm {
pushad
pushfd
}
printf("This executes before the function call\n");
__asm {
popfd
popad
mov original, ebp
pop ebp
call duh
}
printf("This executes after the function call\n");
__asm {
push ebp
mov ebp, original
ret
}
}__declspec(naked) void memes()
{
__asm {
pushad
pushfd
}
printf("This executes before the function call\n");
__asm {
popfd
popad
mov original, ebp
pop ebp
call duh
}
printf("This executes after the function call\n");
__asm {
push ebp
mov ebp, original
ret
}
} void memes()
{
__asm {
leave //fuck this stack
pushfd //don't fuck this stack
pushad
}
int j = 10;
void* ret = 0;
for(int i = 0; i < 100; ++i)
{
__asm {
popad //let's GOO
popfd
mov original, ebp
pop ebp
call next //prehook
call duh
push ebp
mov ebp, original
pushfd
pushad
}
}
printf("This executes after the function call : %d\n", j);
__asm {
popad
popfd
ret
}
}Hook_AShooterPlayerController_ServerRequestLevelUp_ImplementationHook_AShooterPlayerController_ServerRequestLevelUp_Implementation APrimalCharacter* Character;
if(Character->IsA(AShooterCharacter::GetPrivateStaticClass())){
// Is a player
}
if (Character->IsA(APrimalDinoCharacter::GetPrivateStaticClass())){
// Is a dino
}void Hook_AShooterPlayerController_ServerRequestLevelUp_Implementation(AShooterPlayerController* _this, UPrimalCharacterStatusComponent* forStatusComp, EPrimalCharacterStatusValue::Type ValueType)
{
if (AActor* Owner = forStatusComp->GetOwner();
Owner && Owner->IsA(AShooterCharacter::GetPrivateStaticClass()))
{
AShooterCharacter* Char = static_cast<AShooterCharacter*>(Owner);
}
AShooterPlayerController_ServerRequestLevelUp_Implementation_original(_this, forStatusComp, ValueType);
}
1Localhost for IP section in config. It doesn't hurt to use the main IPv4 address when possible as not every plugin configuration file supports LocalHost for 127.0.0.1 mainly issues with reverse proxies for ddos protection setups and such. This can also effect web host like Nitrado/G-Portal aswell.
Notes:
% which can restrict usage if servers are on other machines outside of localhost.ROOT for plugins for security measures. Root accounts of anything is the last account you would want attacked from outside sources.PluginDB account you created has the right permissions when creating new database schema's and altering the current database schema's. This tends to resolve some errors later down the road when plugin configuration requires certain altering table functions and being restricted by the user account not having the proper permissions.SpawnActor, but I was wondering if there's any more specific functions involved for dinos.SpawnActor, but I was wondering if there's any more specific functions involved for dinos. Conformance Mode to No allowed the basic DLL project to then compile.
1Structure->RootComponentField()->RelativeLocationField();void Hook_UPrimalInventoryComponent_AddArkTributeItem(UPrimalInventoryComponent* _this, FItemNetInfo* theItemInfo, bool bFromLoad)
If I use this hook to send items to another server, the server will be stuck for several seconds to tens of secondsAPrimalStructureBed not being a child of APrimalStructure in the API. Is there any quick way to fix this?APrimalStructureBed not being a child of APrimalStructure in the API. Is there any quick way to fix this? Actor->MulticastProperty(), I can't seem to get it right.



1
FString GetTribeName(AShooterPlayerController* playerController)
{
std::string tribeName;
auto playerState = reinterpret_cast<AShooterPlayerState*>(playerController->PlayerStateField());
if (playerState)
{
auto tribeData = playerState->MyTribeDataField();
tribeName = tribeData->TribeNameField().ToString();
}
return tribeName.c_str();
}FString GetTribeName(AShooterPlayerController* playerController)
{
std::string tribeName;
auto playerState = reinterpret_cast<AShooterPlayerState*>(playerController->PlayerStateField());
if (playerState)
{
auto tribeData = playerState->MyTribeDataField();
tribeName = tribeData->TribeNameField().ToString();
}
return tribeName.c_str();
} UClass* BuffClass = UVictoryCore::BPLoadClass(&ClassString);
if (BuffClass != nullptr) {
APrimalBuff* MyBuff;
MyBuff->StaticAddBuff(BuffClass, PlayerCharacter, nullptr, nullptr, true);
}UClass* BuffClass = UVictoryCore::BPLoadClass(&ClassString);
if (BuffClass != nullptr) {
APrimalBuff* MyBuff;
MyBuff->StaticAddBuff(BuffClass, PlayerCharacter, nullptr, nullptr, true);
} Hook_UWorld_SpawnActor and wild dino spawns. I' making some modifications to dino spawns as they go through. Unfortunately it's also picking up when tamed dinos are released (spawned) from cryopods. Does anyone happen to know how to determine if a dino is spawned wild or from a cryo? That function returns an FActorSpawnParameters which includes two actor references, "Owner" and "Instigator", unfortunately both are null when spawning dinos either wild or from cryo. None of the other spawn params are obviously related to being wild or tamed or anything else that would help.
Does anyone know a way of working out what is wild vs tamed spawn? (edited)AMissionType::CanStartMissionAMissionType::CanStartMission AMissionType::CanStartMission (void)AActor* Hook_UWorld_SpawnActor(UWorld* _this, UClass* Class, FVector* Location, FRotator* Rotation, FActorSpawnParameters* SpawnParameters)
FActorSpawnParameters looks like this:
struct FActorSpawnParameters
{
FName Name;
AActor *Template;
AActor *Owner;
APawn *Instigator;
ULevel *OverrideLevel;
unsigned __int32 bNoCollisionFail : 1;
unsigned __int32 bRemoteOwned : 1;
unsigned __int32 bNoFail : 1;
unsigned __int32 bDeferruction : 1;
unsigned __int32 bAllowDuringructionScript : 1;
unsigned __int32 bDeferBeginPlay : 1;
int ExtraSpawnData;
EObjectFlags ObjectFlags;
USceneComponent *AttachToComponent;
FName AttachToBoneName;
};
In the hook I can always see Class, Location and Rotation. In some rare (no-dino) cases I can see SpawnParameters->Instigator as well, but SpawnParameters->Template is always a nullptr, and I'm guessing it holds all the required information to spawn the dino. SpawnParameters->Owner is always nullptr and SpawnParameters->Instigator usually is also.
Does anyone have any ideas? (edited)AActor* Hook_UWorld_SpawnActor(UWorld* _this, UClass* Class, FVector* Location, FRotator* Rotation, FActorSpawnParameters* SpawnParameters)
FActorSpawnParameters looks like this:
struct FActorSpawnParameters
{
FName Name;
AActor *Template;
AActor *Owner;
APawn *Instigator;
ULevel *OverrideLevel;
unsigned __int32 bNoCollisionFail : 1;
unsigned __int32 bRemoteOwned : 1;
unsigned __int32 bNoFail : 1;
unsigned __int32 bDeferruction : 1;
unsigned __int32 bAllowDuringructionScript : 1;
unsigned __int32 bDeferBeginPlay : 1;
int ExtraSpawnData;
EObjectFlags ObjectFlags;
USceneComponent *AttachToComponent;
FName AttachToBoneName;
};
In the hook I can always see Class, Location and Rotation. In some rare (no-dino) cases I can see SpawnParameters->Instigator as well, but SpawnParameters->Template is always a nullptr, and I'm guessing it holds all the required information to spawn the dino. SpawnParameters->Owner is always nullptr and SpawnParameters->Instigator usually is also.
Does anyone have any ideas? (edited)FActorSpawnParameters must have the data in it, otherwise nothing would spawn. So it must have something to do with how its being read in the api.FActorSpawnParameters must have the data in it, otherwise nothing would spawn. So it must have something to do with how its being read in the api. FActorSpawnParameters for me that would be really appreciated FActorSpawnParameters for me that would be really appreciated FActorSpawnParameters isn't null. Just some parameters of it are. And I can't understand how the function would work if those parameters are null. You would end up with an vanilla actor with no parameters.FActorSpawnParameters is correct. I don't think it is.struct __cppobj FActorSpawnParameters
{
FName Name;
AActor *Template;
AActor *Owner;
APawn *Instigator;
ULevel *OverrideLevel;
unsigned __int32 bNoCollisionFail : 1;
unsigned __int32 bRemoteOwned : 1;
unsigned __int32 bNoFail : 1;
unsigned __int32 bDeferConstruction : 1;
unsigned __int32 bAllowDuringConstructionScript : 1;
unsigned __int32 bDeferBeginPlay : 1;
int ExtraSpawnData;
EObjectFlags ObjectFlags;
USceneComponent *AttachToComponent;
FName AttachToBoneName;
};struct __cppobj FActorSpawnParameters
{
FName Name;
AActor *Template;
AActor *Owner;
APawn *Instigator;
ULevel *OverrideLevel;
unsigned __int32 bNoCollisionFail : 1;
unsigned __int32 bRemoteOwned : 1;
unsigned __int32 bNoFail : 1;
unsigned __int32 bDeferConstruction : 1;
unsigned __int32 bAllowDuringConstructionScript : 1;
unsigned __int32 bDeferBeginPlay : 1;
int ExtraSpawnData;
EObjectFlags ObjectFlags;
USceneComponent *AttachToComponent;
FName AttachToBoneName;
}; struct FActorSpawnParameters
{
FActorSpawnParameters()
: Name()
, Template(NULL)
, Owner(NULL)
, Instigator(NULL)
, OverrideLevel(NULL)
, bNoCollisionFail(0)
, bRemoteOwned(false)
, bNoFail(false)
, bDeferruction(false)
, bAllowDuringructionScript(false)
, bDeferBeginPlay(0)
, ExtraSpawnData(0)
, ObjectFlags(EObjectFlags::RF_Transactional)
, AttachToComponent(nullptr)
{
}
FName Name;
AActor *Template;
AActor *Owner;
APawn *Instigator;
ULevel *OverrideLevel;
unsigned __int32 bNoCollisionFail : 1;
unsigned __int32 bRemoteOwned : 1;
unsigned __int32 bNoFail : 1;
unsigned __int32 bDeferruction : 1;
unsigned __int32 bAllowDuringructionScript : 1;
unsigned __int32 bDeferBeginPlay : 1;
int ExtraSpawnData;
EObjectFlags ObjectFlags;
USceneComponent *AttachToComponent;
FName AttachToBoneName;
};AActor* Hook_UWorld_SpawnActor(UWorld* _this, UClass* Class, FVector* Location, FRotator* Rotation, FActorSpawnParameters* SpawnParameters)
{
if(SpawnParameters->Owner == nullptr)
{
std::cout << "Owner is null" << std::endl;
} else {
std::cout << "Owner is not null << std::endl;
}
return UWorld_SpawnActor_original(_this, Class, Location, Rotation, SpawnParameters);
}APrimalDinoCharacter::SpawnDinoDECLARE_HOOK(APrimalDinoCharacter_APrimalDinoCharacter*, APrimalDinoCharacter*, APrimalDinoCharacter*, UWorld*, TSubclassOf<APrimalDinoCharacter>, FVector, FRotator, float, int, bool, bool, int, bool, float, int, bool);
APrimalDinoCharacter* Hook_APrimalDinoCharacter_APrimalDinoCharacter*(APrimalDinoCharacter* _this, UWorld* World, TSubclassOf<APrimalDinoCharacter> DinoClass, FVector SpawnLoc, FRotator SpawnRot, float LevelMultiplier, int ExtraLevelOffset, bool AddLevelOffsetBeforeMultiplier, bool bOverrideBaseNPCLevel, int BaseLevelOverrideValue, bool bNPCDontWander, float NPCAIRangeMultiplier, int NPCAbsoluteBaseLevel, bool bSpawnWithoutCapsuleOffset)
{
return APrimalDinoCharacter_APrimalDinoCharacter*_original(_this, World, DinoClass, SpawnLoc, SpawnRot, LevelMultiplier, ExtraLevelOffset, AddLevelOffsetBeforeMultiplier, bOverrideBaseNPCLevel, BaseLevelOverrideValue, bNPCDontWander, NPCAIRangeMultiplier, NPCAbsoluteBaseLevel, bSpawnWithoutCapsuleOffset);
}
ArkApi::GetHooks().SetHook("APrimalDinoCharacter.APrimalDinoCharacter*", &Hook_APrimalDinoCharacter_APrimalDinoCharacter*, &APrimalDinoCharacter_APrimalDinoCharacter*_original);
ArkApi::GetHooks().DisableHook("APrimalDinoCharacter.APrimalDinoCharacter*", &Hook_APrimalDinoCharacter_APrimalDinoCharacter*);APrimalDinoCharacter::SpawnDino. This is what actually works:
DECLARE_HOOK(APrimalDinoCharacter_SpawnDino, APrimalDinoCharacter*, APrimalDinoCharacter*, UWorld*, TSubclassOf<APrimalDinoCharacter>, FVector, FRotator, float, int, bool, bool, int, bool, float, int, bool);
APrimalDinoCharacter* Hook_APrimalDinoCharacter_SpawnDino(APrimalDinoCharacter* _this, UWorld* World, TSubclassOf<APrimalDinoCharacter> DinoClass, FVector SpawnLoc, FRotator SpawnRot, float LevelMultiplier, int ExtraLevelOffset, bool AddLevelOffsetBeforeMultiplier, bool bOverrideBaseNPCLevel, int BaseLevelOverrideValue, bool bNPCDontWander, float NPCAIRangeMultiplier, int NPCAbsoluteBaseLevel, bool bSpawnWithoutCapsuleOffset)
{
return APrimalDinoCharacter_APrimalDinoCharacter*_original(_this, World, DinoClass, SpawnLoc, SpawnRot, LevelMultiplier, ExtraLevelOffset, AddLevelOffsetBeforeMultiplier, bOverrideBaseNPCLevel, BaseLevelOverrideValue, bNPCDontWander, NPCAIRangeMultiplier, NPCAbsoluteBaseLevel, bSpawnWithoutCapsuleOffset);
}
ArkApi::GetHooks().SetHook("APrimalDinoCharacter.SpawnDino", &Hook_APrimalDinoCharacter_SpawnDino, &APrimalDinoCharacter_SpawnDino_original);
ArkApi::GetHooks().DisableHook("APrimalDinoCharacter.SpawnDino", &Hook_APrimalDinoCharacter_SpawnDino);Faulting application name: ShooterGameServer.exe, version: 4.5.1.0, time stamp: 0x60a468c1
Faulting module name: ShooterGameServer.exe, version: 4.5.1.0, time stamp: 0x60a468c1
Exception code: 0xc0000005
Fault offset: 0x0000000000ced81e
Faulting process id: 0x19e4
Faulting application start time: 0x01d757c43eb80d86
Faulting application path: C:\ARKServer\Servers\Server4\ShooterGame\Binaries\Win64\ShooterGameServer.exe
Faulting module path: C:\ARKServer\Servers\Server4\ShooterGame\Binaries\Win64\ShooterGameServer.exe
Report Id: aa0bab02-e578-4dca-b339-f6b514bc7f09
Faulting package full name:
Faulting package-relative application ID: LowLevelFatalError [File:E:\build\GEN2DLC\Engine\Source\Runtime\Core\Private\HAL\FileManagerGeneric.cpp] [Line: 608]
Invalid BufferCount=0 while reading C:/Program Files/ArkServerManager/fr/Servers/Server1/ShooterGame/Content/Localization/Game/fr/ShooterGame.locres. Pos=0, Size=0, PrecacheSize=2147483647, PrecacheOffset=0
I wouldn't know how to put my crashstack file :/LowLevelFatalError [File:E:\build\GEN2DLC\Engine\Source\Runtime\Core\Private\HAL\FileManagerGeneric.cpp] [Line: 608]
Invalid BufferCount=0 while reading C:/Program Files/ArkServerManager/fr/Servers/Server1/ShooterGame/Content/Localization/Game/fr/ShooterGame.locres. Pos=0, Size=0, PrecacheSize=2147483647, PrecacheOffset=0
I wouldn't know how to put my crashstack file :/ AShooterGameModeHooked::HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* Player, UPrimalPlayerData* PlayerData, AShooterCharacter* PlayerCharacter, bool bIsFromLogin) the PlayerCharacter is NULL if the player just transfered to the server. It is filled if the player logs out on the map and logs back in. Any way to get the AShooterCharacter even in transfer? I think Player->GetPlayerCharacter(); is NULL as well.Hook_APlayerController_ServerReceivedPlayerControllerAck_Implementation(APlayerController* _this)TSubclassOf<APrimalDinoCharacter> in Hook_ANPCZoneManager_SpawnNPC. I normally do UClass->GetDefaultObject(true)->GetFullName(&PathName, nullptr) to get a string of the class path, but if I try that it crashes the server. It's not null.
If I do UClass->GetFullName(&PathName, nullptr) then it doesn't crash but returns an empty string.
. Thanks in advance!
. Thanks in advance! - (329.45) so you could use that
Buyer 99% of the time. The evidence has to be overwhelming for the Seller to actually win the case itself. Paypal has a "Seller Protection" program that basically promises it's customers they have their backs. They do this to prevent them from losing potential future customers. The best method to prevent that is using a third party service that adds a safeguard for the actual sellers themselves. Tebex adds this with their new Checkout program but you have to pay monthly for it there are some free services out there that also offer the seller protection. General rule of thumb if your selling plugins outside of API website have them send it as Friends/Family to prevent any charge backs. We've banned people on both sides on API site and discord for scamming as it goes against our TOS. Having good security and HWID protection in paid plugins also is really nice as if anyone charges backs for an invalid reason you would ban and remove their activation. (edited)SHOOTERGAME_BPActivateMissionActors__
SHOOTERGAME_BPAllowPlayerToLeaveMission__
SHOOTERGAME_BPCanRideMissionDino__
SHOOTERGAME_BPCanSpawnMission__
SHOOTERGAME_BPDeactivateMissionActors__
SHOOTERGAME_BPGenerateMissionRewards__
SHOOTERGAME_BPGetExtraLocalMissionIndicators__
SHOOTERGAME_BPGetMissionStartLocation__
SHOOTERGAME_BPGetMissionTimerText__
SHOOTERGAME_BPOnMissionActivated__
SHOOTERGAME_BPOnMissionCheat__
SHOOTERGAME_BPOnMissionComplete__
SHOOTERGAME_BPOnMissionDeactivated__
SHOOTERGAME_BPOnMissionDinoDamage__
SHOOTERGAME_BPOnMissionDinoDied__
SHOOTERGAME_BPOnMissionDroppedItemPickedUp__
SHOOTERGAME_BPOnMissionPlayerAddedInventoryItem__
SHOOTERGAME_BPOnMissionPlayerDied__
SHOOTERGAME_BPOnMissionPlayerRemovedInventoryItem__
SHOOTERGAME_BPOnMissionPlayerRespawned__
SHOOTERGAME_BPOnMissionServerSetup__
SHOOTERGAME_BPOnMissionStarted__
SHOOTERGAME_BPOnMissionStructureDamage__
SHOOTERGAME_BPOnMissionStructureDestroyed__
SHOOTERGAME_BPOnMissionSuspended__
SHOOTERGAME_BPOnMissionTimedOut__
SHOOTERGAME_BPOnMissionTriggerBeginOverlap__
SHOOTERGAME_BPOnMissionTriggerEndOverlap__
SHOOTERGAME_BPOnPlayerAddedToMission__
SHOOTERGAME_BPOnPlayerRemovedFromMission__
SHOOTERGAME_BPOnRunningMissionDeactivated__
SHOOTERGAME_BPOverrideMissionIndicatorString__
SHOOTERGAME_BPOverrideMissionTimerColor__
SHOOTERGAME_BPOverrideMultiUseMissionList__
SHOOTERGAME_BPStaticCanStartMission__
SHOOTERGAME_BPStaticIsPlayerEligibleForMission__
SHOOTERGAME_ClientMissionEligibilityResponse__
SHOOTERGAME_ClientMissionEvent__
SHOOTERGAME_ClientSendMissionAlert__
SHOOTERGAME_ClientSendMissionNotification__
SHOOTERGAME_GetIntFromMissionType__
SHOOTERGAME_GetMissionDisplayName__
SHOOTERGAME_IsMissionComplete__
SHOOTERGAME_IsValidDispatcherForMissionType__
SHOOTERGAME_MultiActivateMissionActors__
SHOOTERGAME_MultiDeactivateMissionActors__
SHOOTERGAME_MultiMissionPhaseEnded__
SHOOTERGAME_MultiMissionPhaseStarted__
SHOOTERGAME_MultiMissionStateChange__
SHOOTERGAME_MultiResetMissionTimer__
SHOOTERGAME_MultiUpdateMissionData_Bool__
SHOOTERGAME_MultiUpdateMissionData_Int__
SHOOTERGAME_OnMissionPhaseEnded__
SHOOTERGAME_OnMissionPhaseStarted__
SHOOTERGAME_OnMyPlayerMissionComplete__
SHOOTERGAME_OnMyPlayerMissionStarted__
SHOOTERGAME_SendMissionAlertToAllPlayers__
SHOOTERGAME_SendMissionAlertToPlayer__
SHOOTERGAME_ServerRequestCancelMission__
SHOOTERGAME_ServerRequestCreateMissionDataBuff__
SHOOTERGAME_ServerRequestEquipMissionItem__
SHOOTERGAME_ServerRequestMissionEligibilityCheck__
SHOOTERGAME_ServerRequestStartMission__
SHOOTERGAME_SetMissionMusic__
SHOOTERGAME_StaticOnMissionDataInitialized__
SHOOTERGAME_StaticOnReplicatedMissionDataUpdated__AMissionDispatchervoid __fastcall AMissionDispatcher::BPActivateMissionActors(AMissionDispatcher *this) and _BOOL8 __fastcall AMissionType::BPAllowPlayerToLeaveMission(AMissionType *this, AShooterCharacter *PlayerPawn)
Then you need to create struct AMissionDispatcher, (In PrimalStructure.h or Actor.h depening on it's parent, or make a new Missions.h and add it to includes of Ark.h)
then you have to do this following the signature of the found function:
struct AMissionDispatcher : APrimalStructureItemContainer
{
// Functions
void BPActivateMissionActors() { NativeCall<void>(this, "AMissionDispatcher.BPActivateMissionActors"); }
}
struct AMissionType : AActor
{
// Functions
bool BPAllowPlayerToLeaveMission(AShooterCharacter* PlayerPawn) { return NativeCall<bool, AShooterCharacter*>(this, "AMissionType.BPAllowPlayerToLeaveMission", PlayerPawn); }
}void __fastcall AMissionDispatcher::BPActivateMissionActors(AMissionDispatcher *this) and _BOOL8 __fastcall AMissionType::BPAllowPlayerToLeaveMission(AMissionType *this, AShooterCharacter *PlayerPawn)
Then you need to create struct AMissionDispatcher, (In PrimalStructure.h or Actor.h depening on it's parent, or make a new Missions.h and add it to includes of Ark.h)
then you have to do this following the signature of the found function:
struct AMissionDispatcher : APrimalStructureItemContainer
{
// Functions
void BPActivateMissionActors() { NativeCall<void>(this, "AMissionDispatcher.BPActivateMissionActors"); }
}
struct AMissionType : AActor
{
// Functions
bool BPAllowPlayerToLeaveMission(AShooterCharacter* PlayerPawn) { return NativeCall<bool, AShooterCharacter*>(this, "AMissionType.BPAllowPlayerToLeaveMission", PlayerPawn); }
} void __fastcall AMissionDispatcher::BPActivateMissionActors(AMissionDispatcher *this) and _BOOL8 __fastcall AMissionType::BPAllowPlayerToLeaveMission(AMissionType *this, AShooterCharacter *PlayerPawn)
Then you need to create struct AMissionDispatcher, (In PrimalStructure.h or Actor.h depening on it's parent, or make a new Missions.h and add it to includes of Ark.h)
then you have to do this following the signature of the found function:
struct AMissionDispatcher : APrimalStructureItemContainer
{
// Functions
void BPActivateMissionActors() { NativeCall<void>(this, "AMissionDispatcher.BPActivateMissionActors"); }
}
struct AMissionType : AActor
{
// Functions
bool BPAllowPlayerToLeaveMission(AShooterCharacter* PlayerPawn) { return NativeCall<bool, AShooterCharacter*>(this, "AMissionType.BPAllowPlayerToLeaveMission", PlayerPawn); }
} 


.dll to .dll.arkapi will world save and reload the plugin using the second .dll.arkapi file.
2AShooterPlayerController* playerController = static_cast<AShooterPlayerController*>(controller);
if (playerController != nullptr)
{
steam_id = playerController->GetUniqueNetIdAsUINT64();
}
return steam_id; (edited)GetUniqueNetIdAsUINT64 or an internal WC function. static uint64 GetSteamIdFromController(AController* controller)
{
uint64 steam_id = 0;
AShooterPlayerController* playerController = static_cast<AShooterPlayerController*>(controller);
if (playerController != nullptr)
{
steam_id = playerController->GetUniqueNetIdAsUINT64();
}
return steam_id;
}


PerLevelStatsMultiplier_Player per player? And which function can i use for it?AShooterGameMode_SaveWorld.Hook_APrimalDinoCharacter_TakeDamage: is it possible to check if it is a specific gen2 mission and a mission weapon or maybe taking on non mission weapon is not allowed?API::Requests::Get().CreateGetRequest(url, std::bind(&function, std::placeholders::_1, std::placeholders::_2, yourVar1, yourVar2)); (edited)ARK_API bool CreatePostRequest(const std::string& url,
const std::function<void(bool, std::string)>& callback,
const std::string& post_data,
const std::string& content_type,
std::vector<std::string> headers = {});
It took ages to actually get this error out:
2814:6a8c @ 44492234 - LdrpNameToOrdinal - WARNING: Procedure "?CreatePostRequest@Requests@API@@QEAA_NAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV?$function@$$A6AX_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z@4@00V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@4@@Z" could not be located in DLL at base 0x00007FF8AF900000.
Can any of you decipher this? It seems like the overload is just broken.ARK_API bool CreatePostRequest(const std::string& url,
const std::function<void(bool, std::string)>& callback,
const std::string& post_data,
const std::string& content_type,
std::vector<std::string> headers = {});
It took ages to actually get this error out:
2814:6a8c @ 44492234 - LdrpNameToOrdinal - WARNING: Procedure "?CreatePostRequest@Requests@API@@QEAA_NAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBV?$function@$$A6AX_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z@4@00V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@4@@Z" could not be located in DLL at base 0x00007FF8AF900000.
Can any of you decipher this? It seems like the overload is just broken.
1
std::any and doing
hookableFunction<RT, VA, A...>& test()
{
return std::any_cast<hookableFunction<RT, VA, A...>&>(hookable);
}
hookfor(hook : hooks)
unhook(hook)
where unhook might be like
DetourDetach(hook.hookable, hook.callback);
static hookable<void, sdk::UObject*, sdk::UFunction*, void*> process_event_;process_event_.reset(sdk::UObject::StaticClass(), 66);
and attach the hook
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(process_event_.get(), process_event);
DetourTransactionCommit();auto spongehax::process_event(sdk::UObject* who, sdk::UFunction* what, void* how) -> void
{
while(!tick_queue.empty())
{
tick_queue.front()();
tick_queue.pop();
}
const auto func = what->GetName();
auto handled = false;
for (auto [_, callback] : process_event_handlers[func])
{
handled = callback(who, how);
if (handled) break;
}
if (!handled)
process_event_.original(who, what, how);
}
APrimalDinoCharacter::DoMate? I've hooked it as per usual but it won't run.DECLARE_HOOK(AActor_BPServerHandleNetExecCommand, bool, AActor*, APlayerController*, FName, FBPNetExecParams*);
bool Hook_AActor_BPServerHandleNetExecCommand(AActor* _this, APlayerController* FromPC, FName CommandName, FBPNetExecParams* ExecParams)
{
if (config["PreventionOptions"].value("PatchCloningEnemyDinos", true))
{
if (FromPC
&& CommandName.ToString().Find(L"Clone") != -1)
{
APrimalDinoCharacter* toClone = (APrimalDinoCharacter*)ExecParams->ObjParam1;
if (toClone)
{
const int pcTribe = ((AShooterPlayerController*)FromPC)->TargetingTeamField();
const int dinoTribe = toClone->TargetingTeamField();
if (pcTribe != dinoTribe)
return false;
}
}
}
return AActor_BPServerHandleNetExecCommand_original(_this, FromPC, CommandName, ExecParams);
}
ArkApi::GetHooks().SetHook("AActor.BPServerHandleNetExecCommand", &Hook_AActor_BPServerHandleNetExecCommand, &AActor_BPServerHandleNetExecCommand_original);
ArkApi::GetHooks().DisableHook("AActor.BPServerHandleNetExecCommand", &Hook_AActor_BPServerHandleNetExecCommand);
This is what I use in my anti grief plugin @🐨Dream Doctor🦘struct FBPNetExecParams
{
int IntParam1;
int IntParam2;
int IntParam3;
float FloatParam1;
float FloatParam2;
float FloatParam3;
UObject* ObjParam1;
UObject* ObjParam2;
UObject* ObjParam3;
FString StringParam1;
};DECLARE_HOOK(AActor_BPServerHandleNetExecCommand, bool, AActor*, APlayerController*, FName, FBPNetExecParams*);
bool Hook_AActor_BPServerHandleNetExecCommand(AActor* _this, APlayerController* FromPC, FName CommandName, FBPNetExecParams* ExecParams)
{
if (config["PreventionOptions"].value("PatchCloningEnemyDinos", true))
{
if (FromPC
&& CommandName.ToString().Find(L"Clone") != -1)
{
APrimalDinoCharacter* toClone = (APrimalDinoCharacter*)ExecParams->ObjParam1;
if (toClone)
{
const int pcTribe = ((AShooterPlayerController*)FromPC)->TargetingTeamField();
const int dinoTribe = toClone->TargetingTeamField();
if (pcTribe != dinoTribe)
return false;
}
}
}
return AActor_BPServerHandleNetExecCommand_original(_this, FromPC, CommandName, ExecParams);
}
ArkApi::GetHooks().SetHook("AActor.BPServerHandleNetExecCommand", &Hook_AActor_BPServerHandleNetExecCommand, &AActor_BPServerHandleNetExecCommand_original);
ArkApi::GetHooks().DisableHook("AActor.BPServerHandleNetExecCommand", &Hook_AActor_BPServerHandleNetExecCommand);
This is what I use in my anti grief plugin @🐨Dream Doctor🦘 const bool result -> setsleeping(false) -> return varFORCEINLINE uint32 GetTypeHash(const FString& Thing)
{
uint32 Hash = FCrc::MemCrc32(&Thing, sizeof(FString));
return Hash;
} "UseMysql": false,
someone would have already had the same problem or have a solution ?
thank youstruct AStaticMeshActor : AActor
{
UStaticMeshComponent* StaticMeshComponent() { return *GetNativePointerField<UStaticMeshComponent**>(this, "AStaticMeshActor.StaticMeshComponent"); }
static UClass* StaticClass() { return NativeCall<UClass*>(nullptr, "AStaticMeshActor.StaticClass"); }
};
AActor* SpawnTest(FVector* spawn_location)
{
DEBUG_WARN("Spawning actor...");
auto* uworld = ArkApi::GetApiUtils().GetWorld();
if (!uworld) {
return nullptr;
}
FString sphere_path
= "StaticMesh'/Game/PrimalEarth/CoreBlueprints/Sphere_Closed_Inverted_Collidable.Sphere_Closed_Inverted_Collidable'";
auto* sphere_object = UVictoryCore::BPLoadObject(&sphere_path);
if (!sphere_object) {
DEBUG_ERROR("!sphere_object");
return nullptr;
}
DEBUG_INFO("sphere_object loaded! class: {}", Utils::GetClassFullName(sphere_object->ClassField()).ToString());
FRotator rotation(0);
FActorSpawnParameters new_actor_spawn_params;
new_actor_spawn_params.bNoFail = true;
new_actor_spawn_params.bDeferBeginPlay = true;
auto* actor = static_cast<AStaticMeshActor*>(
uworld->SpawnActor(AStaticMeshActor::StaticClass(), spawn_location, &rotation, &new_actor_spawn_params));
if (actor) {
DEBUG_INFO("actor was spawned!");
auto static_mesh_component = actor->StaticMeshComponent();
static_mesh_component->SetStaticMesh(static_cast<UStaticMesh*>(sphere_object));
static_mesh_component->SetWorldScale3D(FVector(100.f));
actor->BeginPlay();
actor->ForceReplicateNow(false, false);
}
else
{
DEBUG_ERROR("!actor");
}
DEBUG_WARN("...end");
return actor;
}struct AStaticMeshActor : AActor
{
UStaticMeshComponent* StaticMeshComponent() { return *GetNativePointerField<UStaticMeshComponent**>(this, "AStaticMeshActor.StaticMeshComponent"); }
static UClass* StaticClass() { return NativeCall<UClass*>(nullptr, "AStaticMeshActor.StaticClass"); }
};
AActor* SpawnTest(FVector* spawn_location)
{
DEBUG_WARN("Spawning actor...");
auto* uworld = ArkApi::GetApiUtils().GetWorld();
if (!uworld) {
return nullptr;
}
FString sphere_path
= "StaticMesh'/Game/PrimalEarth/CoreBlueprints/Sphere_Closed_Inverted_Collidable.Sphere_Closed_Inverted_Collidable'";
auto* sphere_object = UVictoryCore::BPLoadObject(&sphere_path);
if (!sphere_object) {
DEBUG_ERROR("!sphere_object");
return nullptr;
}
DEBUG_INFO("sphere_object loaded! class: {}", Utils::GetClassFullName(sphere_object->ClassField()).ToString());
FRotator rotation(0);
FActorSpawnParameters new_actor_spawn_params;
new_actor_spawn_params.bNoFail = true;
new_actor_spawn_params.bDeferBeginPlay = true;
auto* actor = static_cast<AStaticMeshActor*>(
uworld->SpawnActor(AStaticMeshActor::StaticClass(), spawn_location, &rotation, &new_actor_spawn_params));
if (actor) {
DEBUG_INFO("actor was spawned!");
auto static_mesh_component = actor->StaticMeshComponent();
static_mesh_component->SetStaticMesh(static_cast<UStaticMesh*>(sphere_object));
static_mesh_component->SetWorldScale3D(FVector(100.f));
actor->BeginPlay();
actor->ForceReplicateNow(false, false);
}
else
{
DEBUG_ERROR("!actor");
}
DEBUG_WARN("...end");
return actor;
} inline AActor* BPSpawnActor(UWorld* uworld, FString blueprint, FVector* location, FRotator* rotation, bool do_begin_play)
{
//auto* world = ArkApi::GetApiUtils().GetWorld();
if (!uworld) {
return nullptr;
}
UClass* object_class = UVictoryCore::BPLoadClass(&blueprint);
if (!object_class) {
return nullptr;
}
FActorSpawnParameters new_actor_spawn_params;
new_actor_spawn_params.bDeferBeginPlay = true;
auto* actor = uworld->SpawnActor(object_class, location, rotation, &new_actor_spawn_params);
if (actor) {
if (do_begin_play) {
actor->BeginPlay();
actor->ForceReplicateNow(false, false);
}
return actor;
}
return nullptr;
}
auto* world = ArkApi::GetApiUtils().GetWorld();
auto character = player_controller->GetPlayerCharacter();
auto location = character->RootComponentField()->RelativeLocationField();
FString blueprint = "Blueprint'/Game/PrimalEarth/Structures/StorageBox_Small.StorageBox_Small'";
auto* actor = BPSpawnActor(uworld, blueprint, &location, &rotation, true);
https://i.ibb.co/SRmjjJN/6.png
Also after structure was spawned you need set it parameters like:
auto* primal_structure = static_cast<APrimalStructure*>(actor);
primal_structure->HealthField() = primal_structure->MaxHealthField();const char* instead of the previous const wchar* version, headers are updated so with API v3.51 release any plugin using FNames should be recompiled to comply with the new FName constructor.
This is a requirement for all FNames to work properly, due to the changes made to PDB Reader in the API
Old FNames won't crash, but they won't get the right string passed on (edited)BossLevels GetPlayerBossLevels(UPrimalPlayerData* myData)
{
TArray<float> AscensionData;
BossLevels MyLocalLevels{};
UProperty* prop = myData->FindProperty(FName("AscensionData", EFindName::FNAME_Find, false));
AscensionData = prop->Get<TArray<float>>(myData);
return MyLocalLevels;
}
The line was previously UProperty* prop = myData->FindProperty(FName(L"AscensionData", EFindName::FNAME_Find, false)); which has been modified from wchar to char due to changes, but now when compiling that line throws an error:
'<function-style-cast>': cannot convert from 'initializer list' to 'FName'
Any advice would be appreciated. (edited)FName(const char* InName, EFindName FindType);
1API::Requests::Get().CreateGetReauest(URL, &callbackFunc);API::Requests::Get().CreateGetRequest(url, std::bind(&function, std::placeholders::_1, std::placeholders::_2, yourVar1, yourVar2));API::Requests::Get().CreateGetReauest(URL, &callbackFunc); application/x-www-form-urlencoded, and when I try and add it manually by getting length() of the payload string, it's not correct.
For the JSON payload I was testing I was getting a length of 620 and the request was failing, but when I pasted that same json string into Postman it was sending a Content-Length of about 1200.
Has anyone used API::Requests for Webhooks, and if so how did you do it?void PostDiscordWebhook(FString URL, nlohmann::json Content)
{
API::Requests::Get().CreatePostRequest(URL.ToString(), [](bool Sucess, std::string Result) {}, Content.dump(), "application/json");
}GetCharacterName(...) function HandleNewPlayer hook?
I have such code and function returns empty string. I have latest version of API
bool Hook_AShooterGameMode_HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* newPlayer, UPrimalPlayerData* playerData, AShooterCharacter* playerCharacter, bool isFromLogin)
{
auto result = AShooterGameMode_HandleNewPlayer_original(_this, newPlayer, playerData, playerCharacter, isFromLogin);
const uint64 playerId = ArkApi::GetApiUtils().GetPlayerID(newPlayer);
// Player ID is 0 when character creation window, so we need to catch spawn of character
if (playerId > 0ULL)
{
const uint64 steamId = ArkApi::GetApiUtils().GetSteamIdFromController(newPlayer);
const FString characterName = ArkApi::GetApiUtils().GetCharacterName(newPlayer); // Will be an empty string
Log::GetLog()->warn("Char name {}", characterName.ToString());
// ...
}
return result;
} (edited)nlohmann::json j;
j["username"] = "TestName";
j["avatar_url"] = "https://i.imgur.com/testimg.png";
j["content"] = "";
j["embeds"] = { {
{"title", "Test Webhook Title"},
{"url", "https://testurl.com"},
{"description", "This is a test message with embeds and fields."},
{"color", "16711935"},
{"author", { {"name", "Test Plugin"}, {"icon_url", "https://i.imgur.com/testimg.png"} }},
{"fields", {
{{"name", "TestField1"}, {"value", TestVar1}, {"inline", true}},
{{"name", "TestField2"}, {"value", TestVar2}, {"inline", true}},
{{"name", "TestField3"}, {"value", TestVar3}, {"inline", true}},
{{"name", "TestField4"}, {"value", "This is the last field."}}
}}
} };void Discord_BannedPlayer_Kicked(uint64 SteamID, std::string HWID, time_t TimeRemaining)
{
std::vector<nlohmann::json> ObjVec;
ObjVec.push_back(GetEmbedObject("Player Steam ID", std::to_string(SteamID)));
ObjVec.push_back(GetEmbedObject("Player HWID", HWID));
if (TimeRemaining)
{
tm* Time = gmtime(&TimeRemaining);
ObjVec.push_back(GetEmbedObject("Remaining Ban Days", Time->tm_yday));
ObjVec.push_back(GetEmbedObject("Remaining Ban Hours", Time->tm_hour));
ObjVec.push_back(GetEmbedObject("Remaining Ban Minutes", Time->tm_min));
}
PostDiscordWebhook(conf::sKickWebhook, ConstructWebhook("A Player Was Kicked Because Their Unique Identifiers are Banned!", 16751360, ObjVec));
} (edited)template <typename T>
nlohmann::json GetEmbedObject(std::string Name, T const& Data)
{
nlohmann::json Obj;
Obj["name"] = Name;
Obj["value"] = Data;
Obj["inline"] = conf::IsCompactWebhook;
return Obj;
}string, jsObjectjsObject is either the previously defined type, a string, or a primitiveDictionary<string, Object>map<std::string, std::any>json.hpp header
1c++
UShooterCheatManager* cheatManager = static_cast<UShooterCheatManager*>(new_player->CheatManagerField());
cheatManager->MakeTribeFounder(); I set the owner of the tribe like this, but it will not take effectc++
UShooterCheatManager* cheatManager = static_cast<UShooterCheatManager*>(new_player->CheatManagerField());
cheatManager->MakeTribeFounder(); I set the owner of the tribe like this, but it will not take effect c++
AShooterGameMode* GameMode = ArkApi::GetApiUtils().GetShooterGameMode();
FTribeData* CreatedTribeData = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(CreatedTribeData, 0x200);
if (GameMode->GetOrLoadTribeData(TribeID, CreatedTribeData)) {
CreatedTribeData->OwnerPlayerDataIDField() == PlayerID;
GameMode->UpdateTribeData(CreatedTribeData);
} I will try thisc++
AShooterGameMode* GameMode = ArkApi::GetApiUtils().GetShooterGameMode();
FTribeData* CreatedTribeData = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(CreatedTribeData, 0x200);
if (GameMode->GetOrLoadTribeData(TribeID, CreatedTribeData)) {
CreatedTribeData->OwnerPlayerDataIDField() == PlayerID;
GameMode->UpdateTribeData(CreatedTribeData);
} I will try this CreatedTribeData->OwnerPlayerDataIDField() == PlayerID;
should be
CreatedTribeData->OwnerPlayerDataIDField() = PlayerID;// create tribe
if (Player->GetPlayerCharacter() && !Player->IsSpectator() && !Player->IsInTribe())
{
AShooterGameMode* GameMode = ArkApi::GetApiUtils().GetShooterGameMode();
FString TribeName = L"Tribe of " + ArkApi::GetApiUtils().GetCharacterName(Player);
int CreatedTribeID = GameMode->ForceCreateTribe(&TribeName, 0);
FTribeData* CreatedTribeData = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(CreatedTribeData, 0x200);
if (GameMode->GetOrLoadTribeData(CreatedTribeID, CreatedTribeData))
Player->GetShooterPlayerState()->AddToTribe(CreatedTribeData, false, false, false, nullptr);
FMemory::Free(CreatedTribeData);
UShooterCheatManager* cheat_manager = static_cast<UShooterCheatManager*>(Player->CheatManagerField());
cheat_manager->MakeTribeFounder();
}c++
AShooterGameMode* GameMode = ArkApi::GetApiUtils().GetShooterGameMode();
FTribeData* CreatedTribeData = static_cast<FTribeData*>(FMemory::Malloc(0x200));
RtlSecureZeroMemory(CreatedTribeData, 0x200);
if (GameMode->GetOrLoadTribeData(TribeID, CreatedTribeData)) {
CreatedTribeData->OwnerPlayerDataIDField() = PlayerID;
GameMode->UpdateTribeData(CreatedTribeData);
} I use this code nowUPrimalItem::AddNewItem
DECLARE_HOOK(UPrimalItem_UPrimalItem*, UPrimalItem*, UPrimalItem*, TSubclassOf<UPrimalItem>, UPrimalInventoryComponent*, bool, bool, float, bool, int, bool, float, bool, TSubclassOf<UPrimalItem>, float);
UPrimalItem* Hook_UPrimalItem_UPrimalItem*(UPrimalItem* _this, TSubclassOf<UPrimalItem> ItemArchetype, UPrimalInventoryComponent* GiveToInventory, bool bEquipItem, bool bDontStack, float ItemQuality, bool bForceNoBlueprint, int quantityOverride, bool bForceBlueprint, float MaxItemDifficultyClamp, bool CreateOnClient, TSubclassOf<UPrimalItem> ApplyItemSkin, float MinRandomQuality)
{
return UPrimalItem_UPrimalItem*_original(_this, ItemArchetype, GiveToInventory, bEquipItem, bDontStack, ItemQuality, bForceNoBlueprint, quantityOverride, bForceBlueprint, MaxItemDifficultyClamp, CreateOnClient, ApplyItemSkin, MinRandomQuality);
}
ArkApi::GetHooks().SetHook("UPrimalItem.UPrimalItem*", &Hook_UPrimalItem_UPrimalItem*, &UPrimalItem_UPrimalItem*_original);
ArkApi::GetHooks().DisableHook("UPrimalItem.UPrimalItem*", &Hook_UPrimalItem_UPrimalItem*);UPrimalItem::AllowInventoryItem.
If I add a simple std::cout << "AllowInventoryItem" << std::endl into the hook function as a test, everything works as expected. When the server starts it spits out a few dozen lines from cout in less than a second which is expected.
However, UPrimalItem::AllowInventoryItem has UPrimalItem* as a parameter. If I use ArkApi::GetApiUtils().GetItemBlueprint on that, and cout the result, the whole server slows down to a crawl. It spits out one or two couts per second and the server cannot be connected to.
Does anyone know why that would be and what I could do to fix it?FPlacementData but it only has a forward declaration in base.h? How do I get the details for that struct? (edited)FPlacementData but it only has a forward declaration in base.h? How do I get the details for that struct? (edited)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;
};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;
}; AShooterGameMode.InitGame misses most placed structure actors.AShooterGameMode.InitGame misses most placed structure actors. UGameplayStatics::GetAllActorsOfClass(ArkApi::GetApiUtils().GetWorld(), APrimalStructureItemContainer::GetPrivateStaticClass(), &AllActors);
for (auto* StorageStructure : AllActors)
{
APrimalStructureItemContainer* ItemContainer = static_cast<APrimalStructureItemContainer*>(StorageStructure);
TArray<UPrimalItem*> AllItems = ItemContainer->MyInventoryComponentField()->InventoryItemsField();
...UGameplayStatics::GetAllActorsOfClass(ArkApi::GetApiUtils().GetWorld(), APrimalStructureItemContainer::GetPrivateStaticClass(), &AllActors);
for (auto* StorageStructure : AllActors)
{
APrimalStructureItemContainer* ItemContainer = static_cast<APrimalStructureItemContainer*>(StorageStructure);
TArray<UPrimalItem*> AllItems = ItemContainer->MyInventoryComponentField()->InventoryItemsField();
... if (ItemContainer->MyInventoryComponentField()) did the trick.UObjectBaseUtility::GetName, but it doesn't seem like I can hook that function?UObjectBaseUtility::GetName, but it doesn't seem like I can hook that function? UPrimalInventoryComponent.LoadedFromSaveGame and dumped the details for each structure as it was loaded. The last structure to show before the crash was the one responsible.UPrimalInventoryComponent.LoadedFromSaveGame and dumped the details for each structure as it was loaded. The last structure to show before the crash was the one responsible.
1if (structure->ConsumesPrimalItemField().uClass)
{
TArray<FString> folder_paths = ((UPrimalItem*)(structure->ConsumesPrimalItemField().uClass->GetDefaultObject(true)))->DefaultFolderPathsField();
if (folder_paths.IsValidIndex(1))
tier = folder_paths[1];
} (edited)ArkApi::IApiUtils::GetClassBlueprint(structure->ConsumesPrimalItemField().uClass)[Debug] Structure Tag: None
[Debug] Structure GetArchetype: Blueprint'/Game/PrimalEarth/Structures/StorageBox_TekTransmitter.StorageBox_TekTransmitter'
[Debug] Structure Debug Info: Structure Name: StorageBox_TekTransmitter_C_3 Instigator: NULL OwnerName: YOLO1 Owner: NULL TargetingTeam: 1874804364
[Debug] Structure Debug Info: No_Detailed_Info_Specified
[Debug] Structure Debug Info: No_Detailed_Info_Specified
[Debug] Structure Debug Info: Crafting <--------AShooterCharacter *__fastcall UPrimalItem::GetOwnerPlayer(UPrimalItem *this)
{
AActor *v1; // rax
v1 = UPrimalItem::GetOwnerActor(this);
return Cast<AShooterCharacter>((UObject *)&v1->vfptr);
}bool ArkShop::GiveDino(AShooterPlayerController* player_controller, int level, bool neutered, std::string blueprint, std::string saddleblueprint)
{
bool success = false;
const FString fblueprint(blueprint.c_str());
APrimalDinoCharacter* dino = ArkApi::GetApiUtils().SpawnDino(player_controller, fblueprint, nullptr, level, true, neutered);
if (dino && ArkShop::config["General"].value("GiveDinosInCryopods", false))
{
FString cryo = FString(ArkShop::config["General"].value("CryoItemPath", "Blueprint'/Game/Extinction/CoreBlueprints/Weapons/PrimalItem_WeaponEmptyCryopod.PrimalItem_WeaponEmptyCryopod'"));
UClass* Class = UVictoryCore::BPLoadClass(&cryo);
UPrimalItem* item = UPrimalItem::AddNewItem(Class, nullptr, false, false, 0, false, 0, false, 0, false, nullptr, 0);
if (item)
{
if (ArkShop::config["General"].value("CryoLimitedTime", false))
item->AddItemDurability((item->ItemDurabilityField() - 3600) * -1);
UPrimalItem* saddle = nullptr;
if (saddleblueprint.size() > 0)
{
FString fblueprint(saddleblueprint.c_str());
UClass* Class = UVictoryCore::BPLoadClass(&fblueprint);
saddle = UPrimalItem::AddNewItem(Class, nullptr, false, false, 0, false, 0, false, 0, false, nullptr, 0);
}
FCustomItemData customItemData = ArkShop::GetDinoCustomItemData(dino, saddle);
item->SetCustomItemData(&customItemData);
item->UpdatedItem(true);
if (player_controller->GetPlayerInventoryComponent())
{
UPrimalItem* item2 = player_controller->GetPlayerInventoryComponent()->AddItemObject(item);
if (item2)
success = true;
}
}
dino->Destroy(true, false);
}
else if (dino)
success = true;
return success;
}APrimalDinoCharacter_CanFly, I can't get it to trigger.APrimalDinoCharacter_CanFly, I can't get it to trigger. bool __fastcall APrimalDinoCharacter::BP_CanFly(APrimalDinoCharacter *this)bool __fastcall APrimalDinoCharacter::BP_CanFly(APrimalDinoCharacter *this) APrimalDinoCharacter_CanMount to trigger either. Anyone had any luck with that one?bool __fastcall APrimalDinoCharacter::BP_CanFly(APrimalDinoCharacter *this) _fastcall ignored for x64 architectures?
1APrimalDinoCharacter_CanMount to trigger either. Anyone had any luck with that one? CanRide and realised that was what I needed anyway, and it works.UWorld::SpawnActor used?
2UWorld::SpawnActor used? c++
DECLARE_HOOK(AShooterGameMode_HandleNewPlayer, bool, AShooterGameMode*, AShooterPlayerController*, UPrimalPlayerData*, AShooterCharacter*, bool);
DECLARE_HOOK(AShooterGameMode_Logout, void, AShooterGameMode*, AController*);
bool Hook_AShooterGameMode_HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* new_player,
UPrimalPlayerData* player_data, AShooterCharacter* player_character,
bool is_from_login)
{
return AShooterGameMode_HandleNewPlayer_original(_this, new_player, player_data, player_character, is_from_login);
}
void Hook_AShooterGameMode_Logout(AShooterGameMode* _this, AController* exiting)
{
AShooterGameMode_Logout_original(_this, exiting);
}
ArkApi::GetHooks().SetHook("AShooterGameMode.HandleNewPlayer_Implementation", &Hook_AShooterGameMode_HandleNewPlayer, &AShooterGameMode_HandleNewPlayer_original);
ArkApi::GetHooks().SetHook("AShooterGameMode.Logout", &Hook_AShooterGameMode_Logout, &AShooterGameMode_Logout_original);
ArkApi::GetHooks().DisableHook("AShooterGameMode.HandleNewPlayer_Implementation", &Hook_AShooterGameMode_HandleNewPlayer);
ArkApi::GetHooks().DisableHook("AShooterGameMode.Logout", &Hook_AShooterGameMode_Logout);c++
DECLARE_HOOK(AShooterGameMode_HandleNewPlayer, bool, AShooterGameMode*, AShooterPlayerController*, UPrimalPlayerData*, AShooterCharacter*, bool);
DECLARE_HOOK(AShooterGameMode_Logout, void, AShooterGameMode*, AController*);
bool Hook_AShooterGameMode_HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* new_player,
UPrimalPlayerData* player_data, AShooterCharacter* player_character,
bool is_from_login)
{
return AShooterGameMode_HandleNewPlayer_original(_this, new_player, player_data, player_character, is_from_login);
}
void Hook_AShooterGameMode_Logout(AShooterGameMode* _this, AController* exiting)
{
AShooterGameMode_Logout_original(_this, exiting);
}
ArkApi::GetHooks().SetHook("AShooterGameMode.HandleNewPlayer_Implementation", &Hook_AShooterGameMode_HandleNewPlayer, &AShooterGameMode_HandleNewPlayer_original);
ArkApi::GetHooks().SetHook("AShooterGameMode.Logout", &Hook_AShooterGameMode_Logout, &AShooterGameMode_Logout_original);
ArkApi::GetHooks().DisableHook("AShooterGameMode.HandleNewPlayer_Implementation", &Hook_AShooterGameMode_HandleNewPlayer);
ArkApi::GetHooks().DisableHook("AShooterGameMode.Logout", &Hook_AShooterGameMode_Logout); DECLARE_HOOK(APrimalBuff_StaticAddBuff, APrimalBuff*, TSubclassOf<APrimalBuff>, APrimalCharacter*, UPrimalItem*, AActor*, bool);
Basically I do this:
APrimalBuff* Hook_APrimalBuff_StaticAddBuff(TSubclassOf<APrimalBuff> BuffClass, APrimalCharacter* ForCharacter, UPrimalItem* AssociatedItem, AActor* DamageCauser, bool bForceOnClient)
{
std::string MyBuffClass = ArkApi::GetApiUtils().GetClassBlueprint(BuffClass.UClass).ToString();
}
return APrimalBuff_StaticAddBuff_original(BuffClass, ForCharacter, AssociatedItem, DamageCauser, bForceOnClient);
... and then do some stuff with the string. It's all good until I run gcm on the server, at which point the server instantly crashes but only about 25% of the time.
I know gcm adds a buff to the character, but I don't understand why it crashes the server and only some of the time. I've tested it with maybe 20 or 30 different buffs without any issues. The only crashes were with gcm?1>I:\ARK-Server-API-VS2022\ARK-Server-API-master\version\Core\Private\Tools\Requests.cpp(139,38): error C2440: 'initializing': cannot convert from 'Poco::Net::HTTPRequest' to 'Poco::Net::HTTPRequest &'
1>I:\ARK-Server-API-VS2022\ARK-Server-API-master\version\Core\Private\Tools\Requests.cpp(139,38): message : A non-const reference may only be bound to an lvalue
1>I:\ARK-Server-API-VS2022\ARK-Server-API-master\version\Core\Private\Tools\Requests.cpp(172,38): error C2440: 'initializing': cannot convert from 'Poco::Net::HTTPRequest' to 'Poco::Net::HTTPRequest &'
1>I:\ARK-Server-API-VS2022\ARK-Server-API-master\version\Core\Private\Tools\Requests.cpp(172,38): message : A non-const reference may only be bound to an lvalue
1>I:\ARK-Server-API-VS2022\ARK-Server-API-master\version\Core\Private\Tools\Requests.cpp(210,38): error C2440: 'initializing': cannot convert from 'Poco::Net::HTTPRequest' to 'Poco::Net::HTTPRequest &'
1>I:\ARK-Server-API-VS2022\ARK-Server-API-master\version\Core\Private\Tools\Requests.cpp(210,38): message : A non-const reference may only be bound to an lvalue
1>I:\ARK-Server-API-VS2022\ARK-Server-API-master\version\Core\Private\Tools\Requests.cpp(252,38): error C2440: 'initializing': cannot convert from 'Poco::Net::HTTPRequest' to 'Poco::Net::HTTPRequest &'
1>I:\ARK-Server-API-VS2022\ARK-Server-API-master\version\Core\Private\Tools\Requests.cpp(252,38): message : A non-const reference may only be bound to an lvalue
1>I:\ARK-Server-API-VS2022\ARK-Server-API-master\version\Core\Private\Tools\Requests.cpp(302,38): error C2440: 'initializing': cannot convert from 'Poco::Net::HTTPRequest' to 'Poco::Net::HTTPRequest &'
1>I:\ARK-Server-API-VS2022\ARK-Server-API-master\version\Core\Private\Tools\Requests.cpp(302,38): message : A non-const reference may only be bound to an lvalue (edited)
`FString mind1 = FString(config["General"].value("MindControl", "Blueprint'/Game/PrimalEarth/CoreBlueprints/Buffs/Buff_Base_Disease_Low.Buff_Base_Disease_Low'"));
UClass* Class1 = UVictoryCore::BPLoadClass(&mind1);
if (AttackerShooterController->GetPlayerCharacter()->GetBuff(Class1)) {
Log::GetLog()->warn("view");
return;
}
no fount detecte player and buff (edited)if (!(check(*(data + 1)) &&
check(*(data + 2)) &&
check(*(data + 3)) &&
check(*(data + 4))))
return {};
check is #define check(expr) {}
It's showing these errors: (edited)Hook_FOnlineSessionSteam_UpdateSession(FOnlineSessionSteam* _this, FName SessionName, FOnlineSessionSettings* UpdatedSessionSettings, bool bShouldRefreshOnlineData)struct FOnlineSessionSteam : IOnlineSession
{
FNamedOnlineSession* GetGameServerSession() { return NativeCall<FNamedOnlineSession*>(this, "FOnlineSessionSteam.GetGameServerSession"); }
};struct FOnlineSessionSteam : IOnlineSession
{
FNamedOnlineSession* GetGameServerSession() { return NativeCall<FNamedOnlineSession*>(this, "FOnlineSessionSteam.GetGameServerSession"); }
}; struct AGameSession
{
int& MaxSpectatorsField() { return *GetNativePointerField<int*>(this, "AGameSession.MaxSpectators"); }
int& MaxPlayersField() { return *GetNativePointerField<int*>(this, "AGameSession.MaxPlayers"); }
char& MaxSplitscreensPerConnectionField() { return *GetNativePointerField<char*>(this, "AGameSession.MaxSplitscreensPerConnection"); }
bool& bRequiresPushToTalkField() { return *GetNativePointerField<bool*>(this, "AGameSession.bRequiresPushToTalk"); }
FName& SessionNameField() { return *GetNativePointerField<FName*>(this, "AGameSession.SessionName"); }
};void Hook_AShooterGameSession_RegisterServer(AShooterGameSession* _this)
{
std::cout << "Session Name: " << _this->SessionNameField().ToString().ToString() << std::endl;
AShooterGameSession_RegisterServer_original(_this);
}AGameSession* GameSession = ArkApi::GetApiUtils().GetShooterGameMode()->GameSessionField();AGameSession* GameSession = ArkApi::GetApiUtils().GetShooterGameMode()->GameSessionField(); if (!dinoConf["AttackSpeedModifiers"].empty())
{
for (auto &element : dinoConf["AttackSpeedModifiers"])
{
_this->AttackInfosField()[element["Index"].get<int>()].RiderAttackIntervalField() = element["AttackSpeed"].get<float>();
}
}UPrimalCharacterStatusComponent* status = dino->GetCharacterStatusComponent();
char* stats = status->NumberOfLevelUpPointsAppliedField()();
I am trying to figure out why the stats from dinos are negative after the stats gets above 127 points. For example, i have a giga with 150 points on damage and the status (int)stats[8] gives me -108 and a rex with 150 gives -106UPrimalCharacterStatusComponent* status = dino->GetCharacterStatusComponent();
char* stats = status->NumberOfLevelUpPointsAppliedField()();
I am trying to figure out why the stats from dinos are negative after the stats gets above 127 points. For example, i have a giga with 150 points on damage and the status (int)stats[8] gives me -108 and a rex with 150 gives -106 UPrimalCharacterStatusComponent* status = dino->GetCharacterStatusComponent();
char* stats = status->NumberOfLevelUpPointsAppliedField()();
I am trying to figure out why the stats from dinos are negative after the stats gets above 127 points. For example, i have a giga with 150 points on damage and the status (int)stats[8] gives me -108 and a rex with 150 gives -106 `FString mind1 = FString(config["General"].value("MindControl", "Blueprint'/Game/PrimalEarth/CoreBlueprints/Buffs/Buff_Base_Disease_Low.Buff_Base_Disease_Low'"));
UClass* Class1 = UVictoryCore::BPLoadClass(&mind1);
if (AttackerShooterController->GetPlayerCharacter()->GetBuff(Class1)) {
Log::GetLog()->warn("view");
return;
}
no fount detecte player and buff (edited)c++
bool isPlayerUnderNoglinMindControl(AShooterPlayerController* player_controller) {
auto buffs = player_controller->GetPlayerCharacter()->BuffsField();
for (const auto& buff : buffs)
{
const FString bpBuff = ArkApi::GetApiUtils().GetBlueprint(buff);
//const FString bpPlayerUsingNoglin= L"Blueprint'/Game/Genesis2/Dinos/BrainSlug/Buff_BrainSlugPostProccess.Buff_BrainSlugPostProccess'";
const FString bpPlayerUnderMindControl = L"Blueprint'/Game/Genesis2/Dinos/BrainSlug/Buff_BrainSlug_HumanControl.Buff_BrainSlug_HumanControl'";
if (bpPlayerUnderMindControl == bpBuff) {
// Player is under Noglin mind control
return true;
}
}
return false;
}
Hope this helps! (edited)
1FString mind = FString(config["General"].value("MindControl", "Blueprint'/Game/Genesis2/Dinos/BrainSlug/Buff_BrainSlug_HumanControl.Buff_BrainSlug_HumanControl'"));
UClass* Class = UVictoryCore::BPLoadClass(&mind);
if (AttackerShooterController->GetPlayerCharacter()->GetBuff(Class)) {
ArkApi::GetApiUtils().SendChatMessage(AttackerShooterController, *KillGetText("Sender"), *KillGetText("MsgNogglin"));
return;
} (edited)UVictoryCore::BPLoadClass(&mind) is betterUVictoryCore::BPLoadClass(&mind) is better FInstalledItemInfo which includes FThreadedTaskContainer. So I try and add that and it includes FThreadedTaskContainer_vtbl and, well it looks like below and obviously doesn't work.
struct /*VFT*/ FThreadedTaskContainer_vtbl
{
void(__fastcall * ~FThreadedTaskContainer)(FThreadedTaskContainer* this);
bool(__fastcall* IsActive)(FThreadedTaskContainer* this);
void(__fastcall* GetStatus)(FThreadedTaskContainer* this, int*, int*);
bool(__fastcall* WasSucessfull)(FThreadedTaskContainer* this);
};
struct FThreadedTaskContainer
{
FThreadedTaskContainer_vtbl* __vftable /*VFT*/;
};FInstalledItemInfo looks like this:
struct FInstalledItemInfo
{
unsigned __int64 Id;
FString Title;
FString InstallPath;
FString InfoFilePath;
TArray<FString, FDefaultAllocator> MapNames;
int Version;
FGuid GUID;
EModType::Type ModType;
bool bHasMetaInfo;
TMap<FString, FString, FDefaultSetAllocator, TDefaultMapKeyFuncs<FString, FString, 0> > ModMetaInfo;
bool RetrievedInfo;
bool Subscribed;
bool Installed;
bool HasError;
unsigned __int64 SubscriptionCallback;
unsigned __int64 RetrieveInfoCallback;
FThreadedTaskContainer* ThreadedCopyProgress;
FDirectoryTreeCopyProgress* CopyProgress;
};
It seems fine. What happens if I just leave off those last two lines from the struct that I don't need? void* ThreadedCopyProgress;
void* CopyProgress;
or something, you don't want to change the size of the struct depending on what you're doingFInstalledItemInfo which includes FThreadedTaskContainer. So I try and add that and it includes FThreadedTaskContainer_vtbl and, well it looks like below and obviously doesn't work.
struct /*VFT*/ FThreadedTaskContainer_vtbl
{
void(__fastcall * ~FThreadedTaskContainer)(FThreadedTaskContainer* this);
bool(__fastcall* IsActive)(FThreadedTaskContainer* this);
void(__fastcall* GetStatus)(FThreadedTaskContainer* this, int*, int*);
bool(__fastcall* WasSucessfull)(FThreadedTaskContainer* this);
};
struct FThreadedTaskContainer
{
FThreadedTaskContainer_vtbl* __vftable /*VFT*/;
}; FInstalledItemInfo looks like this:
struct FInstalledItemInfo
{
unsigned __int64 Id;
FString Title;
FString InstallPath;
FString InfoFilePath;
TArray<FString, FDefaultAllocator> MapNames;
int Version;
FGuid GUID;
EModType::Type ModType;
bool bHasMetaInfo;
TMap<FString, FString, FDefaultSetAllocator, TDefaultMapKeyFuncs<FString, FString, 0> > ModMetaInfo;
bool RetrievedInfo;
bool Subscribed;
bool Installed;
bool HasError;
unsigned __int64 SubscriptionCallback;
unsigned __int64 RetrieveInfoCallback;
FThreadedTaskContainer* ThreadedCopyProgress;
FDirectoryTreeCopyProgress* CopyProgress;
};
It seems fine. What happens if I just leave off those last two lines from the struct that I don't need? AShooterGameSession, and I've looked through FShooterGameSessionParams which looks like:
struct FShooterGameSessionParams
{
FName SessionName;
FName InitSessionName;
bool bIsLAN;
bool bIsPresence;
bool bIsPrivate;
TSharedPtr<FUniqueNetId, 0> UserId;
int BestSessionIdx;
FString DDUserId;
FString DDUserName;
unsigned __int64 ModId;
FString ServerPassword;
FString ServerAdminPassword;
FString SpectatorPassword;
};
Only about three of those fields return anything. The rest are blank. I've also looked at FShooterSessionData which looks like:
const struct FShooterSessionData
{
int EntryIndex;
FString GameName;
FString MapName;
FString OwnerName;
FString DayTimeStr;
int NumPlayers;
int MaxNumPlayers;
int Ping;
FString HostAddrWithPort;
FString HostAddr;
unsigned __int64 ModId;
bool bIsOfficial;
bool bHasPassword;
bool bPVEServer;
bool bUsingBattleEye;
bool bAllowDownloadCharacters;
bool bAllowDownloadItems;
bool bIsLegacyServer;
bool bLastPlayedSession;
bool bHasActiveMods;
int QueryPort;
int LobbyReportedBuildID;
FString SessionId;
unsigned __int64 TotalConversionID;
FGuid Identifier;
};
That is returned in an array which is always empty.
I'm getting the reference to ShooterGameSession from void Hook_AShooterGameSession_RegisterServer(AShooterGameSession* _this) which seems to work for other purposes. I even added a 30 second delay to my functions looking at the reference but that made no difference.AShooterGameSession, and I've looked through FShooterGameSessionParams which looks like:
struct FShooterGameSessionParams
{
FName SessionName;
FName InitSessionName;
bool bIsLAN;
bool bIsPresence;
bool bIsPrivate;
TSharedPtr<FUniqueNetId, 0> UserId;
int BestSessionIdx;
FString DDUserId;
FString DDUserName;
unsigned __int64 ModId;
FString ServerPassword;
FString ServerAdminPassword;
FString SpectatorPassword;
};
Only about three of those fields return anything. The rest are blank. I've also looked at FShooterSessionData which looks like:
const struct FShooterSessionData
{
int EntryIndex;
FString GameName;
FString MapName;
FString OwnerName;
FString DayTimeStr;
int NumPlayers;
int MaxNumPlayers;
int Ping;
FString HostAddrWithPort;
FString HostAddr;
unsigned __int64 ModId;
bool bIsOfficial;
bool bHasPassword;
bool bPVEServer;
bool bUsingBattleEye;
bool bAllowDownloadCharacters;
bool bAllowDownloadItems;
bool bIsLegacyServer;
bool bLastPlayedSession;
bool bHasActiveMods;
int QueryPort;
int LobbyReportedBuildID;
FString SessionId;
unsigned __int64 TotalConversionID;
FGuid Identifier;
};
That is returned in an array which is always empty.
I'm getting the reference to ShooterGameSession from void Hook_AShooterGameSession_RegisterServer(AShooterGameSession* _this) which seems to work for other purposes. I even added a 30 second delay to my functions looking at the reference but that made no difference. type& TheVariableNameField() { return *GetNativePointerField<type*>(this, "ClassName.FieldName"); }Field at the end of the functions is just a convention to know it is a field, and not a function. In the FieldName you should input the variable name as you see it when extracting from idatype& TheVariableNameField() { return *GetNativePointerField<type*>(this, "ClassName.FieldName"); } FShooterSessionData, why is it that sometimes that works and sometimes it doesn't, and what makes the pdb reader method work better?FShooterSessionData, why is it that sometimes that works and sometimes it doesn't, and what makes the pdb reader method work better? 


>>> a2s.info(address)
SourceInfo(protocol=17, server_name=" 24/7 Dustbowl :: Nemu's Stomping Ground", map_name='cp_dustbowl',
folder='tf', game='Team Fortress', app_id=440, player_count=31, max_players=33, bot_count=21,
server_type='d', platform='l', password_protected=False, vac_enabled=True, version='5579073',
edf=177, port=27015, steam_id=85568392920040090, stv_port=None, stv_name=None,
keywords='brutus,celt,couch,cp,dustbowl,increased_maxplayers,nemu,nocrits,nodmgspread,pony,replays,vanilla',
game_id=440, ping=0.253798684978392)
>>> a2s.players(address)
[Player(index=0, name='Brutus', score=34, duration=836.4749145507812),
Player(index=0, name='RageQuit', score=6, duration=1080.8099365234375),
Player(index=0, name="Screamin' Eagles", score=1, duration=439.8598327636719)]>>> a2s.info(address)
SourceInfo(protocol=17, server_name=" 24/7 Dustbowl :: Nemu's Stomping Ground", map_name='cp_dustbowl',
folder='tf', game='Team Fortress', app_id=440, player_count=31, max_players=33, bot_count=21,
server_type='d', platform='l', password_protected=False, vac_enabled=True, version='5579073',
edf=177, port=27015, steam_id=85568392920040090, stv_port=None, stv_name=None,
keywords='brutus,celt,couch,cp,dustbowl,increased_maxplayers,nemu,nocrits,nodmgspread,pony,replays,vanilla',
game_id=440, ping=0.253798684978392)
>>> a2s.players(address)
[Player(index=0, name='Brutus', score=34, duration=836.4749145507812),
Player(index=0, name='RageQuit', score=6, duration=1080.8099365234375),
Player(index=0, name="Screamin' Eagles", score=1, duration=439.8598327636719)]
1AShooterGameSession. It looks like this in GameState.h:
struct AShooterGameSession : AGameSession
{
TArray<FInstalledItemInfo>& CachedModsField() { return *GetNativePointerField<TArray<FInstalledItemInfo>*>(this, "AShooterGameSession.CachedMods"); }
TArray<FShooterSessionData>& ThreadSafeSearchResultsField() { return *GetNativePointerField<TArray<FShooterSessionData>*>(this, "AShooterGameSession.ThreadSafeSearchResults"); }
TArray<UNetConnection*> FailedAuthTokenClientConnectionsField() { return *GetNativePointerField<TArray<UNetConnection*>*>(this, "AShooterGameSession.FailedAuthTokenClientConnections"); }
TArray<FUniqueNetIdUInt64>& FailedAuthTokenClientUniqueIDsField() { return *GetNativePointerField<TArray<FUniqueNetIdUInt64>*>(this, "AShooterGameSession.FailedAuthTokenClientUniqueIDs"); }
FShooterGameSessionParams& CurrentSessionParamsField() { return *GetNativePointerField<FShooterGameSessionParams*>(this, "AShooterGameSession.CurrentSessionParams"); }
TSharedPtr<FShooterOnlineSessionSettings, 0>& HostSettingsField() { return *GetNativePointerField<TSharedPtr<FShooterOnlineSessionSettings, 0>*>(this, "AShooterGameSession.HostSettings"); }
TSharedPtr<FShooterOnlineSearchSettings, 0>& SearchSettingsField() { return *GetNativePointerField<TSharedPtr<FShooterOnlineSearchSettings, 0>*>(this, "AShooterGameSession.SearchSettings"); }
bool& bFoundSessionField() { return *GetNativePointerField<bool*>(this, "AShooterGameSession.bFoundSession"); }
I'm trying to get to CachedMods and ThreadSafeSearchResults but they both return empty arrays. I've tried checking them with Hook_AShooterGameSession_RegisterServer(AShooterGameSession* _this) and using that reference. I've also tried by adding an RCON command which uses AShooterGameSession* MyShooterSession = static_cast<AShooterGameSession*>(ArkApi::GetApiUtils().GetShooterGameMode()->GameSessionField()); to get a AShooterGameSession refernce. I can run the command after the server has started and settled to see if anything changes, but it doesn't.
Has anyone else used either of those arrays in their work and been able to make them work?AShooterGameSession reference but they're all ints and FStrings that are inherited from AGameSession.AShooterGameSession. It looks like this in GameState.h:
struct AShooterGameSession : AGameSession
{
TArray<FInstalledItemInfo>& CachedModsField() { return *GetNativePointerField<TArray<FInstalledItemInfo>*>(this, "AShooterGameSession.CachedMods"); }
TArray<FShooterSessionData>& ThreadSafeSearchResultsField() { return *GetNativePointerField<TArray<FShooterSessionData>*>(this, "AShooterGameSession.ThreadSafeSearchResults"); }
TArray<UNetConnection*> FailedAuthTokenClientConnectionsField() { return *GetNativePointerField<TArray<UNetConnection*>*>(this, "AShooterGameSession.FailedAuthTokenClientConnections"); }
TArray<FUniqueNetIdUInt64>& FailedAuthTokenClientUniqueIDsField() { return *GetNativePointerField<TArray<FUniqueNetIdUInt64>*>(this, "AShooterGameSession.FailedAuthTokenClientUniqueIDs"); }
FShooterGameSessionParams& CurrentSessionParamsField() { return *GetNativePointerField<FShooterGameSessionParams*>(this, "AShooterGameSession.CurrentSessionParams"); }
TSharedPtr<FShooterOnlineSessionSettings, 0>& HostSettingsField() { return *GetNativePointerField<TSharedPtr<FShooterOnlineSessionSettings, 0>*>(this, "AShooterGameSession.HostSettings"); }
TSharedPtr<FShooterOnlineSearchSettings, 0>& SearchSettingsField() { return *GetNativePointerField<TSharedPtr<FShooterOnlineSearchSettings, 0>*>(this, "AShooterGameSession.SearchSettings"); }
bool& bFoundSessionField() { return *GetNativePointerField<bool*>(this, "AShooterGameSession.bFoundSession"); }
I'm trying to get to CachedMods and ThreadSafeSearchResults but they both return empty arrays. I've tried checking them with Hook_AShooterGameSession_RegisterServer(AShooterGameSession* _this) and using that reference. I've also tried by adding an RCON command which uses AShooterGameSession* MyShooterSession = static_cast<AShooterGameSession*>(ArkApi::GetApiUtils().GetShooterGameMode()->GameSessionField()); to get a AShooterGameSession refernce. I can run the command after the server has started and settled to see if anything changes, but it doesn't.
Has anyone else used either of those arrays in their work and been able to make them work? AShooterGameSession.CachedMods contained a list of mods being used by the server, but maybe it's a list of mods on the client. Still hoping to find the server's list of mods.AShooterGameSession.CachedMods contained a list of mods being used by the server, but maybe it's a list of mods on the client. Still hoping to find the server's list of mods. FInstalledItemInfo which seems to have everything needed, but apparently it's only used on the client.
struct FInstalledItemInfo
{
unsigned __int64 Id;
FString Title;
FString InstallPath;
FString InfoFilePath;
TArray<FString,FDefaultAllocator> MapNames;
int Version;
FGuid GUID;
EModType::Type ModType;
bool bHasMetaInfo;
TMap<FString,FString,FDefaultSetAllocator,TDefaultMapKeyFuncs<FString,FString,0> > ModMetaInfo;
bool RetrievedInfo;
bool Subscribed;
bool Installed;
bool HasError;
unsigned __int64 SubscriptionCallback;
unsigned __int64 RetrieveInfoCallback;
FThreadedTaskContainer *ThreadedCopyProgress;
FDirectoryTreeCopyProgress *CopyProgress;
};void __fastcall FOnlineSubsystemSteam::GetMods(FOnlineSubsystemSteam *this, TArray<FInstalledItemInfo,FDefaultAllocator> *Mods) this oneIOnlineSubsystem::Get| 000001AD9E22A800
ModID: 1136125765| InstallPath: ../../../ShooterGame/Content/Mods/1136125765| ModTitle: Bitou2k's Binocular
ModID: 1231538641| InstallPath: ../../../ShooterGame/Content/Mods/1231538641| ModTitle: ARKomatic
ModID: 1404697612| InstallPath: ../../../ShooterGame/Content/Mods/1404697612| ModTitle: Awesome SpyGlass!
ModID: 1428596566| InstallPath: ../../../ShooterGame/Content/Mods/1428596566| ModTitle: Auto Engrams!
ModID: 1609138312| InstallPath: ../../../ShooterGame/Content/Mods/1609138312| ModTitle: Dino Storage v2
ModID: 1829635965| InstallPath: ../../../ShooterGame/Content/Mods/1829635965| ModTitle: HG Remap Stack V1.51
ModID: 1840739225| InstallPath: ../../../ShooterGame/Content/Mods/1840739225| ModTitle: Getter Component
ModID: 1941328406| InstallPath: ../../../ShooterGame/Content/Mods/1941328406| ModTitle: Solo Farm Mod
ModID: 1999447172| InstallPath: ../../../ShooterGame/Content/Mods/1999447172| ModTitle: Super Structures
ModID: 2501968412| InstallPath: ../../../ShooterGame/Content/Mods/2501968412| ModTitle: MTS Ragnarok Extension
ModID: 566885854| InstallPath: ../../../ShooterGame/Content/Mods/566885854| ModTitle: Death Helper
ModID: 928102085| InstallPath: ../../../ShooterGame/Content/Mods/928102085| ModTitle: HG Stacking Mod 10000-90 V315IOnlineSubsystem::Get| 00000222BCB0A800
ModID: 1136125765| ModTitle: Bitou2k's Binocular| ModGUID: 3864034354-1077919130-1255057850-2516745270
ModID: 1231538641| ModTitle: ARKomatic| ModGUID: 3851322781-1221503930-3744069779-3148035478
ModID: 1404697612| ModTitle: Awesome SpyGlass!| ModGUID: 2278268445-1225547686-3572651442-2502918914
ModID: 1428596566| ModTitle: Auto Engrams!| ModGUID: 999821796-1114061443-1560261803-2842499181
ModID: 1609138312| ModTitle: Dino Storage v2| ModGUID: 753996299-1259150744-545294743-2268441977 struct Guid
{
uint32_t A;
uint32_t B;
uint32_t C;
uint32_t D;
};
struct FInstalledItemInfo
{
uint64_t Id; //0x00
FString Title; //0x08
FString InstallPath; //0x18
FString InfoFilePath; //0x28
TArray<FString> MapNames; //0x38
uint32_t Version; //0x48
Guid GUID; //0x4C
uint32_t ModType; //0x5C
bool bHasMetaInfo; //0x60
unsigned char Buffer1[0x07]; //0x61
unsigned char ModMetaInfo[0x50]; //0x68
bool RetrievedInfo; //0xB8
bool Subscribed; //0xB9
bool Installed; //0xBA
bool HasError; //0xxBB
unsigned char Buffer2[0x04]; //0xBC
uint64_t SubscriptionCallback; //0xC0
uint64_t RetrieveInfoCallback; //0xC8
void* ThreadedCopyProgress; //0xD0
void* CopyProgress; //0xD8
};
using IOnlineSubsystem__Get_Type = void*(*)(FName*);
static IOnlineSubsystem__Get_Type IOnlineSubsystem__Get_Original = reinterpret_cast<IOnlineSubsystem__Get_Type>(DetourFindFunction("ShooterGameServer.exe", "IOnlineSubsystem::Get"));
static auto None = FName("None");
void* OnlineSubsystem = IOnlineSubsystem__Get_Original(&None);
printf("IOnlineSubsystem::Get| %p\n", OnlineSubsystem);
TArray<FInstalledItemInfo> Mods{};
using FOnlineSubsystemSteam__GetMods_Type = void(*)(void*, TArray<FInstalledItemInfo>*);
static FOnlineSubsystemSteam__GetMods_Type FOnlineSubsystemSteam__GetMods_Original = reinterpret_cast<FOnlineSubsystemSteam__GetMods_Type>(DetourFindFunction("ShooterGameServer.exe", "FOnlineSubsystemSteam::GetMods"));
FOnlineSubsystemSteam__GetMods_Original(OnlineSubsystem, &Mods);
for (auto&& Mod : Mods)
{
printf("ModID: %llu| ModTitle: %s| ModGUID: %u-%u-%u-%u\n",
Mod.Id,
Mod.Title.IsValid() ? Mod.Title.ToString().c_str() : "",
Mod.GUID.A, Mod.GUID.B, Mod.GUID.C, Mod.GUID.D);
}TArray<FModInfo,FDefaultAllocator> *__fastcall FPackageName::GetMods(TArray<FModInfo,FDefaultAllocator> *result)IOnlineSubsystem::Get| 000001FFABE92100 but the FArray of FInstalledItemInfo is always empty.class ServerInfo
{
private:
ServerRates MyServerRates;
AShooterGameMode* MyGameMode;
public:
void UpdateRates()
{
MyGameMode = ArkApi::GetApiUtils().GetShooterGameMode();
MyServerRates.XPMultiplier = MyGameMode->XPMultiplierField();
}
}
Server crashes when UpdateRates is called. If I modify UpdateRates to this it works fine with no crashes.
void UpdateRates()
{
MyServerRates.XPMultiplier = ArkApi::GetApiUtils().GetShooterGameMode()->XPMultiplierField();
} (edited)MyGameMode = ArkApi::GetApiUtils().GetShooterGameMode();ArkApi::GetApiUtils().GetShooterGameMode() at the same point it works fine. It's very confusing lol.info files inside the mod directories that contain useful info.loaded_plugins in PluginManager?loaded_plugins in PluginManager?
2UFunction* netUpdateFunc = actor->FindFunctionChecked(FName("NetRefreshRadiusScale", EFindName::FNAME_Add));
if (netUpdateFunc)
{
const float units_needed = (radius / 400.f);
int arg = (int)floor(units_needed / 0.2) + 2;
actor->ProcessEvent(netUpdateFunc, &arg);
}struct Params
{
int param1;
FString param2;
};
ex: bool bp func with int and dino character params
struct Params
{
int param1;
APrimalDinoCharacter* param2;
bool returnValue;
};UVictoryCore::ServerOctreeOverlapActorsClass what people use? Is it safe now? I remember something about it causing crashes?UVictoryCore::ServerOctreeOverlapActorsClass what people use? Is it safe now? I remember something about it causing crashes? 

ServerOctreeOverlapActors looks like:
static TArray<AActor*>* ServerOctreeOverlapActors(TArray<AActor*>* result, UWorld* theWorld, FVector AtLoc, float Radius, EServerOctreeGroup::Type OctreeType, bool bForceActorLocationDistanceCheck) { return NativeCall<TArray<AActor*>*, TArray<AActor*>*, UWorld*, FVector, float, EServerOctreeGroup::Type, bool>(nullptr, "UVictoryCore.ServerOctreeOverlapActors", result, theWorld, AtLoc, Radius, OctreeType, bForceActorLocationDistanceCheck);
Or am I doing the wrong thing? lolIApiUtils::GetAllActorsInRange i think it wasIApiUtils::GetAllActorsInRange i think it was
1
if (!PC->bIsAdmin().Get())
{
UObject* Object = reinterpret_cast<UObject*>(PC);
UFunction* Func = Object->FindFunctionChecked(FName("ClientNotifyAdmin", EFindName::FNAME_Find));
Object->ProcessEvent(Func, nullptr);
}void Hook_UObject_ProcessEvent(UObject* _this, UFunction* Function, void* Parameters)
{
UObject_ProcessEvent_original(_this, Function, Parameters);
FName objname = Function->NameField();
FString FuncName;
objname.ToString(&FuncName);
if (FuncName == L"the function name you need to hook")
{
//do stuff
}
}void AddBpHook(const std::string FunctionName, const FString ContainerBP)
{
UObject* Obj = GetDefaultObjectOfClass(ContainerBP);
if (Obj)
{
UFunction* Func = Obj->FindFunctionChecked(FName(FunctionName.c_str(), EFindName::FNAME_Find));
if (Func)
FunctionsMap_[Func->InternalIndexField()] = FunctionName;
}
}
void OnFunctionCalled(int InternalIndex, UObject* Caller, void* Params)
{
if (Caller && FunctionsMap_.find(InternalIndex) != FunctionsMap_.end())
{
std::string FunctionID = FunctionsMap_[InternalIndex];
if (FunctionID == "OnOpenUIRequested")
OpenUIForPlayer(Caller);
else if (FunctionID == "OnClaimReward")
ClaimReward(Caller, Params);
else if (FunctionID == "OnSwapMission")
SwapMission(Caller, Params);
}
}if (!PC->bIsAdmin().Get())
{
UObject* Object = reinterpret_cast<UObject*>(PC);
UFunction* Func = Object->FindFunctionChecked(FName("ClientNotifyAdmin", EFindName::FNAME_Find));
Object->ProcessEvent(Func, nullptr);
} if (!PC->bIsAdmin().Get())
{
UObject* Object = reinterpret_cast<UObject*>(PC);
UFunction* Func = Object->FindFunctionChecked(FName("ClientNotifyAdmin", EFindName::FNAME_Find));
Object->ProcessEvent(Func, nullptr);
}
2
1#include "Timer.h"
2) to use delay execute use API::Timer::Get().DelayExecute(&function, delaySeconds, args);
You can also pass a lambda instead of a function pointer, like this:
API::Timer::Get().DelayExecute([]()
{
YourFunctionCall();
}, delay);#include "Timer.h"
2) to use delay execute use API::Timer::Get().DelayExecute(&function, delaySeconds, args);
You can also pass a lambda instead of a function pointer, like this:
API::Timer::Get().DelayExecute([]()
{
YourFunctionCall();
}, delay); #include "Timer.h"
2) to use delay execute use API::Timer::Get().DelayExecute(&function, delaySeconds, args);
You can also pass a lambda instead of a function pointer, like this:
API::Timer::Get().DelayExecute([]()
{
YourFunctionCall();
}, delay); e.playerNameW = *(
(ArkApi::GetApiUtils().GetCharacterName(new_player).IsEmpty())
? GetPlayerCharacterNameOLD(new_player)
: ArkApi::GetApiUtils().GetCharacterName(new_player));
1
for (const auto& item : items_map)
{
const std::string command = item["DefeatBoss"];
const std::string BossID = item["BossID"];
const int Dificultad = item["Dificultad"];
FString fcommand = fmt::format("{0} {1} {2} {3}", command, player_controller->GetLinkedPlayerID(), BossID, Dificultad).c_str();
FString result;
Log::GetLog()->warn(fcommand.ToString());
player_controller->ConsoleCommand(&result, &fcommand, true);
}player_controller->bIsAdmin().Set(true);
before you call the command\ARK-Server-API\version\Core\Public).
=> Set all other settings (Output type: DLL, Platform toolset: VS 2017 v141, Character encoding: Unicode, C++ language standard: ISO C++ 17 standard, Incremental linking: No, Subsystem: Windows).
If you don't want to miss any project properties you should look once again at existing projects from GitHub, very valuable source of information #include "API/ARK/GameMode.h"
#pragma comment(lib, "ArkApi.lib")
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Log::Get().Init("MyMod");
Log::GetLog()->info("Loading my mod!");
// Your mod stuff here...
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Log::GetLog()->info("Unloading my mod!");
// Stop your mod processing here if any (for example freeing resources)...
break;
}
return TRUE;
} (edited)Log::Get().Init("MyPlugin");\ARK-Server-API\version\Core\Public).
=> Set all other settings (Output type: DLL, Platform toolset: VS 2017 v141, Character encoding: Unicode, C++ language standard: ISO C++ 17 standard, Incremental linking: No, Subsystem: Windows).
If you don't want to miss any project properties you should look once again at existing projects from GitHub, very valuable source of information LostIsland make error on UnicodeRcon plugin. LoadServerRconPort() occur error with Hook_AShooterGameMode_HandleNewPlayer(...), so it take build error on LoadServerRconPort()3.53, 3.54URCONServer is already defined in the api so no need to redefine it on headers anymore. Also SocketField returns a reference a not a pointer. So you can't static cast a reference to a pointer.LostIsland make error on UnicodeRcon plugin. LoadServerRconPort() occur error with Hook_AShooterGameMode_HandleNewPlayer(...), so it take build error on LoadServerRconPort() rconport = static_cast<FSocketBSD*>(&ArkApi::GetApiUtils()
.GetShooterGameMode()->RCONSocketField()->SocketField())->GetPortNo();UnicodeRconinventoryComp->InventoryItemsField() (edited)ArkApi::GetApiUtils().GetItemBlueprint()`DECLARE_HOOK(AShooterGameMode_ForceCreateTribe, int, AShooterGameMode*, FString*, int);`
Can't we use this to find the moment to create a tribe? Or which hook do you use?`DECLARE_HOOK(AShooterGameMode_ForceCreateTribe, int, AShooterGameMode*, FString*, int);`
Can't we use this to find the moment to create a tribe? Or which hook do you use? AShooterPlayerState::ServerRequestCreateTribe_ImplementationAShooterPlayerState::ServerRequestCreateTribe_Implementation AShooterPlayerState::ServerRequestCreateTribe_Implementation 
PlayerControllerListFieldBlueprint'/Game/Mods/HWIDBans/Actor_BP_HWIDBans.Actor_BP_HWIDBans'void CheckPlayer(AShooterPlayerController* PC, FString PlayerHWID)FindFunctionCheck :pHook_APlayerController_ServerReceivedPlayerControllerAck_Implementation
DECLARE_HOOK) utilize C macros instead of STL templatesDECLARE_HOOK macro is also limited by (even more limited, it assumes fastcall))static hookable<void(sdk::UObject*, sdk::UFunction*, void*)> process_event_;std::function signature of the function to hook.auto spongehax::process_event(sdk::UObject* who, sdk::UFunction* what, void* how) -> void
{
while(!tick_queue.empty())
{
tick_queue.front()();
tick_queue.pop();
}
const auto func = what->GetName();
auto handled = false;
for (auto [_, callback] : process_event_handlers[func])
{
handled = callback(who, how);
if (handled) return;
}
process_event_.original(who, what, how);
}process_event_.reset(0xadd9e55); and taking the address of the address of (for Detours, MinHook, etc.)
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(process_event_.get(), process_event); // (hookable_object.get(), callback)
DetourTransactionCommit(); (edited)hook_event which has a static callback to pass the data into the registered callbacks.template<typename RT, typename VA, typename ...A, typename name>
class HookEvent<RT(A...), VA, name>
{
public:
static inline hookable<RT(A...)> hook;
static inline std::vector<std::function<RT(A..., bool&)>> preHooks;
static inline std::vector<std::function<RT(A..., bool&)>> postHooks;
static RT callback(A... args)
{
auto handled = false;
for (auto hook : preHooks)
{
hook(args..., handled);
if (handled)
return;
}
hook.original(args...);
for (auto hook : postHooks)
{
hook(args..., handled);
if (handled)
return;
}
}
using type = HookEvent<RT(A...), VA, name>;
};process_event_.reset(0xadd9e55); and taking the address of the address of (for Detours, MinHook, etc.)
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(process_event_.get(), process_event); // (hookable_object.get(), callback)
DetourTransactionCommit(); (edited)#pragma comment(linker, "/export:GetFileVersionInfoA=C:\\windows\\system32\\version.dll.GetFileVersionInfoA,@1")
#pragma comment(linker, "/export:GetFileVersionInfoByHandle=C:\\windows\\system32\\version.dll.GetFileVersionInfoByHandle,@2")
#pragma comment(linker, "/export:GetFileVersionInfoExA=C:\\windows\\system32\\version.dll.GetFileVersionInfoExA,@3")
#pragma comment(linker, "/export:GetFileVersionInfoExW=C:\\windows\\system32\\version.dll.GetFileVersionInfoExW,@4")
#pragma comment(linker, "/export:GetFileVersionInfoSizeA=C:\\windows\\system32\\version.dll.GetFileVersionInfoSizeA,@5")
#pragma comment(linker, "/export:GetFileVersionInfoSizeExA=C:\\windows\\system32\\version.dll.GetFileVersionInfoSizeExA,@6")
#pragma comment(linker, "/export:GetFileVersionInfoSizeExW=C:\\windows\\system32\\version.dll.GetFileVersionInfoSizeExW,@7")
#pragma comment(linker, "/export:GetFileVersionInfoSizeW=C:\\windows\\system32\\version.dll.GetFileVersionInfoSizeW,@8")
#pragma comment(linker, "/export:GetFileVersionInfoW=C:\\windows\\system32\\version.dll.GetFileVersionInfoW,@9")
#pragma comment(linker, "/export:VerFindFileA=C:\\windows\\system32\\version.dll.VerFindFileA,@10")
#pragma comment(linker, "/export:VerFindFileW=C:\\windows\\system32\\version.dll.VerFindFileW,@11")
#pragma comment(linker, "/export:VerInstallFileA=C:\\windows\\system32\\version.dll.VerInstallFileA,@12")
#pragma comment(linker, "/export:VerInstallFileW=C:\\windows\\system32\\version.dll.VerInstallFileW,@13")
#pragma comment(linker, "/export:VerLanguageNameA=C:\\windows\\system32\\version.dll.VerLanguageNameA,@14")
#pragma comment(linker, "/export:VerLanguageNameW=C:\\windows\\system32\\version.dll.VerLanguageNameW,@15")
#pragma comment(linker, "/export:VerQueryValueA=C:\\windows\\system32\\version.dll.VerQueryValueA,@16")
#pragma comment(linker, "/export:VerQueryValueW=C:\\windows\\system32\\version.dll.VerQueryValueW,@17") (edited)const auto dino = (APrimalDinoCharacter*)actor;
dino->SomeComponent->SomeValue;Hook_APrimalDinoCharacter_Die(APrimalDinoCharacter* _this, float KillingDamage, FDamageEvent* DamageEvent, AController* Killer, AActor* DamageCauser)
It provides a Controller reference, which I assumed would not be valid if the killer was a dino, but it is, and that reference can be cast to a valid ShooterPlayerController reference. How is that possible when it's a dino that's doing the killing? At first I thought it was because the dino was being ridden, but it does this even when the wild dino is the killer?Hook_APrimalDinoCharacter_Die(APrimalDinoCharacter* _this, float KillingDamage, FDamageEvent* DamageEvent, AController* Killer, AActor* DamageCauser)
It provides a Controller reference, which I assumed would not be valid if the killer was a dino, but it is, and that reference can be cast to a valid ShooterPlayerController reference. How is that possible when it's a dino that's doing the killing? At first I thought it was because the dino was being ridden, but it does this even when the wild dino is the killer? APlayerController can always (or most of the times) be casted to AShooterPlayerController, but AController is not always a player controller
1 Base* b2 = new Derived;
if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr)
{
std::cout << "downcast from b2 to d successful\n";
d->name(); // safe to call
}
if(const auto ptr = get_ptr(…)) ~~~v Declaration, could equal null. ~~~v check d value
if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr)
{
std::cout << "downcast from b2 to d successful\n";
d->name(); // safe to call
}Derived* d = dynamic_cast<Derived*>(b2); isn't equality checkstruct __cppobj FChatMessage
{
FString SenderName;
FString SenderSteamName;
FString SenderTribeName;
unsigned int SenderId;
FString Message;
FString Receiver;
int SenderTeamIndex;
long double ReceivedTime;
TEnumAsByte<enum EChatSendMode::Type> SendMode;
unsigned int RadioFrequency;
TEnumAsByte<enum EChatType::Type> ChatType;
UTexture2D *SenderIcon;
FString UserId;
};unsigned char arrayUPrimalItem::CreateFromBytesUPrimalItem::CreateFromBytes
1UClass for a structure. I need to get ConsumesPrimalItemField from a APrimalStructure of the type in UClass. If I create a new instance of APrimalStructure, how do I set it to the class that I have in UClass so that I can then get the correct ConsumesPrimalItemField back again?UClass for a structure. I need to get ConsumesPrimalItemField from a APrimalStructure of the type in UClass. If I create a new instance of APrimalStructure, how do I set it to the class that I have in UClass so that I can then get the correct ConsumesPrimalItemField back again? APrimalStructure* MyPrimalStructure = static_cast<APrimalStructure*>(_this->GetDefaultObject(true));
UClass* PrimalItemClass = MyPrimalStructure->ConsumesPrimalItemField().uClass;// save data
TArray<unsigned char> item_bytes;
item->GetItemBytes(&item_bytes);
// create item
auto* item = UPrimalItem::CreateFromBytes(&item_bytes);
https://github.com/2bite/ARK-Server-Plugins-public/blob/main/DumpCryopods/DumpCryopods/DumpCryopods.cpp
2bUnlocked, but I'm wondering what functions are used when players do it in-game.void Hooked_ServerRequestCreateNewTribe_Implementation(AShooterPlayerState* _this, FString* TribeName, FTribeGovernment TribeGovernment)
{
original_ServerRequestCreateNewTribe_Implementation(_this, TribeName, TribeGovernment);
Log::GetLog()->Error(_this->MyPlayerDataStructField()->TribeIDField());
Log::GetLog()->Error(_this->IsInTribe());
Log::GetLog()->Error(_this->MyTribeDataField()->TribeIDField());
Log::GetLog()->Error(_this->MyPlayerDataField()->GetTribeTeamID);
}c++
enum EResourceSizeMode
{
Exclusive = 0x0,
Inclusive = 0x1,
Open = 0x2,
};
struct FRenderResource
{
};
struct FTexture : FRenderResource
{
};
struct FTextureResource : FTexture
{
};
struct UTexture : UObject
{
static UClass* StaticClass() { return NativeCall<UClass*>(nullptr, "UTexture.StaticClass"); }
};
struct UTexture2D: UTexture
{
static UClass* StaticClass() { return NativeCall<UClass*>(nullptr, "UTexture2D.StaticClass"); }
void GetMipData(int FirstMipToLoad, void** OutMipData) { return NativeCall<void, int, void**>(this, "UTexture2D.GetMipData", FirstMipToLoad, OutMipData); }
void UpdateResourceW() { return NativeCall<void>(this, "UTexture2D.UpdateResourceW"); }
FTextureResource* CreateResource() { return NativeCall<FTextureResource*>(this, "UTexture2D.CreateResource"); }
------> __int64 GetResourceSize(EResourceSizeMode type) { return NativeCall<__int64, EResourceSizeMode>(this, "UTexture2D.GetResourceSize", type); }
float GetSurfaceHeight() { return NativeCall<float>(this, "UTexture2D.GetSurfaceHeight"); }
int& SizeX_DEPRECATED() { return *GetNativePointerField<int*>(this, "UTexture2D.SizeX_DEPRECATED"); }
int& SizeY_DEPRECATED() { return *GetNativePointerField<int*>(this, "UTexture2D.SizeY_DEPRECATED"); }
}; (edited)ArkApi::GetApiUtils().GetShooterGameMode()->TribesIdsField(){
"username": "Webhook",
"avatar_url": "https://i.imgur.com/4M34hi2.png",
"content": "Text message. Up to 2000 characters.",
"embeds": [
{
"author": {
"name": "Birdie♫",
"url": "https://www.reddit.com/r/cats/",
"icon_url": "https://i.imgur.com/R66g1Pe.jpg"
},
"title": "Title",
"url": "https://google.com/",
"description": "Text message. You can use Markdown here. *Italic* **bold** __underline__ ~~strikeout~~ [hyperlink](https://google.com) `code`",
"color": 15258703,
"fields": [
{
"name": "Text",
"value": "More text",
"inline": true
},
{
"name": "Even more text",
"value": "Yup",
"inline": true
},
{
"name": "Use `\"inline\": true` parameter, if you want to display fields in the same line.",
"value": "okay..."
},
{
"name": "Thanks!",
"value": "You're welcome :wink:"
}
],
"thumbnail": {
"url": "https://upload.wikimedia.org/wikipedia/commons/3/38/4-Nature-Wallpapers-2014-1_ukaavUI.jpg"
},
"image": {
"url": "https://upload.wikimedia.org/wikipedia/commons/5/5a/A_picture_from_China_every_day_108.jpg"
},
"footer": {
"text": "Woah! So cool! :smirk:",
"icon_url": "https://i.imgur.com/fKL31aD.jpg"
}
}
]
}
Normally I have fixed values for the "fields" which is easy, however I now need to add two fields per element of a struct array I have. For each array element I need to add this to the
["embeds"]["fields"] section of my JSON.
{
"name": "Tribe Name",
"value": array.tribename,
"inline": false
},
{
"name": "Count",
"value": array.count,
"inline": true
}
I can't seem to get my head around how to do this ["fields"][index]["value"] = array.tribename; (edited)["fields"][index]["value"] = array.tribename; (edited)AddRconCommand is called multiple times, and it's a random number of times before it finally stops. This only happens on this very large savefile. Smaller maps don't have the problem.
Is there a buffer somewhere that's timing out and repeating or something? (edited)containers.foreach(x =>
{
counts[x.targettingTeam] += x.inventoryItems.reduce((a, y) => a += y.staticClass() == classToSearch, 0);
}) (edited)#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <numeric>
#include <execution>
std::unordered_map<int, int> counts;
class container
{
public:
int team;
std::vector<int> objects;
};
std::vector<container> containers;
int main()
{
containers =
{
container{.team = 1, .objects = {1,2,3,4,5,6,7,8,9}},
container{.team = 2, .objects = {5,2,1,4}},
container{.team = 3, .objects = {7,1,3,6,1,5,8,4,4,4,1,5}},
container{.team = 2, .objects = {1,5,8,3,2}},
container{.team = 2, .objects = {3,2}},
container{.team = 1, .objects = {9,3,7,1}},
container{.team = 4, .objects = {8,3,1,5,1,2}},
container{.team = 3, .objects = {7,4,1,5,8,1}},
};
for (auto container : containers)
{
std::cout << "Container is for team " << container.team << " and contains " << container.objects.size() << " items, iterating now.\n";
counts[container.team] += std::reduce(std::execution::seq, container.objects.begin(), container.objects.end(), 0, [](auto sum, auto next)
{
return sum + (next == 3);
});
}
for (auto count : counts)
{
std::cout << "And now we have the counts, for team " << count.first << " we have a total of " << count.second << " items where item equals 3.\n";
}
}#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <numeric>
#include <execution>
std::unordered_map<int, int> counts;
class container
{
public:
int team;
std::vector<int> objects;
};
std::vector<container> containers;
int main()
{
containers =
{
container{.team = 1, .objects = {1,2,3,4,5,6,7,8,9}},
container{.team = 2, .objects = {5,2,1,4}},
container{.team = 3, .objects = {7,1,3,6,1,5,8,4,4,4,1,5}},
container{.team = 2, .objects = {1,5,8,3,2}},
container{.team = 2, .objects = {3,2}},
container{.team = 1, .objects = {9,3,7,1}},
container{.team = 4, .objects = {8,3,1,5,1,2}},
container{.team = 3, .objects = {7,4,1,5,8,1}},
};
for (auto container : containers)
{
std::cout << "Container is for team " << container.team << " and contains " << container.objects.size() << " items, iterating now.\n";
counts[container.team] += std::reduce(std::execution::seq, container.objects.begin(), container.objects.end(), 0, [](auto sum, auto next)
{
return sum + (next == 3);
});
}
for (auto count : counts)
{
std::cout << "And now we have the counts, for team " << count.first << " we have a total of " << count.second << " items where item equals 3.\n";
}
} AddRconCommand is called multiple times, and it's a random number of times before it finally stops. This only happens on this very large savefile. Smaller maps don't have the problem.
Is there a buffer somewhere that's timing out and repeating or something? (edited)DelayExecute timer with a 1 second delay, and the problem of repeating went away. So there must be something in the API or the server somewhere that deals with RCON commands that repeats the execution after some short timeout?void RunCountRcon(RCONClientConnection* rconclient, RCONPacket* packet, UWorld* world)
{
Log::GetLog()->debug("RunCountRcon Triggered.");
DoCount();
}
And this stops those repeats:
void RunCountRcon(RCONClientConnection* rconclient, RCONPacket* packet, UWorld* world)
{
Log::GetLog()->debug("RunCountRcon Triggered.");
API::Timer::Get().DelayExecute(&DoCount, 1);
}
(DoCount() takes between 6 and 7 seconds to complete on a very large map. On smaller maps, where it takes a much shorter time, the repeats do not occur.)#include <format>
int main() {
std::string s = std::format("{:.2f}", 3.14159265359); // s == "3.14"
}new and delete operators (they're not just keywords) and this is how UE4 uses their own internal memory management systemnew instead of having to manually FMallocparseservertojson in your start argsUPrimalInventoryComponent.RemoteInventoryAllowAddItems and just return false in the cases I need to, which is great. However the S+ transfer tools don't use this function and so on S+ servers it's pointless to use that hook. Does anyone know which functions the S+ tools use?UPrimalInventoryComponent.RemoteInventoryAllowAddItems and just return false in the cases I need to, which is great. However the S+ transfer tools don't use this function and so on S+ servers it's pointless to use that hook. Does anyone know which functions the S+ tools use? AllowAddInventoryItem causes the item to just vanish into thin air. RemoteInventoryAllowAddItems at least blocks the transfer completely, but doesn't work for S+.{ "LimitedItems":
[{
"ItemClass": "ExampleClass_1",
"AllowedInventories": [
"ExampleInventory_1",
"ExampleInventory_2",
"ExampleInventory_3"
]
},
{
"ItemClass": "ExampleClass_2",
"AllowedInventories": [
"ExampleInventory_1",
"ExampleInventory_2",
"ExampleInventory_3"
]
}],
"ExtraDebug": true
}
I have this code (simplified):
struct LimitedItem {
std::string ItemClass;
std::vector<std::string> AllowedInventories;
};
std::vector<LimitedItem> LimitedItems;
void from_json(const nlohmann::json& j, LimitedItem& it) {
j.at("ItemClass").get_to(it.ItemClass);
j.at("AllowedInventories").get_to(it.AllowedInventories);
}
const std::string config_path = ArkApi::Tools::GetCurrentDir() + "/ArkApi/Plugins/TestPlugin/config.json";
std::ifstream file{ config_path };
auto json = nlohmann::json::parse(file);
file.close();
auto ExtraDebug = config["ExtraDebug"].get<bool>();
auto LimitedItems = json["LimitedItems"].get<std::vector<LimitedItem>>();
However the plugin fails to load with a 1114 error. It works if I comment out everything that doesn't just read "ExtraDebug". Can anyone see where I went wrong? Or how I can better debug these JSON errors? (edited)GetOrLoadTribeData provides FTribeData which has everything, but that apparently has memory leak issues.ArkApi::ApiUtils::steam_id_map_? Keeps a "store" or "cache" or whatever you call it of player id vs steam id?ArkApi::ApiUtils::steam_id_map_? Keeps a "store" or "cache" or whatever you call it of player id vs steam id? GetOrLoadTribeData once on startup to prefill the data?GetOrLoadTribeData once on startup to prefill the data? GetOrLoadTribeData, does that count as online or offline?APlayerController::TargetingTeamField() which I compiled and tested and it all worked fine. I shut down and did nothing else until this morning, when I open VS and it won't compile because it says TargetingTeamField() doesn't exist on APlayerController. Unless I'm wrong, AACtor is the base class for APlayerController and AActor definitely has TargetingTeamField().
So I go away for twenty minutes, come back and suddenly it will compile again without any issues and without any changes.
VS doing weird things lolstruct PlacedStructure
{
std::string PrimalItemString;
uint64 TribeID;
};
I thought I could use std::count like this, but it won't work.
std::vector<PlacedStructure> PlacedStructures;
PlacedStructure TestStructure;
TestStructure.TribeID = 123456;
TestStructure.PrimalItemString = "SomePrimalItemString";
TribeStructureCount = std::count(PlacedStructures.begin(), PlacedStructures.end(), TestStructure);
Obviously I can just iterate and count manually, but I was hoping to do it more efficiently.struct PlacedStructure
{
std::string PrimalItemString;
uint64 TribeID;
};
I thought I could use std::count like this, but it won't work.
std::vector<PlacedStructure> PlacedStructures;
PlacedStructure TestStructure;
TestStructure.TribeID = 123456;
TestStructure.PrimalItemString = "SomePrimalItemString";
TribeStructureCount = std::count(PlacedStructures.begin(), PlacedStructures.end(), TestStructure);
Obviously I can just iterate and count manually, but I was hoping to do it more efficiently. TribeStructureCount = std::count_if(PlacedStructures.begin(), PlacedStructures.end(), [&](const PlacedStructure& s) { return s.TribeID == TestStructure.TribeID && s.PrimalItemString == TestStructure.PrimalItemString; }); (edited)UWorld::PreSaveRoot) doesn't seem to be called when saving.UWorld::PreSaveRoot) doesn't seem to be called when saving. DECLARE_HOOK that we use in the API?
hookable<HANDLE(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE), stdcall_t> create_filea;DECLARE_HOOK that we use in the API?
hookable<HANDLE(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE), stdcall_t> create_filea; static auto __stdcall create_file(LPCSTR a, DWORD b, DWORD c, LPSECURITY_ATTRIBUTES d, DWORD e, DWORD f, HANDLE g) -> HANDLE
{
auto which = convert_to_vfs(a);
if (vfs_map.contains(which))
return create_filea.original(vfs_map[which].string().c_str(), b, c, d, e, f, g);
return create_filea.original(a, b, c, d, e, f, g);
} static auto enable() -> void
{
build_vfs(); v---- this is the win api function
create_filea.reset(CreateFileA); <---- this sets the internal pointer to where the original is
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(create_filea.get(), hook(&create_file)); <---- this hooks the original (from the internal pointer on create_filea)
DetourTransactionCommit();
} (edited)static auto __stdcall create_file(LPCSTR a, DWORD b, DWORD c, LPSECURITY_ATTRIBUTES d, DWORD e, DWORD f, HANDLE g) -> HANDLE
{
auto which = convert_to_vfs(a);
if (vfs_map.contains(which))
return create_filea.original(vfs_map[which].string().c_str(), b, c, d, e, f, g); <---- this calls the original after swapping files
return create_filea.original(a, b, c, d, e, f, g); <---- this calls the original from my hook with untouched data.
}hookable<HANDLE(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE)> create_filea;cdecl which is the same as stdcall when in x64stdcall is mostly for 32 bit codehook(&create_file) is also not really required for thiscreate_filehook exists for when I want to do member functions (and I know the this will be passed from the existing program), it's just a work around to trick the compiler to forget that I'm giving it a member methodtemplate<typename T>
static inline auto hook(T member)
{
return *(void**)(&member);
}hook on the callback (edited)
1
(at what point do I have to upgrade?)
Also.. Are you launching the solution via the Application? or Double clicking on the sln file?
(at what point do I have to upgrade?)
Also.. Are you launching the solution via the Application? or Double clicking on the sln file? int configCacheDecayMins = 15;
FString damClassPath = "Blueprint'/Game/PrimalEarth/CoreBlueprints/Inventories/PrimalInventoryBP_BeaverDam.PrimalInventoryBP_BeaverDam'";
UClass* damClass;
FString woodClassPath = "Blueprint'/Game/PrimalEarth/CoreBlueprints/Resources/PrimalItemResource_Wood.PrimalItemResource_Wood'";
UClass* woodClass;
void Hook_UPrimalInventoryComponent_ServerCloseRemoteInventory(UPrimalInventoryComponent* _this, AShooterPlayerController* ByPC)
{
bool isOnlyWood = true;
APrimalStructureItemContainer* cache;
UPrimalInventoryComponent_ServerCloseRemoteInventory_original(_this, ByPC);
if (!damClass)
damClass = UVictoryCore::BPLoadClass(&damClassPath);
if (_this->IsA(damClass) && (_this->InventoryItemsField().Num() > 0))
{
if (!woodClass)
woodClass = UVictoryCore::BPLoadClass(&woodClassPath);
for (UPrimalItem* item : _this->InventoryItemsField())
{
if (item && !item->IsA(woodClass))
{
isOnlyWood = false;
break;
}
}
if (isOnlyWood)
_this->DropInventoryDeposit(ArkApi::GetApiUtils().GetWorld()->GetTimeSeconds() + (configCacheDecayMins * 60), false, false, nullptr, nullptr, &cache, nullptr, FString(""), FString(""), -1, 300, false, -1, false, nullptr, false);
}
}
Hey guys! I just got into writing ARK plugins. Whole new world for me, but I've done a few cool things (in my opinion at least).
This hook makes beaver dams drop their inventory into an item cache when they are left containing only wood. I thought it could be worth publishing as a plugin. Also possible I've made some bad novice mistakes, in which case I'd certainly appreciate any feedback.
I haven't had success getting access on the website so I finally tried opening a ticket here yesterday. Is this the right place for support? If anyone with the appropriate website permissions wants to put this in a plugin, go for it.int configCacheDecayMins = 15;
FString damClassPath = "Blueprint'/Game/PrimalEarth/CoreBlueprints/Inventories/PrimalInventoryBP_BeaverDam.PrimalInventoryBP_BeaverDam'";
UClass* damClass;
FString woodClassPath = "Blueprint'/Game/PrimalEarth/CoreBlueprints/Resources/PrimalItemResource_Wood.PrimalItemResource_Wood'";
UClass* woodClass;
void Hook_UPrimalInventoryComponent_ServerCloseRemoteInventory(UPrimalInventoryComponent* _this, AShooterPlayerController* ByPC)
{
bool isOnlyWood = true;
APrimalStructureItemContainer* cache;
UPrimalInventoryComponent_ServerCloseRemoteInventory_original(_this, ByPC);
if (!damClass)
damClass = UVictoryCore::BPLoadClass(&damClassPath);
if (_this->IsA(damClass) && (_this->InventoryItemsField().Num() > 0))
{
if (!woodClass)
woodClass = UVictoryCore::BPLoadClass(&woodClassPath);
for (UPrimalItem* item : _this->InventoryItemsField())
{
if (item && !item->IsA(woodClass))
{
isOnlyWood = false;
break;
}
}
if (isOnlyWood)
_this->DropInventoryDeposit(ArkApi::GetApiUtils().GetWorld()->GetTimeSeconds() + (configCacheDecayMins * 60), false, false, nullptr, nullptr, &cache, nullptr, FString(""), FString(""), -1, 300, false, -1, false, nullptr, false);
}
}
Hey guys! I just got into writing ARK plugins. Whole new world for me, but I've done a few cool things (in my opinion at least).
This hook makes beaver dams drop their inventory into an item cache when they are left containing only wood. I thought it could be worth publishing as a plugin. Also possible I've made some bad novice mistakes, in which case I'd certainly appreciate any feedback.
I haven't had success getting access on the website so I finally tried opening a ticket here yesterday. Is this the right place for support? If anyone with the appropriate website permissions wants to put this in a plugin, go for it. template <typename T, typename... Args>
FORCEINLINE void SendServerMessage(AShooterPlayerController* player_controller, FLinearColor msg_color, const T* msg, Args&&... args)
{
if (player_controller)
{
FString text(FString::Format(msg, std::forward<Args>(args)...));
player_controller->ClientServerChatDirectMessage(&text, msg_color, false);
}
}
I understand that typename... Args allows any number of parameters to be supplied to allow, for example, a large number of strings. I think I understand that std::forward is forwarding all those arguments to FString::Format which I assume will accept them. And I think I understand that typename T is used for msg to allow for different types of strings to be used for the message.
Am I getting anything wrong there?template <typename T, typename... Args>
FORCEINLINE void SendServerMessage(AShooterPlayerController* player_controller, FLinearColor msg_color, const T* msg, Args&&... args)
{
if (player_controller)
{
FString text(FString::Format(msg, std::forward<Args>(args)...));
player_controller->ClientServerChatDirectMessage(&text, msg_color, false);
}
}
I understand that typename... Args allows any number of parameters to be supplied to allow, for example, a large number of strings. I think I understand that std::forward is forwarding all those arguments to FString::Format which I assume will accept them. And I think I understand that typename T is used for msg to allow for different types of strings to be used for the message.
Am I getting anything wrong there? SGM:InitGame hook to run some code, which works fine when the plugin is loaded normally at server startup, but I want have that same code run when the plugin is loaded after startup with the plugins.load command. (edited)c++
if (ArkApi::GetApiUtils().GetStatus() == ArkApi::ServerStatus::Ready)
{
// plugin was loaded while server was running
}c++
if (ArkApi::GetApiUtils().GetStatus() == ArkApi::ServerStatus::Ready)
{
// plugin was loaded while server was running
}
1
1resourceswhen essentially all the work done on the project in the last 12 months or more was freely contributed by other developers doesn't sit right with me.
The same team is the one running ArkServerAPI.
but I'd really love to know exactly who and what this new organisation is made up of.
Same as before, the same support team members are still running it as normal.
I'd also really love to hear from the people who've actually contributed code to the API, and what they think of all this.
The API team is still active and will still provide support. If anything the API will now have more support since the support team members will now be paid for their services and time.The level of commercialization also doesn't sit right either.
The support team that is helping run and keeping updates to the official API will be paid as before they weren't being paid for their services. We're actually building and working on new requirements for "Paid Plugins" where devs will have to contribute an "X" amount of "FREE" plugins or content before they can upload "PAID" plugins. This will create a system where there are more "FREE" plugins for the public rather then privatized and paid plugins controlling the marketplace. We're gonna explore this more in-depth as a staff team together to make sure we find the right balance between all of that. It's a good thing that the new system can support and allow support team members to earn monthly cash incentives for helping grow and keep the project alive it's the least we can do to show support for their hard work.
The overall goal and objective is to provide more "FREE" content rather then content hidden behind subscriptions and paywalls.
I think you're going to need to be a LOT more transparent. Saying "the same" isn't transparent.
I agree with you, with the new updates we should be 100% transparent about everything. I don't disagree with you at all on that, I support that 100% and that will happen going forward.
Why aren't these people mentioned anywhere?
Yeah that's a great question, the question being how can we showcase the devs working behind the scenes to support ArkServerAPI. We'll have to discuss that with the staff team and see which staff members want to be credited publicly, that's a great idea I support that. Maybe we can do a section on site to include them as credit with a short bio or something.
Because all I've seen so far are you and Foppa, and, while you are both obviously very talented devs who've both written some great plugins, as far as I know, and I could be wrong, neither of you have written any code that is currently in the API source?
That's another great question, Yeah Foppa is active in the API development, we also have an amazing team now that works together to push out "official" API updates. In the past it was strictly restricted to Michidu producing updates, in the past 6 months or so Foppa and the other support team members have been getting together to provide regular quality of life updates to API. We're always growing the support team and now with the support team officially being "paid" for their services we can really start to plan out a future strategy for Ark 2 and beyond.The level of commercialization also doesn't sit right either.
The support team that is helping run and keeping updates to the official API will be paid as before they weren't being paid for their services. We're actually building and working on new requirements for "Paid Plugins" where devs will have to contribute an "X" amount of "FREE" plugins or content before they can upload "PAID" plugins. This will create a system where there are more "FREE" plugins for the public rather then privatized and paid plugins controlling the marketplace. We're gonna explore this more in-depth as a staff team together to make sure we find the right balance between all of that. It's a good thing that the new system can support and allow support team members to earn monthly cash incentives for helping grow and keep the project alive it's the least we can do to show support for their hard work.
The overall goal and objective is to provide more "FREE" content rather then content hidden behind subscriptions and paywalls.
I think you're going to need to be a LOT more transparent. Saying "the same" isn't transparent.
I agree with you, with the new updates we should be 100% transparent about everything. I don't disagree with you at all on that, I support that 100% and that will happen going forward.
Why aren't these people mentioned anywhere?
Yeah that's a great question, the question being how can we showcase the devs working behind the scenes to support ArkServerAPI. We'll have to discuss that with the staff team and see which staff members want to be credited publicly, that's a great idea I support that. Maybe we can do a section on site to include them as credit with a short bio or something.
Because all I've seen so far are you and Foppa, and, while you are both obviously very talented devs who've both written some great plugins, as far as I know, and I could be wrong, neither of you have written any code that is currently in the API source?
That's another great question, Yeah Foppa is active in the API development, we also have an amazing team now that works together to push out "official" API updates. In the past it was strictly restricted to Michidu producing updates, in the past 6 months or so Foppa and the other support team members have been getting together to provide regular quality of life updates to API. We're always growing the support team and now with the support team officially being "paid" for their services we can really start to plan out a future strategy for Ark 2 and beyond. 
1
https://www.gameservershub.com/forums/resources/ark-server-api.12/, but that isn't easy to get to from the current landing page..thmonetize_upgradeHeader__price {
z-index: 0;
}
.thmonetize_upgradeHeader__price:before {
z-index: -1;
}https://www.gameservershub.com/forums/resources/ark-server-api.12/, but that isn't easy to get to from the current landing page.
1Resources tabREST API today it's live on site and it's also setup in a staff discord channel. We're gonna have a development docs wiki setup hopefully in the coming weeks that will include the API itself and the other developer tools. It's definitely a feature being planned and slowly worked on right now.
I guess I'm also a little worried about directing users from the website to this Discord.REST API today it's live on site and it's also setup in a staff discord channel. We're gonna have a development docs wiki setup hopefully in the coming weeks that will include the API itself and the other developer tools. It's definitely a feature being planned and slowly worked on right now.
I guess I'm also a little worried about directing users from the website to this Discord.GRAB | PULL | READ | VALIDATE any site data in real time with your content. Very helpful for plugins/licenses/discord bots and other personal website integrations.GRAB | PULL | READ | VALIDATE any site data in real time with your content. Very helpful for plugins/licenses/discord bots and other personal website integrations. 
const uint64 playerId = ArkApi::IApiUtils::GetSteamIdFromController(playerController);FUniqueNetIdEOSDeveloper roles can see the channels. Developer role will sync directly to forum rank to lower those chat messages.5% the old system was 8-10%5% the old system was 8-10%
If i didnt miss any free version (edited)Ark Permissions plugin listed anymore. Was the name changed to something else or is it removed?Ark Permissions plugin listed anymore. Was the name changed to something else or is it removed? Ark Permissions is a plugin and ARK: Server API is the framework? Since they're both in the same category. Maybe by some sort of tag you can add. So i know which items to ignore. (same goes for ATLAS) (edited)ARK: Server API is gonna show up as a downloadable pluginARK: Server API is gonna show up as a downloadable plugin Ark Permissions plugin was listed under the free category. So that worked fineArk Permissions is a plugin and ARK: Server API is the framework? Since they're both in the same category. Maybe by some sort of tag you can add. So i know which items to ignore. (same goes for ATLAS) (edited)Framework you can filter this via your end.
1ClampItemStats=true
DestroyTamesOverLevelClamp=450
ItemStatClamps[1]=19800
ItemStatClamps[3]=19800ClampItemStats=true
DestroyTamesOverLevelClamp=450
ItemStatClamps[1]=19800
ItemStatClamps[3]=19800 ClampItemStats=true
DestroyTamesOverLevelClamp=450
ItemStatClamps[1]=19800
ItemStatClamps[3]=19800 DestroyTamesOverLevelClamp still works as expected for me. If you have tames over the clamp they get destroyed on restart. WC also improved it over the years so that you can't manually level your tames past the clamp or release dinos from cryos if they're above the clamp. I thought that was the behavior on official now, but I don't play much official anymore. Similar to item stats, it's still incomplete/buggy/whatever you want it call it.DestroyTamesOverLevelClamp still works as expected for me. If you have tames over the clamp they get destroyed on restart. WC also improved it over the years so that you can't manually level your tames past the clamp or release dinos from cryos if they're above the clamp. I thought that was the behavior on official now, but I don't play much official anymore. Similar to item stats, it's still incomplete/buggy/whatever you want it call it.
1Game.INI file directly to see if the configuration edit is successfully added into the configuration file. In addition to that you should go to the steam workshop mod page for that mod and ensure that's the correct engram_bp_path otherwise it won't work. I personally would highly suggest using https://usebeacon.app/ over ASM as beacon has more support and handles the configuration editing much easier then ASM.void Startup_LoadActorsHWID()
{
FString bpPath = "Blueprint'/Game/Mods/HWIDBans/Actor_BP_HWIDBans.Actor_BP_HWIDBans'";
UClass* actorBpHWID = MyBPLoadClass(&bpPath);
if (actorBpHWID != nullptr)
{
TArray<AActor*> foundActorsHWID;
UGameplayStatics::GetAllActorsOfClass(ArkApi::GetApiUtils().GetWorld(), actorBpHWID, &foundActorsHWID);
int nbActorsFound = foundActorsHWID.Num();
if (nbActorsFound > 0)
for (int i = 0; i < nbActorsFound; i++)
{
AActor* actorHWID = foundActorsHWID[i];
// Is this how to get the AShooterPlayerController* for this actor?
AShooterPlayerController* shooterPC = static_cast<AShooterPlayerController*>(actorHWID->GetOwnerController());
CacheActorHWIDForPlayer(shooterPC, actorHWID);
}
}
} (edited)https://ark-server-api.com/forums/resources/market-place-dashboard/view-sales-useautoreporter I think this will do that.Failed to open connection!. Tried with two different MySQL Servers now. (MySQL 8.0.28). I setup that server pretty fresh, so I am not sure if it's a problem with MySQL 8.0 or if there is any C++ Redistributable or something missing. Anyone got a idea where I can check what's not working anymore? Even tried to dump the error_code or error_message from the daotk::mysql lib. code is 0, message is emptyC:\Program Files\MySQL\MySQL Server 8.0\bin>mysql -uark -park ark
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 5898
Server version: 8.0.28 MySQL Community Server - GPL
Copyright (c) 2000, 2022, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show tables;
+-----------------------+
| Tables_in_ark |
+-----------------------+
| xxxxxxxxx |
| xxxxxxxxxxx |
| xxxxxxxxx |
+-----------------------+
3 rows in set (0.01 sec)
can connect via mysql command line.dll files on their machines as if any of the hidden console files were taken from a machine it could result in legal action between Nitrado and Wildcard studios. They know it's something that would benefit their customers but it comes at a risk of not knowing how safe plugin files are. I have plans down the road to establish built in virus protection scanning and more safe guards into the resource downloads to ensure user safety is priority.
I personally would suggest avoid them entirely and getting a dedicated machine or use a service like GameServerApp that has better reputation and supports ArkServerAPI integration directly..dll files on their machines as if any of the hidden console files were taken from a machine it could result in legal action between Nitrado and Wildcard studios. They know it's something that would benefit their customers but it comes at a risk of not knowing how safe plugin files are. I have plans down the road to establish built in virus protection scanning and more safe guards into the resource downloads to ensure user safety is priority.
I personally would suggest avoid them entirely and getting a dedicated machine or use a service like GameServerApp that has better reputation and supports ArkServerAPI integration directly.
1c++
const auto iter = std::find_if(online_players_.begin(), online_players_.end(),
[steamid](const std::shared_ptr<OnlinePlayersData>& data) -> bool
{
return data->steam_id == steamid;
});closed source now or in the future.
1Fatal error!
VERSION: 346.16
VERSION.dll!ArkApi::Commands::CheckCommands<ArkApi::Commands::Command<void __cdecl(RCONClientConnection *,RCONPacket *,UWorld *)>,RCONClientConnection * &,RCONPacket * &,UWorld * &>() (0x00007fff79ec7625) + 83 bytes [J:\ARK-Server-API-master\ARK-Server-API\version\Core\Private\Commands.h:115]
VERSION.dll!ArkApi::Hook_RCONClientConnection_ProcessRCONPacket() (0x00007fff79ec3c34) + 0 bytes [J:\ARK-Server-API-master\ARK-Server-API\version\Core\Private\Ark\HooksImpl.cpp:145]
CommandLogger.dll!UnknownFunction (0x00007fff70e4d547) + 0 bytes [UnknownFile:0]
ShooterGameServer.exe!RCONClientConnection::Tick() (0x00007ff7a886b77f) + 0 bytes [f:\build\lostisland\projects\shootergame\source\shootergame\private\rconserver.cpp:104]
ShooterGameServer.exe!URCONServer::Tick() (0x00007ff7a886d409) + 0 bytes [f:\build\lostisland\projects\shootergame\source\shootergame\private\rconserver.cpp:324]
ShooterGameServer.exe!AShooterGameMode::Tick() (0x00007ff7a8a63a51) + 0 bytes [f:\build\lostisland\projects\shootergame\source\shootergame\private\shootergamemode.cpp:5223]
ShooterGameServer.exe!AActor::TickActor() (0x00007ff7aa10c00e) + 0 bytes [f:\build\lostisland\engine\source\runtime\engine\private\actor.cpp:789]
ShooterGameServer.exe!FActorTickFunction::ExecuteTick() (0x00007ff7aa10a7aa) + 30 bytes [f:\build\lostisland\engine\source\runtime\engine\private\actor.cpp:154]
ShooterGameServer.exe!TGraphTask<FTickTaskSequencer::FTickFunctionTask>::ExecuteTask() (0x00007ff7aa3d81bc) + 28 bytes [f:\build\lostisland\engine\source\runtime\core\public\async\taskgraphinterfaces.h:871]
ShooterGameServer.exe!FNamedTaskThread::ProcessTasksNamedThread() (0x00007ff7a9b59c25) + 0 bytes [f:\build\lostisland\engine\source\runtime\core\private\async\taskgraph.cpp:939]
ShooterGameServer.exe!FNamedTaskThread::ProcessTasksUntilQuit() (0x00007ff7a9b5954e) + 0 bytes [f:\build\lostisland\engine\source\runtime\core\private\async\taskgraph.cpp:680]
ShooterGameServer.exe!FTaskGraphImplementation::WaitUntilTasksComplete() (0x00007ff7a9b5b424) + 0 bytes [f:\build\lostisland\engine\source\runtime\core\private\async\taskgraph.cpp:1777]
ShooterGameServer.exe!FTickTaskSequencer::ReleaseTickGroup() (0x00007ff7aa3aa693) + 0 bytes [f:\build\lostisland\engine\source\runtime\engine\private\ticktaskmanager.cpp:205]
ShooterGameServer.exe!FTickTaskManager::RunTickGroup() (0x00007ff7aa3ad56c) + 0 bytes [f:\build\lostisland\engine\source\runtime\engine\private\ticktaskmanager.cpp:867]
ShooterGameServer.exe!UWorld::RunTickGroup() (0x00007ff7aa2707fe) + 0 bytes [f:\build\lostisland\engine\source\runtime\engine\private\leveltick.cpp:697]
ShooterGameServer.exe!UWorld::Tick() (0x00007ff7aa271dfb) + 13 bytes [f:\build\lostisland\engine\source\runtime\engine\private\leveltick.cpp:1210]
ShooterGameServer.exe!UGameEngine::Tick() (0x00007ff7aa1dc801) + 0 bytes [f:\build\lostisland\engine\source\runtime\engine\private\gameengine.cpp:1195]
ShooterGameServer.exe!FEngineLoop::Tick() (0x00007ff7a7fc7c12) + 0 bytes [f:\build\lostisland\engine\source\runtime\launch\private\launchengineloop.cpp:2647]
ShooterGameServer.exe!GuardedMain() (0x00007ff7a7fc39cc) + 0 bytes [f:\build\lostisland\engine\source\runtime\launch\private\launch.cpp:140]
ShooterGameServer.exe!GuardedMainWrapper() (0x00007ff7a7fc8b9a) + 5 bytes [f:\build\lostisland\engine\source\runtime\launch\private\windows\launchwindows.cpp:125]
ShooterGameServer.exe!WinMain() (0x00007ff7a7fc8ce9) + 8 bytes [f:\build\lostisland\engine\source\runtime\launch\private\windows\launchwindows.cpp:213]
ShooterGameServer.exe!__tmainCRTStartup() (0x00007ff7ab275799) + 21 bytes [f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c:618]
KERNEL32.DLL!UnknownFunction (0x00007fffad167974) + 0 bytes [UnknownFile:0]
ntdll.dll!UnknownFunction (0x00007fffadafa2f1) + 0 bytes [UnknownFile:0]
ntdll.dll!UnknownFunction (0x00007fffadafa2f1) + 0 bytes [UnknownFile:0]
慌瑳删灥楬慣整捁潴汐祡牥慐湷敔瑳䙟浥污彥彃ㄱ慌瑳删浥瑯畆据楴湯䌠楬湥䅴正潇摯潍敶
Func value, which is a pointer to an "exec" method that interfaces between the Unreal VM call stack and native calling conventions. Then I'd use Zydis to disassemble the exec function at runtime and automatically detect the native address (for virtual functions I would grab the class's default object from the global objects array).
More recently, I'm wondering if I can avoid the disassambler and just do hooking/calling using the UFunction's Func field. It's not quite as fast but it's more reliable and easier to implement, especially since I'll be doing it for blueprint hooking anyways. One concern I have about this method is that I think there are cases where some of those native functions get called natively instead of as UFunctions, so the hooking may not always be reliable.Func value, which is a pointer to an "exec" method that interfaces between the Unreal VM call stack and native calling conventions. Then I'd use Zydis to disassemble the exec function at runtime and automatically detect the native address (for virtual functions I would grab the class's default object from the global objects array).
More recently, I'm wondering if I can avoid the disassambler and just do hooking/calling using the UFunction's Func field. It's not quite as fast but it's more reliable and easier to implement, especially since I'll be doing it for blueprint hooking anyways. One concern I have about this method is that I think there are cases where some of those native functions get called natively instead of as UFunctions, so the hooking may not always be reliable. ProcessEvent as a UFunction if I'm remembering correctlyProcessEvent as a UFunction if I'm remembering correctly UObject::ProcessEvent( UFunction* Function, void* Parms ), but the engine also sometimes invokes UFunctions through UObject::CallFunction( FFrame& Stack, RESULT_DECL, UFunction* Function ). Both of those functions eventually call UFunction::Invoke(UObject* Obj, FFrame& Stack, RESULT_DECL), which calls the function pointed to by the UFunctions Func field.
For native UFunctions, Func points to the function's "exec" helper function that eventually calls the actual function. For script functions, Func points to UObject::ProcessInternal( FFrame& Stack, RESULT_DECL ), which executes the VM bytecode.
So (I think) you can use ProcessEvent to call any UFunction (how other ARK SDKs work), but you won't be able to hook every single UFunction call with it. That's why I like the idea of just modifying the Func field of hooked UFunctions so they call into my own hook dispatcher function. But that technique only works if every native function that is reflected as a UFunction always gets called as a UFunction, which I'm not sure is the case.
Then you have many native engine functions that don't make it into the reflection system (e.g., all the functions I just mentioned). ArkServerApi can get at them through debug symbols, but we're not so lucky on Linux. ProcessInternal()'s address is easy to find at least because you can read it from a script UFunction's Func field.GetPrivateStaticClass() function. I also see a couple mentions of it crashing in the Discord history. In ArkServerAPI headers, some classes define it with UClass* GetPrivateStaticClass(), some classes define it with UClass* GetPrivateStaticClass(const wchar_t* Package), and a few classes overload it with both forms. The overloading confused me because IDA only finds one instance of the function per class and ArkServerAPI doesn't appear to handle overloaded functions well anyways.
IDA always shows the name of the function as [Class]::GetPrivateStaticClass(const wchar_t*) with an arg. However, IDA also ends up showing some variation in the function type between classes: UClass *__fastcall(const wchar_t *Package) or UClass *__fastcall() or UField *__fastcall(TClassCompiledInDefer<UPrimitiveComponent> *this). I guess that's how the different forms ended up in the headers?
Sometimes GetPrivateStaticClass() uses the Package arg, sometimes it just gets the string from elsewhere in memory (I don't know if that's because of how the classes are defined in UE or a quirk of compilation or what). The second case is when IDA shows the arg-less type.GetPrivateStaticClass() is defined as:
c++
UClass* TClass::GetPrivateStaticClass(const TCHAR* Package)
{
static UClass* PrivateStaticClass = NULL;
if (!PrivateStaticClass)
{
/* this could be handled with templates, but we want it external to avoid code bloat */
GetPrivateStaticClassBody<TClass>(
Package,
(TCHAR*)TEXT(#TClass) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0),
PrivateStaticClass,
StaticRegisterNatives##TClass
);
}
return PrivateStaticClass;
}
So the Package arg often ends up not mattering, even when IDA does show it in the function type.
Looks to me like it's always safe to use the form with the Package arg and the arg-less form can sometimes be a problem?GetPrivateStaticClass() functions because I re-generated the ARK API headers for myself (nothing new, just updating the existing function definitions, hasn't been done in a while). I was going to submit a PR but I wasn't sure how to handle GetPrivateStaticClass(). Seems correct to me to always use GetPrivateStaticClass(const wchar_t*). But I wonder if that's too high-impact. For example, ArkServerAPI has code that uses APrimalDinoCharacter::GetPrivateStaticClass() even though IDA shows that function taking an arg. Not sure how intentional it is. Maybe I should just leave GetPrivateStaticClass() as the dev team already has it and update the other functions. (edited)GetPrivateStaticClass() functions because I re-generated the ARK API headers for myself (nothing new, just updating the existing function definitions, hasn't been done in a while). I was going to submit a PR but I wasn't sure how to handle GetPrivateStaticClass(). Seems correct to me to always use GetPrivateStaticClass(const wchar_t*). But I wonder if that's too high-impact. For example, ArkServerAPI has code that uses APrimalDinoCharacter::GetPrivateStaticClass() even though IDA shows that function taking an arg. Not sure how intentional it is. Maybe I should just leave GetPrivateStaticClass() as the dev team already has it and update the other functions. (edited)GetPrivateStaticClass()static UClass* GetPrivateStaticClass() and static UClass* GetPrivateStaticClass(const wchar_t* Package) for this functionGetPrivateStaticClass() that's been compiled like that without explicitly giving it an argument, what value does the function ends up using as Package?
1ADroppedItemEgg::GetPrivateStaticClass() like I normally do with something like APrimalStructureItemContainer::GetPrivateStaticClass(), however the first is asking for an argument const wchar_t* Package. Can someone help me understand what that is?ADroppedItemEgg::GetPrivateStaticClass() like I normally do with something like APrimalStructureItemContainer::GetPrivateStaticClass(), however the first is asking for an argument const wchar_t* Package. Can someone help me understand what that is? nullptr. I want to play with it a little more later when I have some free time, been messing around with the GetPrivateStaticClass() functions myself lately.nullptr. I want to play with it a little more later when I have some free time, been messing around with the GetPrivateStaticClass() functions myself lately. ::StaticClass() instead, which seems to get the same result as ::GetPrivateStaticClass?UPrimalInventoryComponent->AddCustomFolderServerNotifyEditText which is why it is so particular and problematic and why it always crashes when trying to call it from plugin code. FServerCustomFolder folder;
folder.FolderName = <text>;
folder.InventoryCompType = 768;
UPrimalInventoryComponent->CustomFolderItemsField().Add(folder);
UPrimalInventoryComponent->ServerCustomFolderField().Add(<text>); (edited)UPrimalInventoryComponent->AddCustomFolder c++
void AddCustomFolder(UPrimalInventoryComponent* Comp, FString FolderName)
{
FServerCustomFolder Folder;
Folder.FolderName = FolderName;
Folder.InventoryCompType = 512;// crafting tab
Comp->CustomFolderItemsField().Add(Folder);
} (edited)c++
void AddCustomFolder(UPrimalInventoryComponent* Comp, FString FolderName)
{
FServerCustomFolder Folder;
Folder.FolderName = FolderName;
Folder.InventoryCompType = 512;// crafting tab
Comp->CustomFolderItemsField().Add(Folder);
} (edited)
bIncludeHotbarSlots arg:
c++
bool DropInventoryDeposit(long double DestroyAtTime, bool bDoPreventSendingData, bool bIgnorEquippedItems, TSubclassOf<APrimalStructureItemContainer> OverrideInventoryDepositClass, APrimalStructureItemContainer* CopyStructureValues, APrimalStructureItemContainer** DepositStructureResult, AActor* GroundIgnoreActor, FString CurrentCustomFolderFilter, FString CurrentNameFilter, unsigned __int64 DeathCacheCharacterID, float DropInventoryOnGroundTraceDistance, bool bForceDrop, int OverrideMaxItemsDropped, bool bOverrideDepositLocation, FVector* DepositLocationOverride, bool bForceLocation, bool bIncludeHotbarSlots)
instead of:
c++
bool DropInventoryDeposit(long double DestroyAtTime, bool bDoPreventSendingData, bool bIgnorEquippedItems, TSubclassOf<APrimalStructureItemContainer> OverrideInventoryDepositClass, APrimalStructureItemContainer* CopyStructureValues, APrimalStructureItemContainer** DepositStructureResult, AActor* GroundIgnoreActor, FString CurrentCustomFolderFilter, FString CurrentNameFilter, unsigned __int64 DeathCacheCharacterID, float DropInventoryOnGroundTraceDistance, bool bForceDrop, int OverrideMaxItemsDropped, bool bOverrideDepositLocation, FVector* DepositLocationOverride, bool bForceLocation)
But even after fixing the definition it didn't seem to work for me. I didn't spend any time on it though, just switched to using this instead:
c++
void BPDropInventoryDeposit(long double DestroyAtTime, int OverrideMaxItemsDropped, bool bOverrideCacheLocation, FVector CacheLocationOverride)bIncludeHotbarSlots arg:
c++
bool DropInventoryDeposit(long double DestroyAtTime, bool bDoPreventSendingData, bool bIgnorEquippedItems, TSubclassOf<APrimalStructureItemContainer> OverrideInventoryDepositClass, APrimalStructureItemContainer* CopyStructureValues, APrimalStructureItemContainer** DepositStructureResult, AActor* GroundIgnoreActor, FString CurrentCustomFolderFilter, FString CurrentNameFilter, unsigned __int64 DeathCacheCharacterID, float DropInventoryOnGroundTraceDistance, bool bForceDrop, int OverrideMaxItemsDropped, bool bOverrideDepositLocation, FVector* DepositLocationOverride, bool bForceLocation, bool bIncludeHotbarSlots)
instead of:
c++
bool DropInventoryDeposit(long double DestroyAtTime, bool bDoPreventSendingData, bool bIgnorEquippedItems, TSubclassOf<APrimalStructureItemContainer> OverrideInventoryDepositClass, APrimalStructureItemContainer* CopyStructureValues, APrimalStructureItemContainer** DepositStructureResult, AActor* GroundIgnoreActor, FString CurrentCustomFolderFilter, FString CurrentNameFilter, unsigned __int64 DeathCacheCharacterID, float DropInventoryOnGroundTraceDistance, bool bForceDrop, int OverrideMaxItemsDropped, bool bOverrideDepositLocation, FVector* DepositLocationOverride, bool bForceLocation)
But even after fixing the definition it didn't seem to work for me. I didn't spend any time on it though, just switched to using this instead:
c++
void BPDropInventoryDeposit(long double DestroyAtTime, int OverrideMaxItemsDropped, bool bOverrideCacheLocation, FVector CacheLocationOverride) c++
APrimalStructureItemContainer* dropAllCharacter(APrimalCharacter* char1, UPrimalInventoryComponent* inv, bool bIgnoreEquippedItems = false)
{
if (inv)
{
APrimalStructureItemContainer* deathCache = nullptr;
auto Location = myTools::GetGroundLocation(&char1->RootComponentField()->RelativeLocationField());
bool bForceDrop = true;
bool bOverrideDepositLocation = true;
bool bForceLocation = true;
inv->DropInventoryDeposit(ArkApi::GetApiUtils().GetWorld()->TimeSecondsField() + 3600, false, bIgnoreEquippedItems, nullptr, nullptr, &deathCache, nullptr, FString(""), FString(""), -1, 300, bForceDrop, -1, bOverrideDepositLocation, &Location, bForceLocation);
return deathCache;
}
return nullptr;
} (edited)

1StructureSpawnPointMaxDistance float variable on a Deinonychus_Character_BP actor. Then I'd like to run the Spawn Nest Egg bp function. (edited)StructureSpawnPointMaxDistance float variable on a Deinonychus_Character_BP actor. Then I'd like to run the Spawn Nest Egg bp function. (edited)FindProperty for a variable and assign it to a UProperty*, then Set that property to change it? I assume you need to know the variable type beforehand?FindFunctionChecked to assign it to a UFunction*, then ProcessEvent to run the function?nullptr in parametersAActor* ModComm::GetModSingleton()
{
ACustomActorList* customList = UVictoryCore::GetCustomActorList(ArkApi::GetApiUtils().GetWorld(), FName("CustomActorListName", EFindName::FNAME_Add));
if (customList)
{
return customList->ActorListField()[0];
}
return nullptr;
}struct ACustomActorList : AInfo
{
TArray<AActor*> ActorListField() { return *GetNativePointerField<TArray<AActor*>*>(this, "ACustomActorList.ActorList"); }
};auto_update_config.json that gives you the boolean for true/false to enable.07/27/22 19:06 [API][info] -----------------------------------------------
07/27/22 19:06 [API][info] ARK: Server Api V3.54
07/27/22 19:06 [API][info] Loading...
Is this intended?auto_update_config.json inside it you can toggle the auto update feature on or off (it comes enabled by default)07/27/22 19:06 [API][info] -----------------------------------------------
07/27/22 19:06 [API][info] ARK: Server Api V3.54
07/27/22 19:06 [API][info] Loading...
Is this intended?
1auto_update_config.json inside it you can toggle the auto update feature on or off (it comes enabled by default) auto_update_config.json inside it you can toggle the auto update feature on or off (it comes enabled by default)
1UPrimalGlobals::GetDayCycleManager(ArkApi::GetApiUtils().GetWorld());UPrimalGlobals::GetDayCycleManager(ArkApi::GetApiUtils().GetWorld()); ADayCycleManager which is only defined in the API as an empty struct in the Atlas code. How would I get from there to being able to call FindProperty and FindFuctionChecked on that class?ADayCycleManager which is only defined in the API as an empty struct in the Atlas code. How would I get from there to being able to call FindProperty and FindFuctionChecked on that class? .def file to get unmangled names for exports.def two exports, one with the old name mangling and one with unmangled for backwards compatibility though, I'm not 100% sure yet.GetBitField should be exported as just ... thatProcessEventProcessEvent auto spongehax::process_event(sdk::UObject* who, sdk::UFunction* what, void* how) -> void
{
while(!tick_queue.empty())
{
tick_queue.front()();
tick_queue.pop();
}
const auto func = what->GetName();
auto handled = false;
for (auto [_, callback] : process_event_handlers[func])
{
handled = callback(who, how);
if (handled) return;
}
process_event_.original(who, what, how);
} static std::unordered_map<std::string, std::unordered_map<std::string, std::function<bool(sdk::UObject*, void*)>>> process_event_handlers; process_event_handlers["ReceiveBeginPlay"]["add_tracked"] = [](sdk::UObject* who, void*) -> bool
{
if (is_default(who)) return false;
for (auto tracked : tracked_classes)
if (who->IsA(tracked))
actor_lists[tracked].insert(who);
return false;
};
process_event_handlers["ReceiveEndPlay"]["removed_tracked"] = [](sdk::UObject* who, void*) -> bool
{
if (is_default(who)) return false;
for (auto tracked : tracked_classes)
if (who->IsA(tracked))
actor_lists[tracked].erase(who);
return false;
};UVictoryCore::BPLoadClass() to load the class we want to get the function inFindFunctionChecked to find the funtion we are looking forInternalIndexField in a variable for further usage on ProcessEvent hookUObject::ProcessEvent, then inside the hook check if the Function->InternalIndexField() equals the one you saved earlier. If it matches then you are on the function you need
CallFunction(), not ProcessEvent(). Even then, you can still access the arguments and variables through the UE VM stack if you define a few additional structures (stuff like UFunction, FFrame, FOutParmRec) that ArkServerAPI doesn't currently fully provide.execFoo() functions that UE generates for native UFunctions). Still got several kinks to work out though.execFoo() functions that UE generates for native UFunctions). Still got several kinks to work out though. int FunctionIdx = -1;
void LoadFunction()
{
static FString f("Blueprint'/Game/...'");
UClass* loadedClass = UVictoryCore::BPLoadClass(&f);
if (loadedClass)
{
UObject* CDO = loadedClass->GetDefaultObject(true);
if (CDO)
{
UFunction* func = CDO->FindFunctionChecked(FName("FuncName", EFindName::FNAME_Add));
if (func)
{
FunctionIdx = func->InternalIndexField();
}
}
}
}
DECLARE_HOOK(AActor_ProcessEvent, void, AActor*, UFunction*, void*);
void Hook_AActor_ProcessEvent(AActor* _this, UFunction* Function, void* Parameters)
{
if (_this
&& Function
&& Function->InternalIndexField() == FunctionIdx)
{
// it's what we need
}
}int FunctionIdx = -1;
void LoadFunction()
{
static FString f("Blueprint'/Game/...'");
UClass* loadedClass = UVictoryCore::BPLoadClass(&f);
if (loadedClass)
{
UObject* CDO = loadedClass->GetDefaultObject(true);
if (CDO)
{
UFunction* func = CDO->FindFunctionChecked(FName("FuncName", EFindName::FNAME_Add));
if (func)
{
FunctionIdx = func->InternalIndexField();
}
}
}
}
DECLARE_HOOK(AActor_ProcessEvent, void, AActor*, UFunction*, void*);
void Hook_AActor_ProcessEvent(AActor* _this, UFunction* Function, void* Parameters)
{
if (_this
&& Function
&& Function->InternalIndexField() == FunctionIdx)
{
// it's what we need
}
} void LoadFunction()
{
static FString f("Blueprint'/Game/...'");
UClass* loadedClass = UVictoryCore::BPLoadClass(&f);
if(!loadedClass)
return;
UObject* CDO = loadedClass->GetDefaultObject(true);
if(!CDO)
return;
UFunction* func = CDO->FindFunctionChecked(FName("FuncName", EFindName::FNAME_Add));
if(func)
FunctionIdx = func->InternalIndexField();
}CallFunction(), not ProcessEvent(). Even then, you can still access the arguments and variables through the UE VM stack if you define a few additional structures (stuff like UFunction, FFrame, FOutParmRec) that ArkServerAPI doesn't currently fully provide. CallFunction(), so I was wondering if you had some example on how to read parameters and write the return value?CallFunction(), so I was wondering if you had some example on how to read parameters and write the return value? FFrame to tell you where locals are stored plus Offset_Internal from the UProperty. For outputs, you can get the address directly from the FOutParmRecs PropAddr field.CallFunction(), so I was wondering if you had some example on how to read parameters and write the return value? CallFunction(). I think basically if there is a UE FFrame stack available, CallFunction() is used. And ProcessEvent() is called when a new stack needs to be created.
FFrame to tell you where locals are stored plus Offset_Internal from the UProperty. For outputs, you can get the address directly from the FOutParmRecs PropAddr field. FFrame has been created and populated and is still valid (i.e., in the middle of ProcessEvent() or CallFunction()). So you can't just hook CallFunction() and access the args like you've seen with hooking ProcessEvent(). CallFunction() and ProcessEvent() both eventually call ProcessInternal() for script UFunctions (not native UFunctions), so hooking that function might be one option.CanCapture BlueprintPure script function to prevent cryopods from capturing any dino:
c++
// WeapEmptyCryopod_C CanCapture()
// Public, HasOutParms, BlueprintCallable, BlueprintEvent, BlueprintPure
//
// Parameters (0x0009)
// 0x0000 (0x0008) Dino ObjectProperty Parm, ZeroConstructor, IsPlainOldData, NoDestructor
// 0x0008 (0x0001) Capture BoolProperty Parm, OutParm, ZeroConstructor, IsPlainOldData, NoDestructor
DECLARE_HOOK(UObject_ProcessInternal, void, UObject*, FFrame*, void* const);
void Hook_UObject_ProcessInternal(UObject* _this, FFrame* Stack, void* const Result)
{
// If this is not our function, process the script normally and return
if (Stack->NodeField()->NameField().ToString().ToString() != "CanCapture") {
UObject_ProcessInternal_original(_this, Stack, Result);
return;
}
bool* outputCapture = nullptr;
int outParmCount = 0;
FOutParmRec* currOutParm = Stack->OutParmsField();
for (UProperty* currProperty = Stack->NodeField()->PropertyLinkField(); currProperty; currProperty = currProperty->PropertyLinkNextField())
if ((currProperty->PropertyFlagsField() & 0x080) && (currProperty->PropertyFlagsField() & 0x100))
outParmCount++;
for (int i = 0; currOutParm && (i < outParmCount); ++i)
{
if (currOutParm->PropertyField() && currOutParm->PropertyField()->NameField().ToString().ToString() == "Capture")
{
outputCapture = reinterpret_cast<bool*>(currOutParm->PropAddrField());
break;
}
currOutParm = currOutParm->NextOutParmField();
}
if (!outputCapture) {
Log::GetLog()->error("Capture OutParm not found");
return;
}
*outputCapture = false;
}CanCapture BlueprintPure script function to prevent cryopods from capturing any dino:
c++
// WeapEmptyCryopod_C CanCapture()
// Public, HasOutParms, BlueprintCallable, BlueprintEvent, BlueprintPure
//
// Parameters (0x0009)
// 0x0000 (0x0008) Dino ObjectProperty Parm, ZeroConstructor, IsPlainOldData, NoDestructor
// 0x0008 (0x0001) Capture BoolProperty Parm, OutParm, ZeroConstructor, IsPlainOldData, NoDestructor
DECLARE_HOOK(UObject_ProcessInternal, void, UObject*, FFrame*, void* const);
void Hook_UObject_ProcessInternal(UObject* _this, FFrame* Stack, void* const Result)
{
// If this is not our function, process the script normally and return
if (Stack->NodeField()->NameField().ToString().ToString() != "CanCapture") {
UObject_ProcessInternal_original(_this, Stack, Result);
return;
}
bool* outputCapture = nullptr;
int outParmCount = 0;
FOutParmRec* currOutParm = Stack->OutParmsField();
for (UProperty* currProperty = Stack->NodeField()->PropertyLinkField(); currProperty; currProperty = currProperty->PropertyLinkNextField())
if ((currProperty->PropertyFlagsField() & 0x080) && (currProperty->PropertyFlagsField() & 0x100))
outParmCount++;
for (int i = 0; currOutParm && (i < outParmCount); ++i)
{
if (currOutParm->PropertyField() && currOutParm->PropertyField()->NameField().ToString().ToString() == "Capture")
{
outputCapture = reinterpret_cast<bool*>(currOutParm->PropAddrField());
break;
}
currOutParm = currOutParm->NextOutParmField();
}
if (!outputCapture) {
Log::GetLog()->error("Capture OutParm not found");
return;
}
*outputCapture = false;
} CallFunction().ProcessInternal() is pretty similar to the way people use ProcessEvent() though. Then you can catch any script function whether it came through ProcessEvent() or CallFunction().Func field for native UFunctions, or modifying the bytecode for script UFunctions) instead of hooking ProcessInternal().Func field for native UFunctions, or modifying the bytecode for script UFunctions) instead of hooking ProcessInternal(). ProcessInternal() and I just stuck with that. Plus I've mostly been doing this on Linux where I'm not currently doing any native function hooking since I don't have debug symbols (although ProcessInternal() is easy to find even without debug symbols since script UFunctions point to it in their Func field).ProcessInternal() and I just stuck with that. Plus I've mostly been doing this on Linux where I'm not currently doing any native function hooking since I don't have debug symbols (although ProcessInternal() is easy to find even without debug symbols since script UFunctions point to it in their Func field). ProcessEvent(), which would work well enough on Windows with the .pdb. But I don't have a nice, reliable way yet to detect ProcessEvent() on Linux. I've written my own function to do some stack handling and then I call ProcessInternal(), but it's not as nice as letting UE do the work for me.ProcessEvent(), which would work well enough on Windows with the .pdb. But I don't have a nice, reliable way yet to detect ProcessEvent() on Linux. I've written my own function to do some stack handling and then I call ProcessInternal(), but it's not as nice as letting UE do the work for me. ProcessEvent() with my own code.ProcessEvent() with my own code. ProcessEvent(), which would work well enough on Windows with the .pdb. But I don't have a nice, reliable way yet to detect ProcessEvent() on Linux. I've written my own function to do some stack handling and then I call ProcessInternal(), but it's not as nice as letting UE do the work for me. while(!sdk::UObject::FindClass("Class CoreUObject.Object"))
{
using namespace std::chrono_literals;
std::this_thread::sleep_for(250ms); //Let's let the CPU get work done in the mean time.
printf("Waiting for UObject.\n");
}
spongehax::load();auto spongehax::load() -> void
{
//snip
process_event_.reset(sdk::UObject::StaticClass(), 66);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(process_event_.get(), process_event);
DetourTransactionCommit(); static hookable<void(sdk::UObject*, sdk::UFunction*, void*)> process_event_;Class UFunction has no member InternalIndexField. Did you modify your source somehow?Class UFunction has no member InternalIndexField. Did you modify your source somehow? UObjectBase -> UObjectBaseUtility -> UObject -> UField -> UStruct -> UFunction
UObjectBase is where InternalIndexField is defined. Seems like something goes wrong for Intellisense after UObject, as Intellisense/Autocomplete works for UObject::InternalIndexField but not UField::InternalIndexField.__declspec(dllexport) UProperty* FindProperty(FName name); within UObjectBlueprint'/Game/Genesis2/CoreBlueprints/Environment/DayCycleManager_Gen2.DayCycleManager_Gen2' on Gen 2. I've tried two events and a function. I can get the index of those two events and the function, however I'm not having any luck actually hooking them.
I've used Pelayori's examples of Hook_AActor_ProcessEvent. I've checked that that hook is actually being triggered, which it is, and I am able to get the InternalIndexField, however the indexes I'm after don't ever seem to be returned.
Is there anything I might be missing?void Hook_AActor_ProcessEvent(AActor* _this, UFunction* Function, void* Parameters)
{
if (_this && Function && Function->InternalIndexField() == MyIndex)
{
Log::GetLog()->debug("Hook_AActor_ProcessEvent worked.");
}
AActor_ProcessEvent_original(_this, Function, Parameters);
}Hook_AActor_ProcessEvent, but most of them don't seem to be?CallFunction(), not ProcessEvent(). Even then, you can still access the arguments and variables through the UE VM stack if you define a few additional structures (stuff like UFunction, FFrame, FOutParmRec) that ArkServerAPI doesn't currently fully provide. _this for every call to Hook_AActor_ProcessEvent, filtered them all for Blueprint'/Game/Genesis2/CoreBlueprints/Environment/DayCycleManager_Gen2.DayCycleManager_Gen2', then did Function::GetFullName to find the name of the function and dumped the index and function name to debug. By looking through that I found one BP function that was invoked through ProcessEvent that was what I needed. I guess I was lucky this time, but I'd love it if someone could share how they hook CallFunction as I'm certain I won't always be that lucky. (edited)_this for every call to Hook_AActor_ProcessEvent, filtered them all for Blueprint'/Game/Genesis2/CoreBlueprints/Environment/DayCycleManager_Gen2.DayCycleManager_Gen2', then did Function::GetFullName to find the name of the function and dumped the index and function name to debug. By looking through that I found one BP function that was invoked through ProcessEvent that was what I needed. I guess I was lucky this time, but I'd love it if someone could share how they hook CallFunction as I'm certain I won't always be that lucky. (edited)UObject::ProcessInternal, Mollusk shared an example here: https://discord.com/channels/513432877904691202/513432877904691205/1005964066474430514UObject::ProcessInternal, Mollusk shared an example here: https://discord.com/channels/513432877904691202/513432877904691205/1005964066474430514 DayCycleManager_Gen2's TriggerWarp() function (which is called through UObject::CallFunction()) and modify the index parameter to control the incoming asteroid zone.
// Function TriggerWarp
// BlueprintCallable, BlueprintEvent
//
// Parameters (0x0004)
// 0x0000 (0x0004) index UIntProperty Parm, ZeroConstructor, IsPlainOldData, NoDestructorc++
struct FOutParmRec
{
UProperty*& PropertyField() { return *GetNativePointerField<UProperty**>(this, "FOutParmRec.Property"); }
unsigned __int8*& PropAddrField() { return *GetNativePointerField<unsigned __int8**>(this, "FOutParmRec.PropAddr"); }
FOutParmRec*& NextOutParmField() { return *GetNativePointerField<FOutParmRec**>(this, "FOutParmRec.NextOutParm"); }
};
struct FFrame : FOutputDevice
{
UFunction*& NodeField() { return *GetNativePointerField<UFunction**>(this, "FFrame.Node"); }
UObject*& ObjectField() { return *GetNativePointerField<UObject**>(this, "FFrame.Object"); }
unsigned __int8*& CodeField() { return *GetNativePointerField<unsigned __int8**>(this, "FFrame.Code"); }
unsigned __int8*& LocalsField() { return *GetNativePointerField<unsigned __int8**>(this, "FFrame.Locals"); }
UProperty*& MostRecentPropertyField() { return *GetNativePointerField<UProperty**>(this, "FFrame.MostRecentProperty"); }
unsigned __int8*& MostRecentPropertyAddressField() { return *GetNativePointerField<unsigned __int8**>(this, "FFrame.MostRecentPropertyAddress"); }
FFrame*& PreviousFrameField() { return *GetNativePointerField<FFrame**>(this, "FFrame.PreviousFrame"); }
FOutParmRec*& OutParmsField() { return *GetNativePointerField<FOutParmRec**>(this, "FFrame.OutParms"); }
UField*& PropertyChainForCompiledInField() { return *GetNativePointerField<UField**>(this, "FFrame.PropertyChainForCompiledIn"); }
UFunction*& CurrentNativeFunctionField() { return *GetNativePointerField<UFunction**>(this, "FFrame.CurrentNativeFunction"); }
};UObject::ProcessInternal() and get parameters from the FFrame:
c++
// Find the TriggerWarp UFunction during your plugin's init and save its InternalIndex
int triggerWarpIdx;
DECLARE_HOOK(UObject_ProcessInternal, void, UObject*, FFrame*, void* const);
void Hook_UObject_ProcessInternal(UObject* _this, FFrame* Stack, void* const Result)
{
// The Stack's Node field is the UFunction that this FFrame was constructed for
if (Stack->NodeField()->InternalIndexField() != triggerWarpIdx) {
// Process the function normally and return if this is not the function we're looking for
UObject_ProcessInternal_original(_this, Stack, Result);
return;
}
int* parmIndex = nullptr;
// Get the pointer to the "index" input parameter
for (UProperty* prop = Stack->NodeField()->PropertyLinkField(); prop; prop = prop->PropertyLinkNextField())
{
if (prop->NameField().ToString().Equals("index"))
{
parmIndex = reinterpret_cast<int*>(Stack->LocalsField() + prop->Offset_InternalField());
break;
}
}
// Warp to black pearl asteroids
if (parmIndex)
*parmIndex = 7;
else
Log::GetLog()->error("\"index\" parm not found");
UObject_ProcessInternal_original(_this, Stack, Result);
}c++
struct FOutParmRec
{
UProperty*& PropertyField() { return *GetNativePointerField<UProperty**>(this, "FOutParmRec.Property"); }
unsigned __int8*& PropAddrField() { return *GetNativePointerField<unsigned __int8**>(this, "FOutParmRec.PropAddr"); }
FOutParmRec*& NextOutParmField() { return *GetNativePointerField<FOutParmRec**>(this, "FOutParmRec.NextOutParm"); }
};
struct FFrame : FOutputDevice
{
UFunction*& NodeField() { return *GetNativePointerField<UFunction**>(this, "FFrame.Node"); }
UObject*& ObjectField() { return *GetNativePointerField<UObject**>(this, "FFrame.Object"); }
unsigned __int8*& CodeField() { return *GetNativePointerField<unsigned __int8**>(this, "FFrame.Code"); }
unsigned __int8*& LocalsField() { return *GetNativePointerField<unsigned __int8**>(this, "FFrame.Locals"); }
UProperty*& MostRecentPropertyField() { return *GetNativePointerField<UProperty**>(this, "FFrame.MostRecentProperty"); }
unsigned __int8*& MostRecentPropertyAddressField() { return *GetNativePointerField<unsigned __int8**>(this, "FFrame.MostRecentPropertyAddress"); }
FFrame*& PreviousFrameField() { return *GetNativePointerField<FFrame**>(this, "FFrame.PreviousFrame"); }
FOutParmRec*& OutParmsField() { return *GetNativePointerField<FOutParmRec**>(this, "FFrame.OutParms"); }
UField*& PropertyChainForCompiledInField() { return *GetNativePointerField<UField**>(this, "FFrame.PropertyChainForCompiledIn"); }
UFunction*& CurrentNativeFunctionField() { return *GetNativePointerField<UFunction**>(this, "FFrame.CurrentNativeFunction"); }
}; Error C1047 The object or library file '..\lib\libMinHook.x64.lib' was created by a different version of the compiler than other objects like 'x64\Ark\Core\Private\Ark\ApiUtils.obj'; rebuild all objects and libraries with the same compiler version
I normally have to go and download the libMinHook library, then compile and install it manually. Is there an automated way of doing this?Error C1047 The object or library file '..\lib\libMinHook.x64.lib' was created by a different version of the compiler than other objects like 'x64\Ark\Core\Private\Ark\ApiUtils.obj'; rebuild all objects and libraries with the same compiler version
I normally have to go and download the libMinHook library, then compile and install it manually. Is there an automated way of doing this? msdia140.dllError (active) E0393 pointer to incomplete class type "UObject" is not allowed
Error (active) E0393 pointer to incomplete class type "UProperty" is not allowed
Error (active) E0254 type name is not allowed
Error (active) E0393 pointer to incomplete class type "UObject" is not allowed
Error (active) E0393 pointer to incomplete class type "UProperty" is not allowed
Error (active) E0254 type name is not allowed
Error (active) E0167 argument of type "ADayCycleManager *" is incompatible with parameter of type "UObjectBase *"
Error (active) E0135 class "ADayCycleManager" has no member "FindFunctionChecked"
Error (active) E0135 class "ADayCycleManager" has no member "FindFunctionChecked"
Error (active) E0135 class "ADayCycleManager" has no member "FindFunctionChecked"
Error (active) E0393 pointer to incomplete class type "UFunction" is not allowed
Error (active) E0393 pointer to incomplete class type "UFunction" is not allowed
Error (active) E0393 pointer to incomplete class type "UFunction" is not allowed
Error (active) E0393 pointer to incomplete class type "UFunction" is not allowed
Error (active) E0167 argument of type "AActor *" is incompatible with parameter of type "UObject *"
Error (active) E0167 argument of type "AActor *" is incompatible with parameter of type "UObject *"
Error (active) E0167 argument of type "AActor *" is incompatible with parameter of type "UObject *"
Error (active) E0167 argument of type "AActor *" is incompatible with parameter of type "UObject *"
Error (active) E0167 argument of type "AActor *" is incompatible with parameter of type "UObject *"
Error (active) E0167 argument of type "AActor *" is incompatible with parameter of type "UObjectBase *"
Error (active) E0393 pointer to incomplete class type "UFunction" is not allowed
Error (active) E0167 argument of type "AActor *" is incompatible with parameter of type "UObject *"
Error (active) E0167 argument of type "AActor *" is incompatible with parameter of type "UObject *"
Error (active) E0393 pointer to incomplete class type "UFunction" is not allowed
Error (active) E0393 pointer to incomplete class type "UFunction" is not allowed
Error (active) E0393 pointer to incomplete class type "UProperty" is not allowed
Error (active) E0393 pointer to incomplete class type "UProperty" is not allowed
Error (active) E0393 pointer to incomplete class type "UProperty" is not allowedUFunction::InternalIndexField throwing an intellisense issue, is now fixed! lol
1Error (active) E0135 class "UProperty" has no member "NameField" (edited)AShooterWeapon in AShooterWeapon_OnEquip, or would a change like that not be replicated to the client?AShooterWeapon in AShooterWeapon_OnEquip, or would a change like that not be replicated to the client? AActor::Rename but that isn't triggered when renaming either a structure or a dino.APrimalStructureBed_ProcessEditText, and if it's a storage container you can use APrimalStructureItemContainer_NetUpdateBoxName.DayCycleManager_Gen2's LoadAsteroids or EndWarp BP functions (which also both take an "index" parameter). Different "index" values correspond to the various asteroid configurations.PrimalInventory_DedicatedStorage_C) has a CurrentResourceCount property.
c++
// itemContainer points to a dedicated storage PrimalStructureItemContainer
void ShowDedicatedCount(APrimalStructureItemContainer* itemContainer, AShooterPlayerController* spc)
{
UPrimalInventoryComponent* inventoryComponent = itemContainer->MyInventoryComponentField();
UProperty* count = inventoryComponent->FindProperty(FName("CurrentResourceCount", EFindName::FNAME_Find));
if (!count)
return;
ArkApi::GetApiUtils().SendChatMessage(spc, "", "Count = {}", count->Get<__int32>(inventoryComponent));
}PrimalInventory_DedicatedStorage_C does have a SelectedResourceType that points to the UClass. But ArkServerApi's UProperty* FindProperty(FName name) returns null when you try to find it c++
__declspec(dllexport) UProperty* UObject::FindProperty(FName name)
{
for (UProperty* Property = this->ClassField()->PropertyLinkField(); Property = Property->PropertyLinkNextField();)
if (Property->NameField().Compare(&name) == 0)
return Property;
return nullptr;
}
Should be:
c++
for (UProperty* Property = this->ClassField()->PropertyLinkField(); Property; Property = Property->PropertyLinkNextField())SelectedResourceClass and ResourceCount
UProperty* selectedResourceProp = structure->FindProperty(FName("SelectedResourceClass", EFindName::FNAME_Add));
UClass* itemClass = selectedResourceProp->Get<UClass*>(structure);
UProperty* itemCountProp = structure->FindProperty(FName("ResourceCount", EFindName::FNAME_Add));
int32 availableAmount = itemCountProp->Get<int32>(structure);SelectedResourceClass and ResourceCount
UProperty* selectedResourceProp = structure->FindProperty(FName("SelectedResourceClass", EFindName::FNAME_Add));
UClass* itemClass = selectedResourceProp->Get<UClass*>(structure);
UProperty* itemCountProp = structure->FindProperty(FName("ResourceCount", EFindName::FNAME_Add));
int32 availableAmount = itemCountProp->Get<int32>(structure); ResourceCount is foundSelectedResourceClass. But I think the provided FindProperty() doesn't work becuase of this: https://discord.com/channels/513432877904691202/513432877904691205/1015668142468505630BP_DedicatedStorage_C as well. So you don't even need to get the inventory component @ehiuError (active) E0135 class "UProperty" has no member "NameField"TimedPermissions column.permissions.addtimed <id> <group> <hours> <delay>player_controller->ClientShowSpawnUI(-1);AShooterPlayerController->ClientAddFloatingText_ImplementationAShooterPlayerController->ClientAddFloatingText_Implementation AShooterPlayerController::ClientAddFloatingText_Implementation
Visual Studio doesn't give any errors. No text in ARK and logs/console.
player_controller->ClientAddFloatingText_Implementation(player_controller->DefaultActorLocationField(), &pp, FColorList::Green, 100, 100, 100, FVector(0, 1, 0), 100, 5, 5);AShooterPlayerController* causer = static_cast<AShooterPlayerController*>(AActor->GetInstigatorController()); (edited)
void TestClass::DoCallBack(bool Success, std::string Response)
{ // Do Something }
void TestClass::SubmitRequest(std::string URL, AShooterPlayerController* player)
{ API::Requests::Get().CreateGetRequest("http://www.testurl.com", &TestClass::DoCallBack); }
Fails with this message: no suitable constructor exists to convert from "void (TestClass::*)(bool Success, std::string Response)" to "std::function<void (bool, std::string)>"
This code works:
void DoCallBack(bool Success, std::string Response)
{ // Do Something }
void SubmitRequest(std::string URL, AShooterPlayerController* player)
{ API::Requests::Get().CreateGetRequest("http://www.testurl.com", &DoCallBack); } (edited)void TestClass::DoCallBack(bool Success, std::string Response)
{ // Do Something }
void TestClass::SubmitRequest(std::string URL, AShooterPlayerController* player)
{ API::Requests::Get().CreateGetRequest("http://www.testurl.com", &TestClass::DoCallBack); }
Fails with this message: no suitable constructor exists to convert from "void (TestClass::*)(bool Success, std::string Response)" to "std::function<void (bool, std::string)>"
This code works:
void DoCallBack(bool Success, std::string Response)
{ // Do Something }
void SubmitRequest(std::string URL, AShooterPlayerController* player)
{ API::Requests::Get().CreateGetRequest("http://www.testurl.com", &DoCallBack); } (edited)Class foo
{
void bar(int arg);
} (edited)void bar(foo* this, int arg); (edited)void bar(int arg);CreateGetRequest expects the first two arguments to be bool and string? (edited)API::Requests::Get().CreateGetRequest("http://www.testurl.com", std::bind(&TestClass::DoCallBack, this, std::placeholders::_1, std::placeholders::_2));if (actor != nullptr && actor->IsA(AShooterPlayerController::GetPrivateStaticClass()))
Character:
if (actor != nullptr && actor->IsA(AShooterCharacter::GetPrivateStaticClass()))
How ever sometimes this can fail if the actor is in a different state and so on (edited)if (actor != nullptr && actor->IsA(AShooterPlayerController::GetPrivateStaticClass()))
Character:
if (actor != nullptr && actor->IsA(AShooterCharacter::GetPrivateStaticClass()))
How ever sometimes this can fail if the actor is in a different state and so on (edited)void Hook_AShooterPlayerController_ClientOnCurrentCharacterAndItemsUploaded(AShooterPlayerController* _this, unsigned __int64 TransferringPlayerDataId) but it is so late... player inventory is not valid void Hook_AShooterPlayerController_ClientOnCurrentCharacterAndItemsUploaded(AShooterPlayerController* _this, unsigned __int64 TransferringPlayerDataId) but it is so late... player inventory is not valid DECLARE_HOOK(AShooterPlayerController_ServerUploadCurrentCharacterAndItems_Implementation, void, AShooterPlayerController*, UPrimalInventoryComponent*);
void Hook_AShooterPlayerController_ServerUploadCurrentCharacterAndItems_Implementation(AShooterPlayerController* _this, UPrimalInventoryComponent* inventoryComp)
{
AShooterPlayerController_ServerUploadCurrentCharacterAndItems_Implementation_original(_this, inventoryComp);
}
ArkApi::GetHooks().SetHook("AShooterPlayerController.ServerUploadCurrentCharacterAndItems_Implementation", &Hook_AShooterPlayerController_ServerUploadCurrentCharacterAndItems_Implementation, &AShooterPlayerController_ServerUploadCurrentCharacterAndItems_Implementation_original);
ArkApi::GetHooks().DisableHook("AShooterPlayerController.ServerUploadCurrentCharacterAndItems_Implementation", &Hook_AShooterPlayerController_ServerUploadCurrentCharacterAndItems_Implementation);c++
// void __fastcall UKismetSystemLibrary::K2_SetTimer(UObject *Object, FString FunctionName, float Time, bool bLooping)
DECLARE_HOOK(UKismetSystemLibrary_K2_SetTimer, void, UObject*, FString, float, bool);
void Hook_UKismetSystemLibrary_K2_SetTimer(UObject* Object, FString FunctionName, float Time, bool bLooping)
{
float newTime = Time;
if ((Object->NameField().ToString().ToString() == "Ragnarok_A1_Cave_C_0") && (FunctionName.ToString() == "Cooldown Timer"))
newTime = 600; // 10 minute cooldown
UKismetSystemLibrary_K2_SetTimer_original(Object, FunctionName, newTime, bLooping);
}c++
// void __fastcall UKismetSystemLibrary::K2_SetTimer(UObject *Object, FString FunctionName, float Time, bool bLooping)
DECLARE_HOOK(UKismetSystemLibrary_K2_SetTimer, void, UObject*, FString, float, bool);
void Hook_UKismetSystemLibrary_K2_SetTimer(UObject* Object, FString FunctionName, float Time, bool bLooping)
{
float newTime = Time;
if ((Object->NameField().ToString().ToString() == "Ragnarok_A1_Cave_C_0") && (FunctionName.ToString() == "Cooldown Timer"))
newTime = 600; // 10 minute cooldown
UKismetSystemLibrary_K2_SetTimer_original(Object, FunctionName, newTime, bLooping);
} c++
// void __fastcall UKismetSystemLibrary::K2_SetTimer(UObject *Object, FString FunctionName, float Time, bool bLooping)
DECLARE_HOOK(UKismetSystemLibrary_K2_SetTimer, void, UObject*, FString, float, bool);
void Hook_UKismetSystemLibrary_K2_SetTimer(UObject* Object, FString FunctionName, float Time, bool bLooping)
{
float newTime = Time;
if ((Object->NameField().ToString().ToString() == "Ragnarok_A1_Cave_C_0") && (FunctionName.ToString() == "Cooldown Timer"))
newTime = 600; // 10 minute cooldown
UKismetSystemLibrary_K2_SetTimer_original(Object, FunctionName, newTime, bLooping);
} c++
// void __fastcall UKismetSystemLibrary::K2_SetTimer(UObject *Object, FString FunctionName, float Time, bool bLooping)
DECLARE_HOOK(UKismetSystemLibrary_K2_SetTimer, void, UObject*, FString, float, bool);
void Hook_UKismetSystemLibrary_K2_SetTimer(UObject* Object, FString FunctionName, float Time, bool bLooping)
{
float newTime = Time;
if ((Object->NameField().ToString().ToString() == "Ragnarok_A1_Cave_C_0") && (FunctionName.ToString() == "Cooldown Timer"))
newTime = 600; // 10 minute cooldown
UKismetSystemLibrary_K2_SetTimer_original(Object, FunctionName, newTime, bLooping);
} UVictoryCore::ActorHasLineOfSightAActor** OutBlockingActor (out parameter) will return the actor that is blocking the LOS (edited)UVictoryCore::ActorHasLineOfSight UVictoryCore::ActorHasLineOfSight bool UVictoryCore::ActorHasLineOfSight(
AActor *FromActor,
AActor *ToActor,
AActor **OutBlockingActor,
FVector *ToActorOffset,
ECollisionChannel Channel,
float DebugDrawDuration)bool ActorHasLineOfSight(AActor* FromActor, AActor* ToActor, AActor** OutBlockingActor, FVector* ToActorOffset, ECollisionChannel Channel, float DebugDrawDuration) { return NativeCall<bool, AActor*, AActor*, AActor**, FVector*, ECollisionChannel, float>(nullptr, "UVictoryCore.ActorHasLineOfSight", FromActor, ToActor, OutBlockingActor, ToActorOffset, Channel, DebugDrawDuration); }UVictoryCorebool ActorHasLineOfSight(AActor* FromActor, AActor* ToActor, AActor** OutBlockingActor, FVector* ToActorOffset, ECollisionChannel Channel, float DebugDrawDuration) { return NativeCall<bool, AActor*, AActor*, AActor**, FVector*, ECollisionChannel, float>(nullptr, "UVictoryCore.ActorHasLineOfSight", FromActor, ToActor, OutBlockingActor, ToActorOffset, Channel, DebugDrawDuration); } bool ActorHasLineOfSight(AActor* FromActor, AActor* ToActor, AActor** OutBlockingActor, FVector* ToActorOffset, ECollisionChannel Channel, float DebugDrawDuration) { return NativeCall<bool, AActor*, AActor*, AActor**, FVector*, ECollisionChannel, float>(nullptr, "UVictoryCore.ActorHasLineOfSight", FromActor, ToActor, OutBlockingActor, ToActorOffset, Channel, DebugDrawDuration); } bool boolean = UVictoryCore::ActorHasLineOfSight(DamageCauser, _this, &b, &_this->DefaultActorLocationField(), ECollisionChannel::ECC_GameTraceChannel2, 0);c++
FVector vLoc;
auto player = static_cast<AShooterCharacter*>(player_controller->CharacterField());
player->RootComponentField()->GetWorldLocation(&vLoc); // get location (edited)
plugins.unload NameOfPlugin in ARK consolewhateverplugin.dll.arkapi and put in the plugin folder the api will auto load the new dll for youcheat plugins.unload <pluginname>
cheat plugins.load <pluginname>
By RCON it's only:
plugins.unload <pluginname>
plugins.load <pluginname>plugins.unload EnoPlugin I get this error message: Failed to unload plugin - Plugin enoplugin is not loaded and I cannot overwrite my dll file.
Here is my test code:
c++
#include "EnoPlugin.h"
/**
* -- Header file contains --
* #include "API/Ark/Ark.h"
* #pragma comment(lib, "ArkApi.lib")
**/
namespace Colors
{
const FLinearColor Red = *new FLinearColor(255, 0, 0);
const FLinearColor Green = *new FLinearColor(102, 255, 51);
}
void HandleTestCommand (AShooterPlayerController* player, const FString* arguments, EChatSendMode::Type mode)
{
FString text = L"Command /test executed with arguments \"" + *arguments + "\"";
player->ClientServerChatDirectMessage(&text, Colors::Green, false);
}
void Load()
{
Log::Get().Init("EnoPlugin");
ArkApi::GetCommands().AddChatCommand("/test", &HandleTestCommand);
}
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;
default:
break;
}
return TRUE;
}plugins.unload EnoPlugin I get this error message: Failed to unload plugin - Plugin enoplugin is not loaded and I cannot overwrite my dll file.
Here is my test code:
c++
#include "EnoPlugin.h"
/**
* -- Header file contains --
* #include "API/Ark/Ark.h"
* #pragma comment(lib, "ArkApi.lib")
**/
namespace Colors
{
const FLinearColor Red = *new FLinearColor(255, 0, 0);
const FLinearColor Green = *new FLinearColor(102, 255, 51);
}
void HandleTestCommand (AShooterPlayerController* player, const FString* arguments, EChatSendMode::Type mode)
{
FString text = L"Command /test executed with arguments \"" + *arguments + "\"";
player->ClientServerChatDirectMessage(&text, Colors::Green, false);
}
void Load()
{
Log::Get().Init("EnoPlugin");
ArkApi::GetCommands().AddChatCommand("/test", &HandleTestCommand);
}
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;
default:
break;
}
return TRUE;
} plugins.unload enoplugin I have Failed to unload plugin - Plugin enoplugin is not loadedplugins.unload enoplugin I have Failed to unload plugin - Plugin enoplugin is not loaded __tmainCRTStartup all the way to the crashing function ULinkerLoad::Preload() are all from ShooterGameServer.exe__tmainCRTStartup all the way to the crashing function ULinkerLoad::Preload() are all from ShooterGameServer.exe SET_HOOK and DISABLE_HOOK and make them into proper functions imoc++
FVector vLoc;
auto player = static_cast<AShooterCharacter*>(player_controller->CharacterField());
player->RootComponentField()->GetWorldLocation(&vLoc); // get location (edited)c++
_this->GetInstigatorController()->CharacterField();c++
auto DamagedPlayer = static_cast<AShooterCharacter*>(_this->GetInstigatorController()->CharacterField());
_this->RootComponentField()->GetWorldLocation(&PPosition);GetInstigatorController() eitherstatic_cast<AShooterCharacter*>(_this)c++
auto DamagedPlayer = static_cast<AShooterCharacter*>(_this)->CharacterField());
_this->RootComponentField()->GetWorldLocation(&PPosition); (edited)CharacterField() part_this is a Shooter Character (you check on the if)auto DamagedPlayer = static_cast<AShooterCharacter*>(_this);
_this->RootComponentField()->GetWorldLocation(&PPosition);auto DamagedPlayer = static_cast<AShooterCharacter*>(_this);
_this->RootComponentField()->GetWorldLocation(&PPosition); APrimalStructure (edited)c++
float Hook_APrimalStructure_TakeDamage(APrimalStructure* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this) {
uint64 attacked_tribeid = _this->TargetingTeamField();
FVector DamagedPosition = _this->DefaultActorLocationField();
}
}GetWorldLocation
UPrimalItem::GetRepairingRequirementsString(UPrimalItem *this,FString *result,UPrimalInventoryComponent*compareInventoryComp,bool bUseBaseRequeriments,Float OverrideRepairPercent) When bUseBaseRequirements is false, the result is correct. If it is true, the result is incorrect#include "Requests.h"
Should be used.
Then to call functions
API::Requests::Get().#include "Requests.h"
Should be used.
Then to call functions
API::Requests::Get(). AGameState, AShooterGameMode, AShooterGameState might be useful. ACustomGameState has TArray<struct FSOTFScorePlayerData> PlayerScoreData and TArray<struct FSOTFScoreTribeData> TribeScoreData fields that might help you determine the winner. AGameMode has void AGameMode::EndMatch() that might get triggered when a match ends.
There's also a bunch of BP-generated SotF classes that will likely be more useful. There's no dev kit I'm aware of, so you're probably left with using the reflection system to explore/dump at runtime. The APrimalGameState_TSOTF class is particularly interesting with a bunch of properties and functions including void SetMatchPhase(TEnumAsByte<MatchPhases_TSOTF> NewPhase) and void EndMatch().
Just some potential starting points. I haven't tried it so I don't know if any of this is useful (could all be unused junk leftover from earlier versions of the game for all I know).AGameState, AShooterGameMode, AShooterGameState might be useful. ACustomGameState has TArray<struct FSOTFScorePlayerData> PlayerScoreData and TArray<struct FSOTFScoreTribeData> TribeScoreData fields that might help you determine the winner. AGameMode has void AGameMode::EndMatch() that might get triggered when a match ends.
There's also a bunch of BP-generated SotF classes that will likely be more useful. There's no dev kit I'm aware of, so you're probably left with using the reflection system to explore/dump at runtime. The APrimalGameState_TSOTF class is particularly interesting with a bunch of properties and functions including void SetMatchPhase(TEnumAsByte<MatchPhases_TSOTF> NewPhase) and void EndMatch().
Just some potential starting points. I haven't tried it so I don't know if any of this is useful (could all be unused junk leftover from earlier versions of the game for all I know). 
AGameState, AShooterGameMode, AShooterGameState might be useful. ACustomGameState has TArray<struct FSOTFScorePlayerData> PlayerScoreData and TArray<struct FSOTFScoreTribeData> TribeScoreData fields that might help you determine the winner. AGameMode has void AGameMode::EndMatch() that might get triggered when a match ends.
There's also a bunch of BP-generated SotF classes that will likely be more useful. There's no dev kit I'm aware of, so you're probably left with using the reflection system to explore/dump at runtime. The APrimalGameState_TSOTF class is particularly interesting with a bunch of properties and functions including void SetMatchPhase(TEnumAsByte<MatchPhases_TSOTF> NewPhase) and void EndMatch().
Just some potential starting points. I haven't tried it so I don't know if any of this is useful (could all be unused junk leftover from earlier versions of the game for all I know). UPropertys and UFunctions. Here's a super-ugly, not fully complete/correct example plugin you can use with Ark or SotF to dump classes, enums, and structs from the reflection system. It creates a Dump\ directory under ShooterGame\Binaries\Win64\ and populates it with subdirectories named after packages. Each package directory has a .txt file for each class in the package and an Enums.txt and a Structs.txt if the package has enums or structs. There are A LOT of files, the Engine and ShooterGame packages should look familiar after working with ArkServerApi.ArkApi::GetApiUtils().SendNotification(player_controller, { 0,255,0,0 }, 1.6f, 15, nullptr, *FString(L"яблоко"));ArkApi::GetApiUtils().SendNotification(player_controller, { 0,255,0,0 }, 1.6f, 15, nullptr, *FString(L"яблоко")); 
struct Langs {
std::string SteamID;
std::string Culture;
};
TArray<Langs> languagepaths;
for (Langs l : languagepaths) {
if (l.SteamID == std::to_string(steamid)) {
languagepaths.Remove(l); // Error
}
} (edited)c++
struct Langs {
std::string SteamID;
std::string Culture;
};
TArray<Langs*> languagepaths;
for (Langs* l : languagepaths)
if (l.SteamID == std::to_string(steamid))
languagepaths.Remove(l); // Error
See if this works (edited)c++
struct Langs {
std::string SteamID;
std::string Culture;
};
TArray<Langs*> languagepaths;
for (Langs* l : languagepaths)
if (l.SteamID == std::to_string(steamid))
languagepaths.Remove(l); // Error
See if this works (edited)
struct myStruct {
std::string MyString;
int MyInt;
uint64 MyInt64;
}
TArray<myStruct> myArrayList;
So looping through is easier sometimes
//add data
myStruct = ms;
ms.MyString = somestring;
ms.MyInt = someint;
ms.MyInt64 = someotherint;
myArrayList.Add(ms);
// Loop through
for(auto entry : myArrayList) {
Log::GetLog()->info("MyString: {}", entry.MyString)
// and so on...
}
// Empty the Array of all entries.
myArrayList.Empty();
// Remove just one of match
for(auto entry : myArrayList) {
Log::GetLog()->info("MyString: {}", entry.MyString)
if(entry.MyString == someotherstring) {
myArrayList.RemoveAt(entry.MyString);
}
}
Or you can find the index and then delete it...
auto index = myArrayList.IndexOfByPredicate([somestring](myStruct ms) {
return ms.MyString == somestring;
});
myArrayList.RemoveAt(index);
Hope that helps... might ofc need to adjust the examples for your fitting and code logic ! struct myStruct {
std::string MyString;
int MyInt;
uint64 MyInt64;
}
TArray<myStruct> myArrayList;
So looping through is easier sometimes
//add data
myStruct = ms;
ms.MyString = somestring;
ms.MyInt = someint;
ms.MyInt64 = someotherint;
myArrayList.Add(ms);
// Loop through
for(auto entry : myArrayList) {
Log::GetLog()->info("MyString: {}", entry.MyString)
// and so on...
}
// Empty the Array of all entries.
myArrayList.Empty();
// Remove just one of match
for(auto entry : myArrayList) {
Log::GetLog()->info("MyString: {}", entry.MyString)
if(entry.MyString == someotherstring) {
myArrayList.RemoveAt(entry.MyString);
}
}
Or you can find the index and then delete it...
auto index = myArrayList.IndexOfByPredicate([somestring](myStruct ms) {
return ms.MyString == somestring;
});
myArrayList.RemoveAt(index);
Hope that helps... might ofc need to adjust the examples for your fitting and code logic ! 
struct myStruct {
std::string MyString;
int MyInt;
uint64 MyInt64;
}
TArray<myStruct> myArrayList;
So looping through is easier sometimes
//add data
myStruct = ms;
ms.MyString = somestring;
ms.MyInt = someint;
ms.MyInt64 = someotherint;
myArrayList.Add(ms);
// Loop through
for(auto entry : myArrayList) {
Log::GetLog()->info("MyString: {}", entry.MyString)
// and so on...
}
// Empty the Array of all entries.
myArrayList.Empty();
// Remove just one of match
for(auto entry : myArrayList) {
Log::GetLog()->info("MyString: {}", entry.MyString)
if(entry.MyString == someotherstring) {
myArrayList.RemoveAt(entry.MyString);
}
}
Or you can find the index and then delete it...
auto index = myArrayList.IndexOfByPredicate([somestring](myStruct ms) {
return ms.MyString == somestring;
});
myArrayList.RemoveAt(index);
Hope that helps... might ofc need to adjust the examples for your fitting and code logic ! 
rconpacket* netrecvpacket(int socket)
{
int packetsize;
rconpacket packet = { 0, 0, 0, {0x00} };
int tempdata = recv(socket, (char*)&packetsize, sizeof(int), 0);
if (tempdata == 0)
{
printf("connection lost\n");
connect_alive = 0;
return nullptr;
}
if (tempdata != sizeof(int))
{
printf("Receive failed. invalid packet size(%d)\n", tempdata);
connect_alive = 0;
return nullptr;
}
if (packetsize < 10 || packetsize > 4096)
{
printf("Warning: Invalid packet size (%d). Must be greater than 10 and less than %d.\n", packetsize, 4096);
if (packetsize > 4096 || packetsize < 0)
packetsize = 4096;
net_clean_incoming(socket, packetsize);
return nullptr;
}
packet.size = packetsize;
int received = 0;
while (received < packetsize)
{
tempdata = recv(socket, (char*)&packet + sizeof(int) + received, packetsize - received, 0);
if (tempdata == 0)
{
printf("connection lost\n");
connect_alive = 0;
return nullptr;
}
received += tempdata;
}
rconpacket* ret = &packet;
return ret;
}
This is the function is hang on int tempdata = recv(socket, (char*)&packetsize, sizeof(int), 0); but only inside the plugin, i've put a timeout on the socket and it return, but with no data.select is a better approach for listening on a socket some rcon commands. (edited) int tempdata;
struct addrinfo info {};
struct addrinfo* server_info, * sinfo;
memset(&info, 0, sizeof info);
info.ai_family = 2;
info.ai_socktype = SOCK_STREAM;
info.ai_protocol = IPPROTO_TCP;
WSA();
int ret = getaddrinfo(hostname, hostport, &info, &server_info);
if (ret != 0)
{
printf("Name resolution failed. Erro:%d: %s", ret, gai_strerror(ret));
exit(1);
}
for (sinfo = server_info; sinfo != nullptr; sinfo = sinfo->ai_next)
{
tempdata = socket(sinfo->ai_family, sinfo->ai_socktype, sinfo->ai_protocol);
if (tempdata == -1)
{
continue;
}
timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 1600;
if (setsockopt(tempdata, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&tv), sizeof(timeval)))
ret = connect(tempdata, sinfo->ai_addr, sinfo->ai_addrlen);
if (ret == -1)
{
net_close(tempdata);
continue;
}
break;
}
if (sinfo == nullptr)
{
printf("Connection failed\n");
freeaddrinfo(server_info);
exit(1);
}
freeaddrinfo(server_info);
return tempdata; this is the code to connectOnCommand_Server event that gets called on the server with the command string as an argument when the mod detects a command on the client. Instead of implementing the "Handling commands on the server" section in the mod, you could hook UObject::ProcessEvent() in a plugin to intercept that event and implement your command handling in C++.OnCommand_Server event that gets called on the server with the command string as an argument when the mod detects a command on the client. Instead of implementing the "Handling commands on the server" section in the mod, you could hook UObject::ProcessEvent() in a plugin to intercept that event and implement your command handling in C++. OnCommand_Server is completely empty. So you might still have to put something there, even if it never actually gets run. Or do something like Pelayori suggested.OnCommand_Server is completely empty. So you might still have to put something there, even if it never actually gets run. Or do something like Pelayori suggested. struct ServerInformation
{
FString EnRules;
};
void Information() {
ServerInformation serverInfo;
serverInfo.EnRules = FString(Data::config["Information"]["Rules"]);
}struct ServerInformation
{
FString EnRules;
};
void Information() {
ServerInformation serverInfo;
serverInfo.EnRules = FString(Data::config["Information"]["Rules"]);
} 
void Hook_UObject_ProcessEvent(UObject* _this, UFunction* Function, void* Parms), then _this is the object the function is being called on. Which is a APlayerController for Client Send Net Exec Command to Server.void Hook_UObject_ProcessEvent(UObject* _this, UFunction* Function, void* Parms), then _this is the object the function is being called on. Which is a APlayerController for Client Send Net Exec Command to Server. Client Send Net Exec Command to Server runs on the server. It calls ServerProcessNetExecCommand, which does run on the server. I would think you'd just want to hook APlayerController::ServerProcessNetExecCommand_Implementation() natively instead of dealing with ProcessEventClient Send Net Exec Command to Server runs on the server. It calls ServerProcessNetExecCommand, which does run on the server. I would think you'd just want to hook APlayerController::ServerProcessNetExecCommand_Implementation() natively instead of dealing with ProcessEvent Client Send Net Exec Command To ServerBPServerHandleNetExecCommandDECLARE_HOOK(AActor_BPServerHandleNetExecCommand, bool, AActor*, APlayerController*, FName, FBPNetExecParams*);
bool Hook_AActor_BPServerHandleNetExecCommand(AActor* _this, APlayerController* FromPC, FName CommandName, FBPNetExecParams* Params)
{
if (_this
&& CommandName.ToString().Contains("MyCustomFunction"))
{
// do stuff
return true;
}
return AActor_BPServerHandleNetExecCommand_original(_this, FromPC, CommandName, Params);
} (edited)Client Send Net Exec Command To ServerBPServerHandleNetExecCommandDECLARE_HOOK(AActor_BPServerHandleNetExecCommand, bool, AActor*, APlayerController*, FName, FBPNetExecParams*);
bool Hook_AActor_BPServerHandleNetExecCommand(AActor* _this, APlayerController* FromPC, FName CommandName, FBPNetExecParams* Params)
{
if (_this
&& CommandName.ToString().Contains("MyCustomFunction"))
{
// do stuff
return true;
}
return AActor_BPServerHandleNetExecCommand_original(_this, FromPC, CommandName, Params);
} (edited)struct FBPNetExecParams
{
int IntParam1;
int IntParam2;
int IntParam3;
float FloatParam1;
float FloatParam2;
float FloatParam3;
UObject* ObjParam1;
UObject* ObjParam2;
UObject* ObjParam3;
FString StringParam1;
};struct FBPNetExecParams
{
int IntParam1;
int IntParam2;
int IntParam3;
float FloatParam1;
float FloatParam2;
float FloatParam3;
UObject* ObjParam1;
UObject* ObjParam2;
UObject* ObjParam3;
FString StringParam1;
}; c++
auto str_data = db_.query(fmt::format("SELECT jsonField FROM {} WHERE SteamId = {};", my_table_, steam_id)).get_value<std::string>();
auto jsonParsed = nlohmann::json::parse(str_data); (edited)c++
auto str_data = db_.query(fmt::format("SELECT jsonField FROM {} WHERE SteamId = {};", my_table_, steam_id)).get_value<std::string>();
auto jsonParsed = nlohmann::json::parse(str_data); (edited)c++
auto str_data = db_.query(fmt::format("SELECT jsonField FROM {} WHERE SteamId = {};", my_table_, steam_id)).get_value<std::string>();
auto jsonParsed = nlohmann::json::parse(str_data); (edited)struct FBPNetExecParams
{
int IntParam1;
int IntParam2;
int IntParam3;
float FloatParam1;
float FloatParam2;
float FloatParam3;
UObject* ObjParam1;
UObject* ObjParam2;
UObject* ObjParam3;
FString StringParam1;
}; nlohmann::json j;
db_.query("SELECT ... FROM ...").each(
[&](rowType first, rowType2 second...)
{
nlohmann::json object;
object["param"] = first;
object["param2"] = second;
...
j.push_back(object);
return true;
}
); (edited)rowType must be replaced by each column's data type, and add as many arguments as the select query will return (edited)BPServerHandleNetExecCommand (edited)bool b = db_.query(fmt::format("SELECT SteamId FROM {} LIMIT 20;", table_players3_)).each(
[](uint64 steamid, std::string nickname, int kills, int deaths)
{
std::cout << std::to_string(steamid);
return true;
});nickname, kills, deaths params, or make it select everythingtry and add catchnickname, kills, deaths params, or make it select everything nlohmann::json j;
bool b = db_.query(fmt::format("SELECT SteamId FROM {} LIMIT 20;", table_players3_)).each([&](uint64 steamid, std::string nickname, int kills, int deaths)
{
nlohmann::json object;
object["SteamId"] = steamid;
object["Nickname"] = nickname;
object["Kills"] = kills;
object["Deaths"] = deaths;
j.push_back(object);
return true;
});
return j.dump(); (edited) nlohmann::json j;
bool b = db_.query(fmt::format("SELECT SteamId FROM {} LIMIT 20;", table_players3_)).each([&](uint64 steamid, std::string nickname, int kills, int deaths)
{
nlohmann::json object;
object["SteamId"] = steamid;
object["Nickname"] = nickname;
object["Kills"] = kills;
object["Deaths"] = deaths;
j.push_back(object);
return true;
});
return j.dump(); (edited).c_str() to the string value you read from the database then put it into an FString..c_str() to the string value you read from the database then put it into an FString. player["Name"] = FString(result.get_value<std::string>(1).c_str());player["Name"] = FString(result.get_value<std::string>(1).c_str()); UProperty::Get() and UProperty::Set() in ArkServerApi. My primary motivation is to fix this snippet:
c++
T Get(UObject* object)
{
if (!object->StaticClass()->HasProperty(this))
throw std::invalid_argument("Object does not contain this property.");
...
object->StaticClass() calls the static UObject::StaticClass(), which returns the UClass for UObject, not the UClass of object. You'd think HasProperty() would return false when called with a UProperty not in the UObject UClass, but it turns out UClass::HasProperty() was flawed before UE4.22 and basically always returns true.
I'd also like some input from the dev team or other users on whether or not I should enhance these functions to handle bools more nicely. In a UClass, UBoolProperty values are packed into a bitfield. You might expect to be able to use uBoolProperty->Get<bool>(object) or uBoolProperty->Set(object, true) to get or set a single bool property, but you would potentially be getting/overwriting an entire byte's worth of bools. You'd have to mask out other bits to get the value you care about after a Get(). Or do a Get(), then modify, then Set() to properly set/unset the value you care about. I could add code to the Get() and Set() functions to do this when called on a UBoolProperty. It would be a change in behavior, but I think it may be a welcome one.UProperty::Get() and UProperty::Set() in ArkServerApi. My primary motivation is to fix this snippet:
c++
T Get(UObject* object)
{
if (!object->StaticClass()->HasProperty(this))
throw std::invalid_argument("Object does not contain this property.");
...
object->StaticClass() calls the static UObject::StaticClass(), which returns the UClass for UObject, not the UClass of object. You'd think HasProperty() would return false when called with a UProperty not in the UObject UClass, but it turns out UClass::HasProperty() was flawed before UE4.22 and basically always returns true.
I'd also like some input from the dev team or other users on whether or not I should enhance these functions to handle bools more nicely. In a UClass, UBoolProperty values are packed into a bitfield. You might expect to be able to use uBoolProperty->Get<bool>(object) or uBoolProperty->Set(object, true) to get or set a single bool property, but you would potentially be getting/overwriting an entire byte's worth of bools. You'd have to mask out other bits to get the value you care about after a Get(). Or do a Get(), then modify, then Set() to properly set/unset the value you care about. I could add code to the Get() and Set() functions to do this when called on a UBoolProperty. It would be a change in behavior, but I think it may be a welcome one. c++
struct UProperty : UField
{
template<typename T>
T Get(UObject* object);
template<typename T>
void Set(UObject* object, T value);
...
};
template<typename T>
T UProperty::Get(UObject* object)
{
if (ClassField()->ClassCastFlagsField() & static_cast<uint64>(ClassCastFlags::CASTCLASS_UBoolProperty))
throw std::invalid_argument("Non-bool type expected from UBoolProperty.");
...
}
template<>
bool UProperty::Get(UObject* object)
{
if (!(ClassField()->ClassCastFlagsField() & static_cast<uint64>(ClassCastFlags::CASTCLASS_UBoolProperty)))
throw std::invalid_argument("Bool type expected from non-UBoolProperty.");
...
} (edited)c++
UBoolProperty* boolProperty = static_cast<UBoolProperty*>(this);
uint8* bytePtr = reinterpret_cast<uint8*>(object) + boolProperty->Offset_InternalField() + boolProperty->ByteOffsetField();
return !!(*bytePtr & boolProperty->FieldMaskField());
And for Set():
c++
UBoolProperty* boolProperty = static_cast<UBoolProperty*>(this);
uint8* bytePtr = reinterpret_cast<uint8*>(object) + boolProperty->Offset_InternalField() + boolProperty->ByteOffsetField();
uint8 newByte = (*bytePtr & ~boolProperty->FieldMaskField()) | (value ? boolProperty->ByteMaskField() : 0);
*(reinterpret_cast<uint8*>(object) + Offset_InternalField()) = newByte; (edited)ArkServerApi links don't work you have to use the proper GameServersHub url. You can locate the plugin by using the resource search function on the site.AShooterPlayerController::ServerSendChatMessage_ImplementationAShooterPlayerController::ServerSendChatMessage_Implementation #pragma comment(lib, "Permissions.lib")
Then use it like this
Permissions::IsPlayerInGroup(steam_id, "Admins") (edited)View Players button in the Steam in-game overlay? Here's an example:View Players button in the Steam in-game overlay? Here's an example: ListPlayers RCON command, which returns SteamIDs (and IDs for Epic players). Or if you write a server plugin, ArkServerApi has utilities for getting SteamIDs. (edited)
1AActor* Hook_UWorld_SpawnActor(UWorld* _this, UClass* Class, FVector* Location, FRotator* Rotation, FActorSpawnParameters* SpawnParameters)
{
AActor* SpawnedActor = UWorld_SpawnActor_original(_this, Class, Location, Rotation, SpawnParameters);
FString HumanReadableName;
SpawnedActor->GetHumanReadableName(&HumanReadableName);
if (SpawnedActor != nullptr && HumanReadableName.Equals("SupplyCrate_Cave_QualityTier1_C")) {
Log::GetLog()->info("{} Spawned at X:{} Y:{}", SpawnedActor->GetHumanReadableName(&HumanReadableName)->ToString(), ArkApi::GetApiUtils().FVectorToCoords(*Location).x, ArkApi::GetApiUtils().FVectorToCoords(*Location).y);
return UWorld_SpawnActor_original(_this, Class, Location, Rotation, SpawnParameters);
}
return UWorld_SpawnActor_original(_this, Class, Location, Rotation, SpawnParameters);
}Class already why do you need something else?FString GetBlueprintFromClass(UClass* object)
{
if (object != nullptr)
{
FString path_name;
object->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("");
} (edited)FString GetBlueprintFromClass(UClass* object)
{
if (object != nullptr)
{
FString path_name;
object->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("");
} (edited)ListPlayers RCON command, which returns SteamIDs (and IDs for Epic players). Or if you write a server plugin, ArkServerApi has utilities for getting SteamIDs. (edited)DECLARE_HOOK(Foo, ...) you'll have Foo_original(...) and Hook_Foo(..)DECLARE_HOOK(AShooterPlayerState_PromoteToTribeAdmin, void, AShooterPlayerState*, APlayerController*);
dont works for meDECLARE_HOOK(AShooterPlayerState_ServerRequestPromotePlayerInMyTribe_Implementation, void, AShooterPlayerState*, int);DECLARE_HOOK(AShooterPlayerController_EnableCheats, void, AShooterPlayerController*, FString);
dont works for me.
Also
DECLARE_HOOK(AShooterPlayerController_CheckCheatsPassword_Implementation, void, AShooterPlayerController*, FString*);
works but it runs every time than player do "enablecheats" even password is correct or no (edited)DECLARE_HOOK(AShooterPlayerController_ConsoleCommand, FString*, AShooterPlayerController*, FString*, FString*, bool);
FString* Hook_AShooterPlayerController_ConsoleCommand(AShooterPlayerController* _this, FString* result, FString* Command, bool bWriteToLog)
{
return AShooterPlayerController_ConsoleCommand_original(_this, result, Command, bWriteToLog);
}
ArkApi::GetHooks().SetHook("AShooterPlayerController.ConsoleCommand", &Hook_AShooterPlayerController_ConsoleCommand, &AShooterPlayerController_ConsoleCommand_original);
ArkApi::GetHooks().DisableHook("AShooterPlayerController.ConsoleCommand", &Hook_AShooterPlayerController_ConsoleCommand);DECLARE_HOOK(AShooterPlayerController_ConsoleCommand, FString*, AShooterPlayerController*, FString*, FString*, bool);
FString* Hook_AShooterPlayerController_ConsoleCommand(AShooterPlayerController* _this, FString* result, FString* Command, bool bWriteToLog)
{
return AShooterPlayerController_ConsoleCommand_original(_this, result, Command, bWriteToLog);
}
ArkApi::GetHooks().SetHook("AShooterPlayerController.ConsoleCommand", &Hook_AShooterPlayerController_ConsoleCommand, &AShooterPlayerController_ConsoleCommand_original);
ArkApi::GetHooks().DisableHook("AShooterPlayerController.ConsoleCommand", &Hook_AShooterPlayerController_ConsoleCommand); FString path = "Blueprint'/Game/Extinction/CoreBlueprints/Weapons/PrimalItem_WeaponEmptyCryopod.PrimalItem_WeaponEmptyCryopod'";
UClass* cryoClass = UVictoryCore::BPLoadClass(&path);
if (!cryoClass) {
Log::GetLog()->critical("No cryopod class found!");
return;
}
UFunction* function = cryoClass->FindFunctionByName(FName("CanDeploy", EFindName::FNAME_Find), EIncludeSuperFlag::ExcludeSuper);
if (!function) {
Log::GetLog()->critical("No function 'CanDeploy' found!");
return;
}
FunctionIndex = function->InternalIndexField();
void Hook_UObject_ProcessInternal(UObject* _this, FFrame* Stack, void* const Result)
{
if (Stack->NodeField()->InternalIndexField() != FunctionIndex) {
UObject_ProcessInternal_original(_this, Stack, Result);
return;
}
//Do stuff
return;
} (edited)_this to an UPrimalItem*, which would give you the cryopod item. Then from the item you get the owner inventory, and from the owner inventory you can get the pawn owner.
_this is always the object calling the function, so if you know the type you can cast to it to access it's data.
#if defined(__clang__ ) /* Clang does not support B(A)(C...) syntax, only A B(C...) and refuses to compile otherwise. */
#define FUNCTION_SIGNATURE(x,y,z) x y (z)
#define FUNCTION_SIGNATURE_VA(x,y,z) x y (z, ...)
#elif defined(__GNUC__) || defined(_MSC_VER) || defined(__INTEL_COMPILER) /* GCC Supports A B(C...) and B(A)(C...) but produces wrong T* for T under A B(C...) */
#define FUNCTION_SIGNATURE(x,y,z) y(x)(z)
#define FUNCTION_SIGNATURE_VA(x,y,z) y(x)(z,...)
#endif (edited)
LICENSE file in it's distribution, and if any changes are made to any OpenSSL code then every change must be listed and included in the distribution.
UObjectMap*UObjectMap&void main()
{
moar::function_ptr<int(int, int)> my_ptr(0xdeadbeef);
int result = my_ptr(2, 3); //result is 5.
return 0;
}
static inline auto from_virtual(void* object, int vfti) -> void* { return (*reinterpret_cast<void***>(object))[vfti]; } class function_ptr<RT(A...), T2, T3> : public extern_ptr<typename signature<RT(A...), typename type_traits::SelectCallingConvention<T2,T3>::type, typename type_traits::SelectVariadic<T2, T3>::type>::type> /* typename not declared yet. */ template<concepts::Function T1, concepts::CommonType T2 = types::default_calling_convention, concepts::CommonType T3 = typename type_traits::SelectDefaultT3<T2>::type>
class function_ptr {};
template<typename T>
struct SelectDefaultT3 {
static_assert(sizeof(T) == 0, "Incorrect Usage of SelectDefaultT3 (T missing.)");
using type = void;
};
template<concepts::Variadic T>
struct SelectDefaultT3<T> { using type = types::default_calling_convention; };
template<concepts::CallingConvention T>
struct SelectDefaultT3<T> { using type = types::default_variadic; };__int64 __fastcall APrimalDinoCharacter::IsBossDino(APrimalDinoCharacter *this)
{
return *((_WORD *)this + 3901) & 1;
}
Thank you IDA, very coolthis + 3901 so something at offset 3901__int64 __fastcall APrimalDinoCharacter::IsBossDino(APrimalDinoCharacter *this)
is actually
class APrimalDinoCharacter
{
uint64_t IsBossDino();
};if ( v0 )v0 is the instance of the object (assuming here), and 12 is the offset in the virtual function table static inline auto from_virtual(void* object, int vfti) -> void* { return (*reinterpret_cast<void***>(object))[vfti]; }__int64 __fastcall APrimalDinoCharacter::IsBossDino(APrimalDinoCharacter *this)
is actually
class APrimalDinoCharacter
{
uint64_t IsBossDino();
}; inline is a hint to the compiler that it may optimize a function by "inlining" it into the caller in assembly instead of actually calling it (although the compiler may choose not to). The cool thing about inline in C++ is that it lets you have more than one definition of functions (and variables since C++17) as long as the definitions are all the same. So you can have inline functions defined in a header file and include them in multiple source files without breaking the one definition rule and they'll all have the same address.
https://en.cppreference.com/w/cpp/language/inline
https://en.cppreference.com/w/cpp/language/definition (edited)MessageBox function:
(C++)
int MessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
Create a C# DLL that will contain the hook function. The DLL should have a public static function with the same signature as the function you want to hook:
(C#)
using System;
using System.Runtime.InteropServices;
namespace HookTest
{
public static class HookFunctions
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
public static int HookedMessageBox(IntPtr hWnd, string text, string caption, uint type)
{
// Implement your custom code here
return MessageBox(hWnd, "Hooked: " + text, caption, type);
}
}
}
Load the C# DLL into the address space of the C++ executable using DLL injection. There are different ways to do this, but one common approach is to use the LoadLibrary function to load the DLL and the GetProcAddress function to get a pointer to the hook function.
(C++)
HMODULE hHookDll = LoadLibrary(TEXT("HookTest.dll"));
if (hHookDll == NULL)
{
// handle error
}
HOOKPROC pHookFunc = (HOOKPROC)GetProcAddress(hHookDll, "HookedMessageBox");
if (pHookFunc == NULL)
{
// handle error
}DetourTransactionBegin, DetourUpdateThread, and DetourAttach functions from the Microsoft Detours library:
(C++)
typedef int(WINAPI *PMSGBOXA)(HWND, LPCSTR, LPCSTR, UINT);
PMSGBOXA pMessageBoxA = &MessageBoxA;
LONG AttachHook()
{
LONG result = DetourTransactionBegin();
if (result != NO_ERROR)
{
return result;
}
result = DetourUpdateThread(GetCurrentThread());
if (result != NO_ERROR)
{
return result;
}
result = DetourAttach(&(LPVOID&)pMessageBoxA, (PMSGBOXA) pHookFunc);
if (result != NO_ERROR)
{
return result;
}
result = DetourTransactionCommit();
if (result != NO_ERROR)
{
return result;
}
return NO_ERROR;
}
LONG DetachHook()
{
LONG result = DetourTransactionBegin();
if (result != NO_ERROR)
{
return result;
}
result = DetourUpdateThread(GetCurrentThread());
if (result != NO_ERROR)
{
return result;
}
result = DetourDetach(&(LPVOID&)pMessageBoxA, (PMSGBOXA)pHookFunc);
if (result != NO_ERROR)
{
return result;
}
result = DetourTransactionCommit();
if (result != NO_ERROR)
{
return result;
}
return NO_ERROR;
}
Finally, call the function you want to hook, and the hook function should be called instead.AShooterPlayerController_ServerRequestDownloadPlayerCharacter_Implementation but it is broken if you pass. Even if it is empty. (edited)DECLARE_HOOK(AShooterPlayerController_ServerRequestDownloadPlayerCharacter_Implementation, void, AShooterPlayerController*, FArkTributePlayerData, int, int);
void Hook_AShooterPlayerController_ServerRequestDownloadPlayerCharacter_Implementation(AShooterPlayerController* _this, FArkTributePlayerData DownloadedCharacter, int spawnPointID, int spawnRegionIndex)
{
std::cout << "SRDPC_I \n";
AShooterPlayerController_ServerRequestDownloadPlayerCharacter_Implementation_original(_this, DownloadedCharacter, spawnPointID, spawnRegionIndex);
} (edited)FArkTributePlayerData to FArkTributePlayerData*int __cdecl _callback___native_event__2U__StringLiteral__0BF__moar__3D0FF__0EP__0GC__0GK__0GF__0GD__0HE__0CO__0FA__0HC__0GP__0GD__0GF__0HD__0HD__0EF__0HG__0GF__0GO__0HE__0A______A6AHPAX0_ZUcdecl_t_types_2_X_moar__SAHPAX0_Z(
void *<args_0>,
void *<args_1>)
COMMANDS.AddChatCommand(L"/to135", to135Command);
COMMANDS.AddChatCommand(L"/to140", to140Command);
COMMANDS.AddChatCommand(L"/to155", to155Command);
COMMANDS.AddChatCommand(L"/evolve", evolveCommand);
COMMANDS.AddChatCommand(L"/defeatboss", defeatBossCommand);void SetChibi(AShooterPlayerController* playerController, int value)
{
AShooterCharacter* myPawn = static_cast<AShooterCharacter*>(playerController->PawnField());
if (!myPawn) return;
UPrimalPlayerData* data = myPawn->GetPlayerData();
if (!data) return;
UProperty* prop = data->FindProperty(FName(L"NumChibiLevelUpsData", EFindName::FNAME_Find, false));
if (!prop) return;
prop->Set<int>(data, value);
data->SavePlayerData(ArkApi::GetApiUtils().GetWorld());
ArkApi::GetApiUtils().SendChatMessage(playerController, FString("Server Message"), "You now have {0} bonus levels from Chibis.", value);
} (edited)void DefeatBoss(std::wstring boss, int difficulty, AShooterPlayerController* playerController)
{
auto player = (static_cast<AShooterCharacter*>(playerController->PawnField()));
UPrimalPlayerData* data = (static_cast<AShooterCharacter*>(playerController->PawnField()))->GetPlayerData();
ExecBP(data, L"DefeatedBoss", nullptr, difficulty, FName(boss.c_str(), EFindName::FNAME_Add, false), playerController);
AShooterPlayerState* state = playerController->GetShooterPlayerState();
UClass* theClass = UVictoryCore::BPLoadClass(&BossNameToBP(boss, difficulty));
if (!state || !theClass)
return;
auto BossDino = static_cast<APrimalDinoCharacter*>(theClass->GetDefaultObject(true));
if (!BossDino)
return;
for (auto gram : BossDino->DeathGiveEngramClassesField())
state->ServerUnlockEngram(gram, true, true);
std::string bossLevel = "";
switch (difficulty)
{
case 0:
bossLevel = "Gamma";
break;
case 1:
bossLevel = "Beta";
break;
case 2:
bossLevel = "Alpha";
break;
}
ArkApi::GetApiUtils().SendChatMessage(playerController, FString("Server Message"), "Defeated boss {0} {1}.", bossLevel, ArkApi::Tools::ConvertToAnsiStr(boss));
}
(You should cache the boss classes)void giveRagnarokTekgrams(AShooterPlayerController* playerController)
{
const wchar_t* tekGrams[] = {
L"Blueprint'/Game/PrimalEarth/CoreBlueprints/Items/Structures/Misc/PrimalItemStructure_TekLight.PrimalItemStructure_TekLight'",
L"Blueprint'/Game/PrimalEarth/CoreBlueprints/Weapons/PrimalItem_WeaponTekSword.PrimalItem_WeaponTekSword'",
L"Blueprint'/Game/PrimalEarth/CoreBlueprints/Items/Armor/Shields/PrimalItemArmor_ShieldTek.PrimalItemArmor_ShieldTek'"
};
AShooterPlayerState* state = playerController->GetShooterPlayerState();
for (const wchar_t* gram : tekGrams)
{
TSubclassOf<UPrimalItem> tekGram;
tekGram.uClass = UVictoryCore::BPLoadClass(&FString(gram));
state->ServerUnlockEngram(tekGram, true, true);
}
}FString steamid;
static_cast<FUniqueNetIdSteam*>(UniqueId->Get())->ToString(&steamid);
std::cout << steamid.ToString() + "\n";UniqueNetId fieldstruct FUniqueNetIdSteam : FUniqueNetId
{
unsigned __int64 UniqueNetId;
// Functions
int GetSize() { return NativeCall<int>(this, "FUniqueNetIdSteam.GetSize"); }
FString* ToString(FString* result) { return NativeCall<FString*, FString*>(this, "FUniqueNetIdSteam.ToString", result); }
bool IsValid() { return NativeCall<bool>(this, "FUniqueNetIdSteam.IsValid"); }
FString* ToDebugString(FString* result) { return NativeCall<FString*, FString*>(this, "FUniqueNetIdSteam.ToDebugString", result); }
};uint64 steamid = static_cast<FUniqueNetIdSteam*>(UniqueId->Get())->UniqueNetId;void Hook_AShooterGameMode_PreLogin(AShooterGameMode* _this, FString* Options, FString* Address, TSharedPtr<FUniqueNetId, 0>* UniqueId, FString* authToken, FString* ErrorMessage)
{
uint64 steamid = static_cast<FUniqueNetIdSteam*>(UniqueId->Get())->UniqueNetId;
std::cout << std::to_string(steamid) + "\n";
AShooterGameMode_PreLogin_original(_this, Options, Address, UniqueId, authToken, ErrorMessage);
}FUniqueNetIdSteamFUniqueNetIdUInt64IOnlinePlatformData doesn't seem to give anything usable at alluint64 steamid = static_cast<FUniqueNetIdUInt64*>(UniqueId->Get())->UniqueNetIdField(); (edited)16140901064495857664AShooterGameMode.PostLogin
1AShooterGameMode.PostLogin for kicking for stuff like whitelistFNetControlMessage and then flush and close the player network connection?README.md as the main page for now, so that everyone has all the official links to everything important. I hope that's ok. (edited)Hook_AShooterGameMode_HandleNewPlayer that I used, and I had to pay attention to the bIsFromLogin parameter.bIsFromLogin indicated if it was a player directly connecting to the server or one that was transferring from another server.ApproveLogin() (edited)AGameSession (edited)UpdateSessionJoinability work?AShooterGameState AShooterGameMode AShooterGameSession and nothing I can do with it. (edited)Start-Process -FilePath "./ShooterGameServer.exe" -ArgumentList "TheIsland?listen?SessionName=test?ServerAdminPassword=test?Port=27015?QueryPort=27016?MaxPlayers=70" -WindowStyle Hidden -WaitStart-Process -FilePath "./ShooterGameServer.exe" -ArgumentList "TheIsland?listen?SessionName=test?ServerAdminPassword=test?Port=27015?QueryPort=27016?MaxPlayers=70" -WindowStyle Hidden -Wait bool Hook_FOnlineSessionSteam_UpdateSession(FOnlineSessionSteam* _this, FName SessionName, FOnlineSessionSettings* UpdatedSessionSettings, bool bShouldRefreshOnlineData)_this->GetGameServerSession()->SessionPrefixField()FUniqueNetIdUInt64.
I can't figure out how to create a variable normally and dont get a stack overflow 
GM->AllowPlayerToJoinNoCheck(PlayerID);
UPD: I have looked through the documentation and header files in the api. I think I've figured out how it works ShooterGameServer.pdb to get the offets for all the structures and functions it finds there (except for a few it discards) and throws them into an unordered_map. All the definitions that are present in the API have previously been manually extracted and added to the API? (edited)ShooterGameServer.pdb to get the offets for all the structures and functions it finds there (except for a few it discards) and throws them into an unordered_map. All the definitions that are present in the API have previously been manually extracted and added to the API? (edited)API::Timer::Get().RecurringExecute() without crash?
I have a function that gets the player position every 5 seconds, but if i unload the plugin, server crash.
c++
void Load() {
API::Timer::Get().RecurringExecute(&ActualizePlayerPosition, 5, -1, true);
} (edited)API::Timer::Get().RecurringExecute() without crash?
I have a function that gets the player position every 5 seconds, but if i unload the plugin, server crash.
c++
void Load() {
API::Timer::Get().RecurringExecute(&ActualizePlayerPosition, 5, -1, true);
} (edited)
AShooterGameMode::StartNewShooterPlayer (I think it fired for spawn), or AShooterCharacter::PossesedBy (this fired for spawn but also for a lot of other things like riding, noglin possibly, etc...)
Then you could do this to get the Buff ref:
AShooterWeapon* weap = character->CurrentWeaponField();
if (!weap)
return;
UProperty* buffProp = weap->FindProperty(FName("Buff Ref", EFindName::FNAME_Find));
if (!buffProp)
return;
APrimalBuff* buff = buffProp->Get<APrimalBuff*>(weap);
UFunction* toggleFunc = buff->FindFunctionChecked(FName("Toggle Target Lock", EFindName_FNAME_Find));
buff->ProcessEvent(toggleFunc, nullptr);API::Timer::Get().DelayExecute(&HandleSpawned, 5, GetWeakReference(_this)); // delays execute of the HandleSpawned function for 5 seconds
void HandleSpawned(TWeakObjectPtr<AShooterCharacter> character)
{
if (!character)
return;
UPrimalInventoryComponent* inventory = character->MyInventoryComponentField();
UPrimalItem* spyglassItem = nullptr;
for (UPrimalItem* item : inventory->InventoryItemsField())
{
if (item
&& item->NameField().ToString().Contains("BP_SuperSpyglass")) // checks if the item is an spyglass
{
spyglassItem = item;
break;
}
}
AShooterPlayerController* SPC = ArkApi::GetApiUtils().FindControllerFromCharacter(character);
SPC->ServerRequestInventoryUseItem(inventory, spyglassItem->ItemIDField()); // request use item
}UVictoryCore::BPLoadClass, and then on you can use APrimalBuff::StaticAddBuff to add it with the class you just loaded. The class can be cached but load class needs to be called after server startup (AShooterGameMode::InitGame or setting a DelayExecute from the load function works well enoughextern "C" __declspec(dllexport) void Plugin_Unload()
{
// join thread
}extern "C" __declspec(dllexport) void Plugin_Unload()
{
// join thread
} 
AShooterGameMode::InitGame
2. Include "Timer.h", and on load, call API::Timer::Get().DelayExecute(&YourFunction, 0);AShooterGameMode::InitGame
2. Include "Timer.h", and on load, call API::Timer::Get().DelayExecute(&YourFunction, 0); AShooterGameMode::InitGame
2. Include "Timer.h", and on load, call API::Timer::Get().DelayExecute(&YourFunction, 0); ScheduleForStart(void* fn);
{
API::Timer::Get().DelayExecute(fn, 0);
}Log->info("Processing startup tasks")hpp is a header file with code, it's all self containedhpp is kinda made uph template<StringLiteral S, concepts::Function T1, concepts::CommonType T2 = types::default_calling_convention, concepts::CommonType T3 = type_traits::select_default_t3_t<T2>>
class native_event
{};
template<StringLiteral S, typename RT, concepts::CommonType T2, concepts::CommonType T3, typename ...A>
class native_event<S, RT(A...), T2, T3>
{
public:
static RT callback(A... args)
{
}
};
Which generates a unique static callback function thru templates (there's a lot more going on, edited for brevity)int __cdecl _callback___native_event__2U__StringLiteral__0BF__moar__3D0FF__0EP__0GC__0GK__0GF__0GD__0HE__0CO__0FA__0HC__0GP__0GD__0GF__0HD__0HD__0EF__0HG__0GF__0GO__0HE__0A______A6AHPAX0_ZUcdecl_t_types_2_X_moar__SAHPAX0_Z(
void *<args_0>,
void *<args_1>)
GeneralizedAchievementTagGrants so as WC (or modders) add stuff, you can update it in the configShooterGameSever.pdb:
struct TCallTraitsParamTypeHelper<FVector2D,1> [sizeof = 1] {
typedef class FVector2D ParamType
typedef class FVector2D ConstParamType
}
Total padding 1 bytes (100% of class size)
Immediate padding 1 bytes (100% of class size)
struct TIsArithmeticType<TSharedPtr<FNavigationQueryFilter const ,0> > [sizeof = 1] {
enum <unnamed-enum-Value> {
Value = 0
}
}
Total padding 1 bytes (100% of class size)
Immediate padding 1 bytes (100% of class size)
struct FGenericPlatformTypes [sizeof = 1] {
typedef unsigned char uint8
typedef unsigned short uint16
typedef unsigned int uint32
typedef unsigned __int64 uint64
typedef char int8
typedef short int16
typedef int int32
typedef __int64 int64
typedef char ANSICHAR
typedef wchar_t WIDECHAR
typedef unsigned char CHAR8
typedef unsigned short CHAR16
typedef unsigned int CHAR32
typedef wchar_t TCHAR
typedef unsigned __int64 UPTRINT
typedef __int64 PTRINT
typedef unsigned __int64 SIZE_T
typedef int TYPE_OF_NULL
typedef void* TYPE_OF_NULLPTR
}
Total padding 1 bytes (100% of class size)
Immediate padding 1 bytes (100% of class size) (edited)BasicTypes.h
/**
* Generic types for almost all compilers and platforms
**/
struct FGenericPlatformTypes
{
// Unsigned base types.
typedef unsigned char uint8; // 8-bit unsigned.
typedef unsigned short int uint16; // 16-bit unsigned.
typedef unsigned int uint32; // 32-bit unsigned.
typedef unsigned long long uint64; // 64-bit unsigned.
// Signed base types.
typedef signed char int8; // 8-bit signed.
typedef signed short int int16; // 16-bit signed.
typedef signed int int32; // 32-bit signed.
typedef signed long long int64; // 64-bit signed.
// Character types.
typedef char ANSICHAR; // An ANSI character - 8-bit fixed-width representation of bit characters.
typedef wchar_t WIDECHAR; // A wide character - In-memory only. ?-bit fixed-width representation of the
typedef uint8 CHAR8; // An 8-bit character type - In-memory only. 8-bit representation. Should really be
typedef uint16 CHAR16; // A 16-bit character type - In-memory only. 16-bit representation. Should
typedef uint32 CHAR32; // A 32-bit character type - In-memory only. 32-bit representation. Should really be
typedef WIDECHAR TCHAR; // A switchable character - In-memory only. Either ANSICHAR or WIDECHAR, depending on a
typedef SelectIntPointerType<uint32, uint64, sizeof(void*)>::TIntPointer UPTRINT; // unsigned int the same size as a pointer
typedef SelectIntPointerType<int32, int64, sizeof(void*)>::TIntPointer PTRINT; // signed int the same size as a pointer
typedef UPTRINT SIZE_T; // unsigned int the same size as a pointer
typedef PTRINT SSIZE_T; // signed int the same size as a pointer
typedef int32 TYPE_OF_NULL;
typedef decltype(nullptr) TYPE_OF_NULLPTR;
};LLVM-15.0.7-win64.exe package from here: https://github.com/llvm/llvm-project/releases/tag/llvmorg-15.0.7
Then ran llvm-pdbutil pretty -classes ShooterGameServer.pdbpretty is the option to dump as formatted output, so if you run llvm-pdbutil pretty --help it gives you a ton of options. (edited) func [0x0166b8b0+ 6 - 0x0166b8db- 6 | sizeof= 43] (FPO) void __cdecl execUseAlternateStandingAnim(FFrame& Stack, const void* Result)0x0166b8b0 exists in the compiland f:\build\lostisland\projects\shootergame\source\shootergame\classes\shootercharacter.h (MD5: D23BAAF6F99E7E718CB639BEE0831768)
Line 52, Address: [0x0166b8b0 - 0x0166b8da] (43 bytes) func [0x0166b8b0+ 6 - 0x0166b8db- 6 | sizeof= 43] (FPO) void __cdecl execUseAlternateStandingAnim(FFrame& Stack, const void* Result) f:\build\lostisland\projects\shootergame\source\shootergame\classes\shootercharacter.h (MD5: D23BAAF6F99E7E718CB639BEE0831768)
Line 52, Address: [0x0166b8b0 - 0x0166b8da] (43 bytes) llvm-pdbutil pretty -all -compilands -lines ShooterGameServer.pdb > text.txtclass UObject where it's struct UObject in the API files.void __fastcall AShooterGameMode::PreLogin(AShooterGameMode *this, const FString *Options, const FString *Address, const TSharedPtr<FUniqueNetId,0> *UniqueId, const FString *authToken, FString *ErrorMessage, UNetConnection *Connection)void* my_ptr;
if(my_ptr = find_ptr()) {
//my_ptr != null
}else{
//my_ptr == null
}my_ptr and validate that my_ptr isn't nullif(x = y) as disallowed since the user usually meant if(x == y)if ((my_ptr = find_ptr()) != nullptr) is generally preferred to clarify intent if you really want to do assignment in an if condition.if ((my_ptr = find_ptr()) != nullptr) is generally preferred to clarify intent if you really want to do assignment in an if condition. if ((my_ptr = find_ptr()) != nullptr) hides malicious code even better imhoif (my_ptr = find_ptr()) should raise additional questions in a code review to ensure it wasn't supposed to be if (my_ptr == find_ptr())nullptr is just 0, so the check would pass the sameif (my_ptr = find_ptr()) should raise additional questions in a code review to ensure it wasn't supposed to be if (my_ptr == find_ptr()) static UClass* BPLoadClass(const FString& PathName) { return NativeCall<UClass*, const FString&>(nullptr, "UVictoryCore.BPLoadClass", PathName); } /* Manual Definition */BPLoadClass nowconst FString& but I left the original (dumped from IDA) which uses FString*FString& is fundamentally the same type as FString* when compiledstatic UClass* myClass = UVictoryCore::BPLoadClass("Blueprint'/Game/PrimalEarth/.../Blueprint'"); (edited) static UClass* BPLoadClass(const FString& PathName) { return NativeCall<UClass*, const FString&>(nullptr, "UVictoryCore.BPLoadClass", PathName); } /* Manual Definition */ c++
FString GetFullName(UObject* StopOuter)
{
FString result;
NativeCall<FString*, FString*, UObject*>(this, "UObjectBaseUtility.GetFullName", result, StopOuter);
return result;
}
Instead of the existing
c++
FString* GetFullName(FString* result, UObject* StopOuter)
{
return NativeCall<FString*, FString*, UObject*>(this, "UObjectBaseUtility.GetFullName", result, StopOuter);
} (edited)c++
FString GetFullName(UObject* StopOuter)
{
FString result;
NativeCall<FString*, FString*, UObject*>(this, "UObjectBaseUtility.GetFullName", result, StopOuter);
return result;
}
Instead of the existing
c++
FString* GetFullName(FString* result, UObject* StopOuter)
{
return NativeCall<FString*, FString*, UObject*>(this, "UObjectBaseUtility.GetFullName", result, StopOuter);
} (edited) FString LinkedPlayerIDString() { FString result; return *LinkedPlayerIDString(&result); }FString* LinkedPlayerIDString(FString* result) { return NativeCall<FString*, FString*>(this, "AShooterPlayerController.LinkedPlayerIDString", result); }struct AWorldSettings : AInfo{
...
std::array<TArray<AActor*>, 33>& ActorListsField() { return *GetNativePointerField<std::array<TArray<AActor*>, 33>*>(this, "AWorldSettings.ActorLists"); }
}
Quick example:
int GetNumTamedDinos(AShooterGameMode* _this)
{
auto* settings = _this->GetWorldSettings();
if (settings == nullptr) {
return 0;
}
auto tamed_dinos = settings->ActorListsField()[EActorListsBP::AL_TAMED_DINOS];
return tamed_dinos.Num();
}
Note that "EActorListsBP" has already been defined in "Enums.h".
namespace EActorListsBP
{
enum Type
{
AL_PLAYERS = 0x0,
...
AL_BEDS = 0x9,
...
AL_NPC_DEAD = 0xb,
...
AL_TAMED_DINOS = 0x16
};
}struct FOnlineSessionSteam : IOnlineSession
{
FNamedOnlineSession* GetGameServerSession() { return NativeCall<FNamedOnlineSession*>(this, "FOnlineSessionSteam.GetGameServerSession"); }
}; 
struct __cppobj __declspec(align(8)) FNamedOnlineSession : FOnlineSession
{
FString SessionPrefix;
const FName SessionName;
int HostingPlayerNum;
bool bHosting;
bool bRestarted;
TArray<TSharedRef<FUniqueNetId,0>,FDefaultAllocator> RegisteredPlayers;
EOnlineSessionState::Type SessionState;
};void Hook_UPrimalCharacterStatusComponent_AddExperience(UPrimalCharacterStatusComponent* _this, float HowMuch, bool bShareWithTribe, EXPType::Type XPType)UPrimalInventoryComponent::ServerUseInventoryItemUPrimalHarvestingComponent::GiveHarvestResourceUPrimalHarvestingComponent::GiveHarvestResource UseUsing
2int HP = statusComp->GetLevelUpPoints(EPrimalCharacterStatusValue::Health, false); works fine this_00 = UPrimalItem::AddNewItem
(local_358,(UPrimalInventoryComponent *)0x0,false,false,0.0,false,0,false ,
0.0,false,(TSubclassOf<UPrimalItem>)0x0,0.0,false,false);
UPrimalItem::GetItemNetInfo(this_00,&local_1c8,false); is what I see in ghidra, is all decompile syntax just in this format?this, which is the object instanceFItemNetInfo* UPrimalItem::GetItemNetInfo(
UPrimalItem *this,
FItemNetInfo *result,
bool bIsForSendingToClient) this_00 = UPrimalItem::AddNewItem
(local_358,(UPrimalInventoryComponent *)0x0,false,false,0.0,false,0,false ,
0.0,false,(TSubclassOf<UPrimalItem>)0x0,0.0,false,false);
UPrimalItem::GetItemNetInfo(this_00,&local_1c8,false); is what I see in ghidra, is all decompile syntax just in this format? class A
{
public:
void test(int, int);
};
and invoke it with
A a;
a.test(10,10)
under the hood the compiler creates a static function, such as A__test where the signature is
A__test(A* this, int, int)
and each instance call, a.test(10,10) becomes
A a;
A__test(&a, 10, 10);class A
{
public:
void test(int, int);
};
test would be
void (__thiscall A::*)(int,int)
which can be decayed into
void (__thiscall *)(A*, int,int)__thiscall since x86_64 uses __fastcall for basically everything.c++
UProperty* prop = actor->FindProperty(FName("StasisComponent", EFindName::FNAME_Find));
USphereComponent& val = prop->Get<USphereComponent>(actor);
Crashes here which makes sense but not sure how to solve it.
C++
Get(UObject* object)
{
...
if (sizeof(T) != this->ElementSizeField())
throw std::invalid_argument("Expected size does not match property size."); (edited)USphereComponent*


1void Hook_UPrimalCharacterStatusComponent_AddExperience(UPrimalCharacterStatusComponent* _this, float howMuch, bool bShareWithTribe, EXPType::Type type) {
auto character = _this->GetPrimalCharacter();
auto isPlayer = character->IsA(AShooterCharacter::StaticClass());
auto isDino = character->IsA(APrimalDinoCharacter::StaticClass());
if ((type == EXPType::MAX || type == EXPType::XP_KILL || type == EXPType::XP_ALPHAKILL) && (isPlayer || isDino)) {
and apparently wild dinos get XP too lolvoid Hook_UPrimalCharacterStatusComponent_AddExperience(UPrimalCharacterStatusComponent* _this, float howMuch, bool bShareWithTribe, EXPType::Type type) {
auto character = _this->GetPrimalCharacter();
auto isPlayer = character->IsA(AShooterCharacter::StaticClass());
auto isDino = character->IsA(APrimalDinoCharacter::StaticClass());
if ((type == EXPType::MAX || type == EXPType::XP_KILL || type == EXPType::XP_ALPHAKILL) && (isPlayer || isDino)) {
and apparently wild dinos get XP too lol BPIsTamed function but that just returns the same comparisonDinoDropInventoryComponent that is created upon death, you could hook one of the inventory init functions and remove the items after it's been initialized, or remove them before even initializing. dino drop inventories generate random items from ItemSets field so you could mess with possible items to be generated.Blueprint'/Game/PrimalEarth/CoreBlueprints/Inventories/DinoDropInventoryComponent_BP_Base.DinoDropInventoryComponent_BP_Base' so you could cache the UClass* and compare it when you need toMyInventoryComponentField upon death, but it for sure is in the component list of the dino after it dies)c++
UGameplayStatics::GetAllActorsOfClass(ArkApi::GetApiUtils().GetWorld(), typeToFind, &FoundActors);
for (uint32_t i = 0; i < FoundActors.Num(); i++)
{
AActor* actor = FoundActors[i];
FString bp = ArkApi::GetApiUtils().GetBlueprint(actor);
if ((bp.Contains("FeedingTrough") || bp.Contains("TekTrough")) == false) continue;
UProperty* prop = actor->FindProperty(FName("StasisComponent", EFindName::FNAME_Find));
if (prop)
{
USphereComponent* val = prop->Get<USphereComponent*>(actor);
val->SetSphereRadius(1.0, true);
}
}c++
UProperty* prop = actor->FindProperty(FName("StasisComponent", EFindName::FNAME_Find));
Does that return anything? I don't know that there's a property called "StasisComponent".git clone https://github.com/SubstituteR/ArkServerAPI-Template.git --recursiveUpdateComponentToWorld() seems to do the trick when updating existing structure's stasis components.
c++
UProperty* stasisCompProp = troughStructure->FindProperty(FName("StasisComponent", EFindName::FNAME_Find));
if (!stasisCompProp)
return;
USphereComponent* stasisComp = stasisCompProp->Get<USphereComponent*>(troughStructure);
if (!stasisComp)
return;
float currentRadius = *GetNativePointerField<float*>(stasisComp, "USphereComponent.SphereRadius");
Log::GetLog()->info("Original Radius = {}", currentRadius);
stasisComp->SetSphereRadius(10000, true);
stasisComp->UpdateComponentToWorld(true);
currentRadius = *GetNativePointerField<float*>(stasisComp, "USphereComponent.SphereRadius");
Log::GetLog()->info("New Radius = {}", currentRadius);Female Mating Range Addition which can increase the range. Not sure if negatives decrease it though.if (GetWorld()->OverlapMultiInternalOctree(HitPrimitives, FBoxCenterAndExtent(GetActorLocation(), FVector(0.75f*Mesh->Bounds.SphereRadius + FemaleMatingRangeAddition)), OCTREEGROUP_DINOPAWNS_TAMED))
{
// process for viable mates
}0.75f*Mesh->Bounds.SphereRadius + FemaleMatingRangeAdditionAShooterGameMode::SaveWorldTSharedPtr<FWriteFileTaskInfo,0>* Hook_UWorld_SaveToFile(UWorld *world, TSharedPtr<FWriteFileTaskInfo,0> *result,
FString *param_1,FString *param_2,
TArray<TSubclassOf<AActor>,FDefaultAllocator> *param_3) (edited)FWriteFileTaskInfo this?struct __cppobj FWriteFileTaskInfo
{
TArray<unsigned char,FDefaultAllocator> FileContent;
TArray<unsigned char,FDefaultAllocator> EXTRA_FileContent;
TArray<unsigned char,FDefaultAllocator> EXTRA2_FileContent;
TArray<unsigned char,FDefaultAllocator> EXTRA3_FileContent;
TArray<unsigned char,FDefaultAllocator> EXTRA4_FileContent;
TRefCountPtr<FGraphEvent> CompletionHandle;
};struct __cppobj __declspec(align(8)) FGraphEvent
{
TClosableLockFreePointerListUnorderedSingleConsumer<FBaseGraphTask,0> SubsequentList;
TArray<TRefCountPtr<FGraphEvent>,TInlineAllocator<4,FDefaultAllocator> > EventsToWaitFor;
FThreadSafeCounter ReferenceCount;
};struct FBaseGraphTask
{
void *__vftable /*VFT*/;
ENamedThreads::Type ThreadToExecuteOn;
FThreadSafeCounter NumberOfPrerequistitesOutstanding;
};struct FThreadSafeCounter
{
volatile int Counter;
}; (edited)TClosableLockFreePointerListUnorderedSingleConsumer in: https://github.com/EpicGames/UnrealEngine/tree/4.5/Engine/Source/Runtime/Core/Public/Containers (edited)




DinoClassDamageMultipliers=(ClassName="Manticore_Character_BP_Easy_C",Multiplier=0.90)
DinoClassResistanceMultipliers=(ClassName="Manticore_Character_BP_Easy_C",Multiplier=0.90)
For example.UPrimalInventoryComponent::RemoveItem is one of the core remove functionsUPROPERTY(EditAnywhere, SaveGame)UPrimalBuffPersistentData* MyBuffPersistentData fieldc++
template <typename T>
struct TWeakObjectPtr
{
T* Get(bool bEvenIfPendingKill = false)
{
return NativeCall<T*, bool>(this, "FWeakObjectPtr.Get", bEvenIfPendingKill);
}
...
}
In Unreal Engine, the template class is defined like:
c++
template<class T=UObject, class TWeakObjectPtrBase=FWeakObjectPtr, class TUObjectArray=FIndexToObject>
struct TWeakObjectPtr : private TWeakObjectPtrBase
{
...
}
If you tried to use ArkServerApi's implementation on a TWeakObjectPtr in the server that doesn't use the default types (TWeakObjectPtrBase=FWeakObjectPtr and TUObjectArray=FIndexToObject), it may not work. But I think those defaults are always used (at least in ARK). (edited)c++
template <typename T>
struct TWeakObjectPtr
{
T* Get(bool bEvenIfPendingKill = false)
{
return NativeCall<T*, bool>(this, "FWeakObjectPtr.Get", bEvenIfPendingKill);
}
...
}
In Unreal Engine, the template class is defined like:
c++
template<class T=UObject, class TWeakObjectPtrBase=FWeakObjectPtr, class TUObjectArray=FIndexToObject>
struct TWeakObjectPtr : private TWeakObjectPtrBase
{
...
}
If you tried to use ArkServerApi's implementation on a TWeakObjectPtr in the server that doesn't use the default types (TWeakObjectPtrBase=FWeakObjectPtr and TUObjectArray=FIndexToObject), it may not work. But I think those defaults are always used (at least in ARK). (edited)AShooterPlayerController::ServerSendChatMessage_ImplementationA-Record or CNAME Record. Since the old endpoints don't match up with the current endpoints if I put ArkServerApi.com on the DNS record for IP address instead of a force redirect then it'll still only work with new URLs rather then old endpoints. The other element is I don't know what the old endpoints where for each resource so that'd be tricky to find them.UClass* FindDinoClass(UPrimalItem* cryopod)
{
if (!cryopod)
return nullptr;
if (!cryopod->NameField().ToString().Contains("Cryopod"))
return nullptr;
struct ReturnParams
{
FCustomItemData data
UClass* returnedClass = nullptr;
};
ReturnParams params;
UFunction* GetContainedDinoFunction = cryopod->FindFunctionChecked(FName("GetContainedDinoClass", EFindName::FNAME_Add));
if (!GetContainedDinoFunction)
return nullptr;
cryopod->ProcessEvent(GetContainedDinoFunction, ¶ms);
return params.returnedClass;
} (edited)UClass* FindDinoClass(UPrimalItem* cryopod)
{
if (!cryopod)
return nullptr;
if (!cryopod->NameField().ToString().Contains("Cryopod"))
return nullptr;
struct ReturnParams
{
FCustomItemData data
UClass* returnedClass = nullptr;
};
ReturnParams params;
UFunction* GetContainedDinoFunction = cryopod->FindFunctionChecked(FName("GetContainedDinoClass", EFindName::FNAME_Add));
if (!GetContainedDinoFunction)
return nullptr;
cryopod->ProcessEvent(GetContainedDinoFunction, ¶ms);
return params.returnedClass;
} (edited)AShooterGameState::AllowDinoTame and AShooterGameState::AllowDinoClassTame
I am not sure if the bitfield on the dino factors in the tame prevention by INI server settings.bCanBeTamed is probably set from AShooterGameState::AllowDinoTame and AShooterGameState::AllowDinoClassTame. I'm trying to check if dinos in caves are tamable and it returns true for all the high level dinos that are not tamable but where the species can be tamed.APrimalDinoCharacter::bForceDisablingTaming for future reference.dino->DescriptionNameField() = FString("text ") + dino->DescriptionNameField() + FString(" text");c++
std::map<FString, bool> modifiedCreatureTypes;
void Hook_UPrimalCharacterStatusComponent_InitializeComponent(UPrimalCharacterStatusComponent* statusComponent)
{
// ...
APrimalCharacter* primalCharacter = static_cast<APrimalCharacter*>(statusComponent->GetPrimalCharacter());
if (primalCharacter == nullptr) return;
FString bp = ArkApi::GetApiUtils().GetBlueprint(primalCharacter);
if (modifiedCreatureTypes.find(bp) != modifiedCreatureTypes.end()) return;
UPrimalCharacterStatusComponent* defaultStatusComponent = static_cast<UPrimalCharacterStatusComponent*>(statusComponent->ClassField()->GetDefaultObject(true));
if (defaultStatusComponent == nullptr) return;
// ...
// get the base value from the default object
float& value = defaultStatusComponent->MaxStatusValuesField()()[EPrimalCharacterStatusValue::Stamina];
// save the base value
float baseValue = value;
// calculate the compensated base value (if our creature had x more base levels in this stat)
float newBaseValue = baseValue * 2;
// set the new base value on the default object
value = newBaseValue;
modifiedCreatureTypes.emplace(bp, true);
// ...
UPrimalCharacterStatusComponent_InitializeComponent_original(statusComponent);
}
void Hook_APrimalDinoCharacter_BeginPlay(APrimalDinoCharacter* _this)
{
APrimalDinoCharacter_BeginPlay_original(_this);
// ...
UPrimalCharacterStatusComponent* statusComponent = _this->MyCharacterStatusComponentField();
// ...
statusComponent->RescaleMaxStat(EPrimalCharacterStatusValue::Stamina, 1.0, true);
} (edited)c++
void ModifyDinoBaseStats(APrimalDinoCharacter* dino, AShooterPlayerController* PC, std::vector<int> baseLevelMods)
{
UPrimalCharacterStatusComponent* status = dino->MyCharacterStatusComponentField();
if (status)
{
// 0: health
// 1: stamina
// 2: torpor
// 3: oxygen
// 4: food
// 5: water
// 6: temperature
// 7: weight
// 8: melee damage
// 9: movement speed
// 10: fortitude
// 11: crafting speed
// ModifyDinoBaseStats(APrimalDinoCharacter* dino, AShooterPlayerController* PC, std::vector<int> baseLevelMods)
// [health, stamina, torpor, oxygen, food, water, temperature, weight, melee damage, movement speed, fortitude, crafting speed]
if (baseLevelMods.size() == 12)
{
auto levelUpPointsAppliedBase = status->NumberOfLevelUpPointsAppliedField()();
auto baseCharacterLevel = 1;
for (auto i = 0; i < 12; i++)
{
auto newBaseLevel = baseLevelMods[i];
if (newBaseLevel < 0) newBaseLevel = 0;
else if (newBaseLevel > 255) newBaseLevel = 255;
levelUpPointsAppliedBase[i] = newBaseLevel;
baseCharacterLevel += newBaseLevel;
}
status->BaseCharacterLevelField() = baseCharacterLevel;
}
status->RescaleAllStats();
auto maxStatusValues = status->MaxStatusValuesField()();
auto status_component = reinterpret_cast<UActorComponent*>(status);
dino->BPNotifyLevelUp(0);
auto func_ClientNotifyLevelUp = dino->FindFunctionChecked(
FName("ClientNotifyLevelUp", EFindName::FNAME_Find));
if (func_ClientNotifyLevelUp) dino->ProcessEvent(func_ClientNotifyLevelUp, nullptr);
auto func_ClientNotifyLevelUpPC = PC->FindFunctionChecked(
FName("ClientNotifyLevelUp", EFindName::FNAME_Find));
if (func_ClientNotifyLevelUpPC)
PC->ProcessEvent(
func_ClientNotifyLevelUpPC, &TArray<unsigned short>());
status->CharacterUpdatedInventory(true);
status->ServerSyncReplicatedValues();
auto baseLevelMaxStatusValues = status->BaseLevelMaxStatusValuesField()();
auto func_NetSyncMaxStatusValues = status_component->FindFunctionChecked(
FName("NetSyncMaxStatusValues", EFindName::FNAME_Find));
if (func_NetSyncMaxStatusValues)
{
TArray<float> aMaxStatusValues, aBaseLevelMaxStatusValues;
for (auto i = 0; i < 12; i++)
{
aMaxStatusValues.Add(maxStatusValues[i]);
aBaseLevelMaxStatusValues.Add(baseLevelMaxStatusValues[i]);
}
TArray<float> Args[] = { aMaxStatusValues, aBaseLevelMaxStatusValues };
status_component->ProcessEvent(func_NetSyncMaxStatusValues, Args);
}
status->UpdateWeightStat(true);
dino->ForceNetUpdate(false, true, false);
}
} (edited)float& value = defaultStatusComponent->MaxStatusValuesField()()[EPrimalCharacterStatusValue::Stamina]; and then set value = x; I get the feeding bug with passive dinos.APrimalDinoCharacter_BeginPlay on levelups etc. If you skip calling rescale after the CDO changes they won't show up in the game tho.ServerChatToPlayer i believevoid* Hook_UWorld_SaveToFile(UWorld *_this, void *result, FString *filename, FString *tempFilename, const void *typesToSave) {
auto color = FLinearColor(255, 0, 0, 255);
ArkApi::GetApiUtils().SendNotificationToAll(color, 1, 5, nullptr, "Server is performing an auto save.");
return UWorld_SaveToFile_original(_this, result, filename, tempFilename, typesToSave);
is sending it after the save lol void Hook_AShooterGameMode_SaveWorld(AShooterGameMode *_this, bool forceWaitOnSave) {
if (!forceWaitOnSave) {
auto color = FLinearColor(255, 0, 0, 255);
ArkApi::GetApiUtils().SendNotificationToAll(color, 1, 5, nullptr, "Server is performing a world save.");
DELAYEXECUTE([_this]() {
AShooterGameMode_SaveWorld_original(_this, false);
},0);
} else {
AShooterGameMode_SaveWorld_original(_this, true);
}
}void Hook_UShooterCheatManager_ServerChat(UShooterCheatManager* _this, FString* msg) {
if (!msg->Contains("A world save is about to be performed")) {
UShooterCheatManager_ServerChat_original(_this, msg);
}
}void Hook_UShooterCheatManager_ServerChat(UShooterCheatManager* _this, FString* msg) {
if (!msg->Contains("A world save is about to be performed")) {
UShooterCheatManager_ServerChat_original(_this, msg);
}
} // UPrimalItem* item = ....
UTexture2D *item_icon = item->GetItemIcon(shooter_pc);
FString icon_path;
item_icon->GetPathName(item, &icon_path);
Log::GetLog()->warn("Path icon: {}", icon_path.ToString()); (edited)// UPrimalItem* item = ....
UTexture2D *item_icon = item->GetItemIcon(shooter_pc);
FString icon_path;
item_icon->GetPathName(item, &icon_path);
Log::GetLog()->warn("Path icon: {}", icon_path.ToString()); (edited)#define CAST(as, from) reinterpret_cast<as>(from)
#define FORCECAST(as, from) *CAST(as*, CAST(void*, &from))DECLARE_HOOK(FWindowsPlatformMisc_RequestExit, void, bool); SafeQueue<std::function<void()>> taskQueue;
volatile bool isShuttingDownTaskQueue = false;
void taskThreadRun() {
while (!isShuttingDownTaskQueue) {
try {
auto task = taskQueue.dequeue();
if (task) task();
} catch (std::exception& e) {
LOG->error("Error Task: " + std::string(e.what()));
}
}
}
std::thread taskThread(taskThreadRun);
void shutdownTaskQueue() {
if (!isShuttingDownTaskQueue) {
isShuttingDownTaskQueue = true;
taskQueue.shutdown();
taskThread.join();
LOG->info("Task Queue Shutdown");
}
}
void addThreadTask(std::function<void()> task) {
if (isShuttingDownTaskQueue) {
try {
task();
} catch (std::exception& e) {
LOG->error("Error Task: " + std::string(e.what()));
}
} else {
taskQueue.enqueue(task);
}
}DoMate is called.
c++
TSubclassOf<APrimalDinoCharacter> EggDinoClassToSpawn; // this is from the DoMate arguments
APrimalDinoCharacter* defaultObject = static_cast<APrimalDinoCharacter*>(EggDinoClassToSpawn.uClass->GetDefaultObject(true));
defaultObject->BabyChanceOfTwinsField() = 1.0;
defaultObject->BabyChanceOfTripletsField() = 0.0; (edited) SafeQueue<std::function<void()>> taskQueue;
volatile bool isShuttingDownTaskQueue = false;
void taskThreadRun() {
while (!isShuttingDownTaskQueue) {
try {
auto task = taskQueue.dequeue();
if (task) task();
} catch (std::exception& e) {
LOG->error("Error Task: " + std::string(e.what()));
}
}
}
std::thread taskThread(taskThreadRun);
void shutdownTaskQueue() {
if (!isShuttingDownTaskQueue) {
isShuttingDownTaskQueue = true;
taskQueue.shutdown();
taskThread.join();
LOG->info("Task Queue Shutdown");
}
}
void addThreadTask(std::function<void()> task) {
if (isShuttingDownTaskQueue) {
try {
task();
} catch (std::exception& e) {
LOG->error("Error Task: " + std::string(e.what()));
}
} else {
taskQueue.enqueue(task);
}
} plugin_unload as __fastcall and c++ standard convention is __cdecl and if you don't set your export explicitly to __fastcall as the API is calling it I believe you can have unknown behavior.extern "C" __declspec(dllexport) void __fastcall Plugin_Unload()
{
// Stop threads here
}__fastcall is going to default to the project defined setting which is __cdecl by default I believe.plugin_unload as __fastcall and c++ standard convention is __cdecl and if you don't set your export explicitly to __fastcall as the API is calling it I believe you can have unknown behavior. if(MSVC)
target_compile_options(${PROJECT_NAME} PRIVATE
$<$<CONFIG:Release>:
/Ot
>
/permissive-;
/Oi;
/sdl;
/Gy;
/W3;
${DEFAULT_CXX_DEBUG_INFORMATION_FORMAT};
${DEFAULT_CXX_EXCEPTION_HANDLING};
/Y-
)
so i assume thats default for cdeclstd::atomic_boolauto now = timestamp();
if (now - lastTickStatus > 15) {
lastTickStatus = now;
writeFile("tick.txt", STR(now));
} works fine as a tick callback
it makes total sense that if the state of the uworld tick detours change while in middle of executing it, things can get funky__cdecl is accepted but typically ignored by the compiler. By convention on ARM and x64, arguments are passed in registers when possible, and subsequent arguments are passed on the stack. In x64 code, use __cdecl to override the /Gv compiler option and use the default x64 calling convention.void ThreadTaskQueue::run() {
std::string threadId = getThreadId();
do {
try {
std::shared_ptr<ThreadTask> task;
{
std::unique_lock<std::mutex> lock(mutex);
if(queue.empty()) {
signal.wait(lock);
}
task = queue.front();
queue.pop();
}
task->operator()();
} catch (std::exception& e) {
Log::GetLog()->error(getThreadId() + " Error Task run: " + std::string(e.what()));
}
} while (!isShuttingDownTaskQueue);
}bHideDefaultInventoryItemsFromDisplay. I'll test.DoMate is called.
c++
TSubclassOf<APrimalDinoCharacter> EggDinoClassToSpawn; // this is from the DoMate arguments
APrimalDinoCharacter* defaultObject = static_cast<APrimalDinoCharacter*>(EggDinoClassToSpawn.uClass->GetDefaultObject(true));
defaultObject->BabyChanceOfTwinsField() = 1.0;
defaultObject->BabyChanceOfTripletsField() = 0.0; (edited)this in DoMate_Implementation(APrimalDinoCharacter *thisc++
void ModifyDinoBaseStats(APrimalDinoCharacter* dino, AShooterPlayerController* PC, std::vector<int> baseLevelMods)
{
UPrimalCharacterStatusComponent* status = dino->MyCharacterStatusComponentField();
if (status)
{
// 0: health
// 1: stamina
// 2: torpor
// 3: oxygen
// 4: food
// 5: water
// 6: temperature
// 7: weight
// 8: melee damage
// 9: movement speed
// 10: fortitude
// 11: crafting speed
// ModifyDinoBaseStats(APrimalDinoCharacter* dino, AShooterPlayerController* PC, std::vector<int> baseLevelMods)
// [health, stamina, torpor, oxygen, food, water, temperature, weight, melee damage, movement speed, fortitude, crafting speed]
if (baseLevelMods.size() == 12)
{
auto levelUpPointsAppliedBase = status->NumberOfLevelUpPointsAppliedField()();
auto baseCharacterLevel = 1;
for (auto i = 0; i < 12; i++)
{
auto newBaseLevel = baseLevelMods[i];
if (newBaseLevel < 0) newBaseLevel = 0;
else if (newBaseLevel > 255) newBaseLevel = 255;
levelUpPointsAppliedBase[i] = newBaseLevel;
baseCharacterLevel += newBaseLevel;
}
status->BaseCharacterLevelField() = baseCharacterLevel;
}
status->RescaleAllStats();
auto maxStatusValues = status->MaxStatusValuesField()();
auto status_component = reinterpret_cast<UActorComponent*>(status);
dino->BPNotifyLevelUp(0);
auto func_ClientNotifyLevelUp = dino->FindFunctionChecked(
FName("ClientNotifyLevelUp", EFindName::FNAME_Find));
if (func_ClientNotifyLevelUp) dino->ProcessEvent(func_ClientNotifyLevelUp, nullptr);
auto func_ClientNotifyLevelUpPC = PC->FindFunctionChecked(
FName("ClientNotifyLevelUp", EFindName::FNAME_Find));
if (func_ClientNotifyLevelUpPC)
PC->ProcessEvent(
func_ClientNotifyLevelUpPC, &TArray<unsigned short>());
status->CharacterUpdatedInventory(true);
status->ServerSyncReplicatedValues();
auto baseLevelMaxStatusValues = status->BaseLevelMaxStatusValuesField()();
auto func_NetSyncMaxStatusValues = status_component->FindFunctionChecked(
FName("NetSyncMaxStatusValues", EFindName::FNAME_Find));
if (func_NetSyncMaxStatusValues)
{
TArray<float> aMaxStatusValues, aBaseLevelMaxStatusValues;
for (auto i = 0; i < 12; i++)
{
aMaxStatusValues.Add(maxStatusValues[i]);
aBaseLevelMaxStatusValues.Add(baseLevelMaxStatusValues[i]);
}
TArray<float> Args[] = { aMaxStatusValues, aBaseLevelMaxStatusValues };
status_component->ProcessEvent(func_NetSyncMaxStatusValues, Args);
}
status->UpdateWeightStat(true);
dino->ForceNetUpdate(false, true, false);
}
} (edited)c++
void Hook_APrimalStructure_BeginPlay(APrimalStructure* _this)
{
APrimalStructure_BeginPlay_original(_this);
if (_this->IsA(APrimalStructureItemContainer::StaticClass()))
{
APrimalStructureItemContainer* itemContainer = static_cast<APrimalStructureItemContainer*>(_this);
UPrimalInventoryComponent* invComponent = itemContainer->MyInventoryComponentField();
if (invComponent != nullptr)
{
static UBlueprintGeneratedClass* cookingPotBaseClass = (UBlueprintGeneratedClass*)Globals::FindClass("BlueprintGeneratedClass /Game/PrimalEarth/Structures/CookingPot.CookingPot_C");
//FString bp = ArkApi::GetApiUtils().GetBlueprint(_this);
//if (bp.Contains("/Game/PrimalEarth/Structures/CookingPot.CookingPot") == true)
if (cookingPotBaseClass != nullptr && actor->IsA(cookingPotBaseClass))
{
invComponent->bHideDefaultInventoryItemsFromDisplay() = false;
}
}
}
}DefaultInventoryItems?bHideFromInventoryDisplay to false and didn't work either. MaxInventoryItems works on existing structures so I guess there is some behind the scenes type setup on engrams that I am missing when bHideDefaultInventoryItemsFromDisplay is not set when the structures are created and placed in the world.



DECLARE_HOOK(FWindowsPlatformMisc_RequestExit, void, bool);void Hook_FEngineLoop_Exit(void* _this) {
exiting = true;
taskQueue.shutdown();
if (shuttingDown) {
writeStatus("cleanshutdown");
} else {
writeStatus("unexpectedshutdown");
}
SAOmega::WorldSave::Exit();
FEngineLoop_Exit_original(_this);
}
so i guess i actually was calling that method post shutdown, in this case those writeStatus are by desire executing on caller thread as the taskQueue is now shutdown.MaxInventoryItems works on existing structures so I guess there is some behind the scenes type setup on engrams that I am missing when bHideDefaultInventoryItemsFromDisplay is not set when the structures are created and placed in the world. const auto& PCS = ArkApi::GetApiUtils().GetWorld()->PlayerControllerListField();
for (TWeakObjectPtr<APlayerController> APC : PCS)
{
AShooterPlayerController* PC = static_cast<AShooterPlayerController*>(APC.Get());
if (PC)
//kick the player
}PC->KickPlayer(); or something to add into that code.ArkApi::GetApiUtils().GetShooterGameMode()->KickPlayerController(PC, &KicKMessage);someprocess.exe > console.txt> console.txt basically says to write all console output to the file console.txtc++
struct FDamageTypeAdjuster
{
TSubclassOf<UDamageType> DamageTypeClass;
float DamageMultiplier;
unsigned __int32 bIgnoreMultiplierIfWildDinoAttacker : 1;
unsigned __int32 bIgnoreMultiplierIfTamedDinoAttacker : 1;
unsigned __int32 bOnlyUseMultiplierIfWildDinoAttacker : 1;
unsigned __int32 bOnlyUseMultiplierIfTamedDinoAttacker : 1;
unsigned __int32 bOnlyUseMultiplierIfTamed : 1;
};
void Hook_APrimalDinoCharacter_BeginPlay(APrimalDinoCharacter* _this)
{
FString bp = ArkApi::GetApiUtils().GetBlueprint(_this);
APrimalDinoCharacter_BeginPlay_original(_this);
if (bp.Equals("Blueprint'/Game/PrimalEarth/Dinos/Mosasaurus/Mosa_Character_BP.Mosa_Character_BP'"))
{
static FString DmgTypeBpPath(FString("Blueprint'/Game/PrimalEarth/CoreBlueprints/DamageTypes/DmgType_Melee_Dino_Carnivore_Small_Electrocute.DmgType_Melee_Dino_Carnivore_Small_Electrocute'"));
static UClass* DmgType = UVictoryCore::BPLoadClass(&DmgTypeBpPath);
FDamageTypeAdjuster stunImmunity;
stunImmunity.DamageTypeClass = TSubclassOf<UDamageType>(DmgType);
stunImmunity.DamageMultiplier = 0.0;
stunImmunity.bIgnoreMultiplierIfTamedDinoAttacker = false;
stunImmunity.bIgnoreMultiplierIfWildDinoAttacker = false;
stunImmunity.bOnlyUseMultiplierIfTamed = false;
stunImmunity.bOnlyUseMultiplierIfTamedDinoAttacker = false;
stunImmunity.bOnlyUseMultiplierIfWildDinoAttacker = false;
TArray<FDamageTypeAdjuster>& damageTypeAdjusters = *GetNativePointerField<TArray<FDamageTypeAdjuster>*>(_this, "APrimalCharacter.DamageTypeAdjusters");
damageTypeAdjusters.Add(stunImmunity);
}
} (edited)CREATE_NO_WINDOWstart $C -ForceAllowCaveFlyers -useautoreporter -serverkey=$id -stdout >> launch.log 2>&1DETACHED_PROCESS or CREATE_NEW_CONSOLEvoid OpenConsole()
{
AllocConsole();
FILE* p_cout;
freopen_s(&p_cout, "conout$", "w", stdout);
SetConsoleOutputCP(CP_UTF8);
}CreateToolhelp32Snapshot should be safe in dllmain as it is located in kernel32kernel32 are safe-ish in dllmainc:\vcpkg>vcpkg list
bzip2:x64-windows 1.0.8#3 bzip2 is a freely available, patent free, high-q...
bzip2[tool]:x64-windows Builds bzip2 executable
expat:x64-windows 2.5.0#3 XML parser library written in C
fmt:x64-windows 9.1.0#1 Formatting library for C++. It can be used as a ...
pcre2:x64-windows 10.40#1 Regular Expression pattern matching using the sa...
poco:x64-windows 1.12.4#3 Modern, powerful open source C++ class libraries...
vcpkg-cmake-config:x64-windows 2022-02-06#1
vcpkg-cmake:x64-windows 2022-12-22
zeromq:x64-windows 4.3.4#6 The ZeroMQ lightweight messaging kernel is a lib...
zlib:x64-windows 1.2.13 A compression library
c:\vcpkg>vcpkg remove poco:x64-windows
The following packages will be removed:
poco:x64-windows
Removing 1/1 poco:x64-windows
c:\vcpkg>DWORD GetParentProcessId()
{
const DWORD InvalidParentProcessId = 0;
HANDLE Snapshot = 0;
PROCESSENTRY32 ProcessEntry;
DWORD PID = GetCurrentProcessId();
Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (Snapshot == INVALID_HANDLE_VALUE)
return InvalidParentProcessId;
ZeroMemory(&ProcessEntry, sizeof(ProcessEntry));
ProcessEntry.dwSize = sizeof(ProcessEntry);
if (!Process32First(Snapshot, &ProcessEntry))
return InvalidParentProcessId;
do
{
if (ProcessEntry.th32ProcessID == PID)
return ProcessEntry.th32ParentProcessID;
} while (Process32Next(Snapshot, &ProcessEntry));
return InvalidParentProcessId;
}
void OpenConsole()
{
if (GetConsoleWindow())
return;
DWORD parentProcessId = GetParentProcessId();
if (parentProcessId && AttachConsole(parentProcessId))
return;
AllocConsole();
FILE* p_cout;
freopen_s(&p_cout, "conout$", "w", stdout);
SetConsoleOutputCP(CP_UTF8);
}AttachToParent to the config.json under settings as "true" to have it attach to the parent console if available.{
"settings":{
"AutomaticPluginReloading":true,
"AutomaticPluginReloadSeconds":5,
"SaveWorldBeforePluginReload":true,
"AttachToParent":true
}
}inline long long calculateFieldOffset(void* _this, const char *field) {
size_t *actualPtr = reinterpret_cast<size_t *>(GetNativePointerField<void*>(_this, field));
return actualPtr - reinterpret_cast<size_t *>(_this);
}
struct FSupplyCrateItemSet {
uint8 _padding[0x40];
TArray<FSupplyCrateItemEntry, FDefaultAllocator>& ItemEntriesField() {
static auto offset = calculateFieldOffset(this, "FSupplyCrateItemSet.ItemEntries");
return *((TArray<FSupplyCrateItemEntry, FDefaultAllocator>*)((size_t*)this + offset));
}
};
would be very easy to apply that pattern to the helper methods and cache the offset and im sure yall know how to clean the pattern up more.
And can get the padding blocks in there so it works fine for TArray I think it was said is where that matters yeah? with that, the risk then would only be if size of a struct changed and that struct is used in an array
Though this could be automated too and then send a ping in a discord channel for devs to be aware of changed structs and know if they use it in their plugin.///AShooterCharacter_gen.h
class AShooterCharacter
{
//generated methods
}
///AShooterCharacter.h
class AShooterCharacter
{
public std::uint64 UniqueIdFromCharacter();
} (edited) if ( GIsOfficialServer )
{
v3 = FOutputDeviceRedirector::Get();
FOutputDevice::Log(
v3,
L"AShooterPlayerController::ReceivedPlayerState() how could this be called on the server?");
}c++
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->TargetingTeamField() < 10000) // wild dinos
{
FString targetName, damageCauserName, eventInstigatorName, weaponName;
FName damageTypeFName;
_this->GetHumanReadableName(&targetName);
DamageCauser->GetHumanReadableName(&damageCauserName);
EventInstigator->GetHumanReadableName(&eventInstigatorName);
DamageEvent->DamageTypeClassField().uClass->GetDefaultObjectName(&damageTypeFName);
if (EventInstigator->IsA(AShooterPlayerController::GetPrivateStaticClass()))
{
AShooterPlayerController* shooterPlayerController = static_cast<AShooterPlayerController*>(EventInstigator);
AShooterWeapon* weapon = shooterPlayerController->GetPlayerCharacter()->CurrentWeaponField();
if (weapon != nullptr) weapon->GetHumanReadableName(&weaponName);
}
SendConsoleMessageToAll("{} damage of type {} to {} from {} by {} using {}", Damage, damageTypeFName.ToString().ToString(), targetName.ToString(), damageCauserName.ToString(), eventInstigatorName.ToString(), weaponName.ToString());
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
}c++
static UBlueprintGeneratedClass* ProjArrowTranqBoltClass = (UBlueprintGeneratedClass*)Globals::FindClass("BlueprintGeneratedClass /Game/PrimalEarth/CoreBlueprints/Projectiles/ProjArrow_Tranq_Bolt.ProjArrow_Tranq_Bolt_C");
static UBlueprintGeneratedClass* DmgTypeProjectileWithImpactFXTranqClass = (UBlueprintGeneratedClass*)Globals::FindClass("BlueprintGeneratedClass /Game/PrimalEarth/CoreBlueprints/DamageTypes/DmgType_ProjectileWithImpactFX_Tranq.DmgType_ProjectileWithImpactFX_Tranq_C");
AShooterProjectile* projCDO = static_cast<AShooterProjectile*>(ProjArrowTranqBoltClass->GetDefaultObject(true));
UDamageType* dmgTypeCDO = reinterpret_cast<UDamageType*>(DmgTypeProjectileWithImpactFXTranqClass->GetDefaultObject(true));
if (projCDO == nullptr || dmgTypeCDO == nullptr) return;
FProjectileWeaponData& weaponConfig = *GetNativePointerField<FProjectileWeaponData*>(projCDO, "AShooterProjectile.WeaponConfig");
weaponConfig.DirectDamage = damage;
float& damageTorpidityIncreaseMultiplier = *GetNativePointerField<float*>(dmgTypeCDO, "UShooterDamageType.DamageTorpidityIncreaseMultiplier");
damageTorpidityIncreaseMultiplier = 10.0;
TArray<FDamagePrimalCharacterStatusValueModifier>& damageCharacterStatusValueModifiers = *GetNativePointerField<TArray<FDamagePrimalCharacterStatusValueModifier>*>(dmgTypeCDO, "UShooterDamageType.DamageCharacterStatusValueModifiers");
FDamagePrimalCharacterStatusValueModifier& mod = damageCharacterStatusValueModifiers[0];
mod.DamageMultiplierAmountToAdd = 10.0;c++
float Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (_this->TargetingTeamField() < 10000) // wild dinos
{
FString targetName, damageCauserName, eventInstigatorName, weaponName;
FName damageTypeFName;
_this->GetHumanReadableName(&targetName);
DamageCauser->GetHumanReadableName(&damageCauserName);
EventInstigator->GetHumanReadableName(&eventInstigatorName);
DamageEvent->DamageTypeClassField().uClass->GetDefaultObjectName(&damageTypeFName);
if (EventInstigator->IsA(AShooterPlayerController::GetPrivateStaticClass()))
{
AShooterPlayerController* shooterPlayerController = static_cast<AShooterPlayerController*>(EventInstigator);
AShooterWeapon* weapon = shooterPlayerController->GetPlayerCharacter()->CurrentWeaponField();
if (weapon != nullptr) weapon->GetHumanReadableName(&weaponName);
}
SendConsoleMessageToAll("{} damage of type {} to {} from {} by {} using {}", Damage, damageTypeFName.ToString().ToString(), targetName.ToString(), damageCauserName.ToString(), eventInstigatorName.ToString(), weaponName.ToString());
}
return APrimalCharacter_TakeDamage_original(_this, Damage, DamageEvent, EventInstigator, DamageCauser);
} ::Tick happening on a single thread?Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser), but EventInstigator and DamageCauser is nullptr when dino is killed using admin rifle Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser), but EventInstigator and DamageCauser is nullptr when dino is killed using admin rifle Hook_APrimalCharacter_TakeDamage(APrimalCharacter* _this, float Damage, FDamageEvent* DamageEvent, AController* EventInstigator, AActor* DamageCauser), but EventInstigator and DamageCauser is nullptr when dino is killed using admin rifle ServerRequestDestroyTargetc++
`FCustomItemData ItemData;
if (!cryopod->GetCustomItemData(FName("Dino", EFindName::FNAME_Find), &ItemData)) {
return;
}CustomDataBytes.ByteArrays which is not as easy. The game uses this byte array to recreate the dino by calling APrimalDinoCharacter::SpawnFromDinoData which in turn uses UObjectSerializer::DeSerializeObject to deserialize the data and spawn the dino.APrimalDinoCharacter::SpawnFromDinoData at 0 0 0 coords, get it IDs and destroy 
AShooterGameMode with Hook_AShooterGameMode_IsPlayerAllowedToJoinNoCheck, but it returns true there. At what point does the server disconnect the player?AShooterGameMode with Hook_AShooterGameMode_IsPlayerAllowedToJoinNoCheck, but it returns true there. At what point does the server disconnect the player? AGameSession::ApproveLogin references that string. It calls AGameSession::AtCapacity and shows that message if the result is non-zero. (edited)AGameSession::ApproveLogin references that string. It calls AGameSession::AtCapacity and shows that message if the result is non-zero. (edited)
thanks.
that is, if AtCapacity returned true, then it will write Server Full? (edited)virtual bool AtCapacityAGameSession::MaxPlayers and AGameSession::MaxSpectators. Calls IOnlineSession::GetNumConnectedPlayersExcludingAuthTokenAGameSession::MaxPlayers and AGameSession::MaxSpectators. Calls IOnlineSession::GetNumConnectedPlayersExcludingAuthToken
thank you. you've been very helpful. may I ask how you knew that?)
thank you. you've been very helpful. may I ask how you knew that?) AGameSession::MaxPlayers and AGameSession::MaxSpectators. Calls IOnlineSession::GetNumConnectedPlayersExcludingAuthToken 
s AllowPlayerToJoinNoCheck.
I think, before load mods call bool IsPlayerAllowedToJoinNoCheck` and if a player is not added to the AllowPlayerToJoinNoCheck.txt, the number of players is checked. If added, it is not executed. Previously, everything was fine, but now even if I added a player to the AllowPlayerToJoinNoCheck.txt, he can download mods, but when connected, he disconnected it with the error that he threw above "server full"AGameSession::AtCapacity with API, but have crash bool AtCapacity(bool bSpectator, FString* AuthToken) { return NativeCall<bool, bool, FString*>(this, "AGameSession.AtCapacity", bSpectator, AuthToken); }
GameState.hShooterGameServer.exe!AGameSession::AtCapacity() (0x00007ff6f72a8dab) + 11 bytes [f:\build\lostisland\engine\source\runtime\engine\private\gamesession.cpp:214]UNetConnection arg
char __fastcall AGameSession::AtCapacity(AGameSession *this, bool bSpectator, const FString *AuthToken, UNetConnection *Connection)c++
DECLARE_HOOK(AGameSession_AtCapacity, bool, AGameSession*, bool, const FString*, UNetConnection*);
bool Hook_AGameSession_AtCapacity(AGameSession* _this, bool bSpectator, const FString* AuthToken, UNetConnection* Connection)
{
return AGameSession_AtCapacity_original(_this, bSpectator, AuthToken, Connection);
}
c++
DECLARE_HOOK(AGameSession_AtCapacity, bool, AGameSession*, bool, const FString*, UNetConnection*);
bool Hook_AGameSession_AtCapacity(AGameSession* _this, bool bSpectator, const FString* AuthToken, UNetConnection* Connection)
{
return AGameSession_AtCapacity_original(_this, bSpectator, AuthToken, Connection);
} Fatal error!
VERSION: 357.18
ShooterGameServer.exe!AGameSession::AtCapacity() (0x00007ff737ad8dab) + 11 bytes [f:\build\lostisland\engine\source\runtime\engine\private\gamesession.cpp:214]
AdminFastCommands.dll!Hook_AGameSession_AtCapacity() (0x00007ff96387e3ae) + 0 bytes [C:\Projects\Plugins\AdminFastCommands\Hooks.cpp:11]
ShooterGameServer.exe!AGameSession::ApproveLogin() (0x00007ff737ad87e7) + 30 bytes [f:\build\lostisland\engine\source\runtime\engine\private\gamesession.cpp:121]
AdminFastCommands.dll!Hook_AGameSession_ApproveLogin() (0x00007ff96387e4a0) + 9 bytes [C:\Projects\Plugins\AdminFastCommands\Hooks.cpp:18]
ShooterGameServer.exe!AShooterGameSession::ApproveLogin() (0x00007ff7363a0a60) + 359 bytes [f:\build\lostisland\projects\shootergame\source\shootergame\private\shootergamesession.cpp:566]
ShooterGameServer.exe!AGameMode::PreLogin() (0x00007ff737ad04c2) + 39 bytes [f:\build\lostisland\engine\source\runtime\engine\private\gamemode.cpp:1289]
ShooterGameServer.exe!AShooterGameMode::PreLogin() (0x00007ff73630feb2) + 0 bytes [f:\build\lostisland\projects\shootergame\source\shootergame\private\shootergamemode.cpp:2962]
...
bool __fastcall AGameSession::AtCapacity(AGameSession *this, bool bSpectator, const FString *AuthToken, UNetConnection *Connection)

bool Hook_AGameSession_AtCapacity(AGameSession* _this, bool bSpectator, const FString* AuthToken, UNetConnection* Connection)
{
auto Result = AGameSession_AtCapacity_original(_this, bSpectator, AuthToken, Connection);
Log::GetLog()->info("AGameSession::AtCapacity called!");
Log::GetLog()->info("Result: {}", Result);
return Result;
}if (!dinoConf["AttackSpeedModifiers"].empty())
{
for (auto &element : dinoConf["AttackSpeedModifiers"])
{
_this->AttackInfosField()[element["Index"].get<int>()].RiderAttackIntervalField() = element["AttackSpeed"].get<float>();
}
} auto& attacks = dino->AttackInfosField();
Log::GetLog()->info("attacks: {}", attacks.Num());
for (FDinoAttackInfo& attack : attacks)
{
Log::GetLog()->info("attack stamina cost: {}", attack.StaminaCostField());
}
i get only the first value, others contain bullshit auto& attacks = dino->AttackInfosField();
Log::GetLog()->info("attacks: {}", attacks.Num());
for (FDinoAttackInfo& attack : attacks)
{
Log::GetLog()->info("attack stamina cost: {}", attack.StaminaCostField());
}
i get only the first value, others contain bullshit auto& attacks = dino->AttackInfosField();
read from PDB
attacks.Num()
Is accurate (read from PDB)
Log::GetLog()->info("attack stamina cost: {}", attack.StaminaCostField());
read from PDB, accurate as long as attack is accuratefor (FDinoAttackInfo& attack : attacks)
{
}
is the iterator version of
for(int i = 0; i < attacks.Num(); ++i)
{
}auto& attacks = dino->AttackInfosField();
is TArray and is not read/sized correctly thenattacks[n]
n > 0
can produce garbagefor(int i = 0; i < attacks.Num(); ++i)
{
auto this_attack = attacks[i];
}
where
attacks[i]
produces
*(attacks + i)
which is actually
result = *(address of attacks + sizeof(FDinoAttackInfo) * i) (edited)sizeof(FDinoAttackInfo)
is not accuratec++
static int FDinoAttackInfoStructSize = GetStructSize<FDinoAttackInfo>();
auto& attacks = dino->AttackInfosField();
Log::GetLog()->info("attacks: {}", attacks.Num());
auto ptr = reinterpret_cast<char*>(&attacks[0]);
for (int i = 0; i < attacks.Num(); i++)
{
auto attack = reinterpret_cast<FDinoAttackInfo*>(ptr + i * FDinoAttackInfoStructSize);
Log::GetLog()->info("attack stamina cost: {}", attack->StaminaCostField());
}c++
static int FDinoAttackInfoStructSize = GetStructSize<FDinoAttackInfo>();
auto& attacks = dino->AttackInfosField();
Log::GetLog()->info("attacks: {}", attacks.Num());
auto ptr = reinterpret_cast<char*>(&attacks[0]);
for (int i = 0; i < attacks.Num(); i++)
{
auto attack = reinterpret_cast<FDinoAttackInfo*>(ptr + i * FDinoAttackInfoStructSize);
Log::GetLog()->info("attack stamina cost: {}", attack->StaminaCostField());
} 
target_include_directories(${PROJECT_NAME} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/ARK-Server-API/version/Core/Public;"
"${CMAKE_CURRENT_SOURCE_DIR}/.;"
"${CMAKE_CURRENT_SOURCE_DIR}/libs;"
"${CMAKE_CURRENT_SOURCE_DIR}/libs/mysql;"
ECC_WorldDynamic or ECC_WorldStatic probably.
1c++
API::Timer::Get().DelayExecute()didn't seem to run on some maps, but on others it ran fine.
I've changed up my code to hook onto "AShooterGameMode.InitGame" and that seems to have fixed it.. i think lol.
Just wondered if anybody would happen to know anything about that. From what i read from checking this discord (albeit briefly) DelayExecute is supposed to run when the server is ready anyway right?c++
AActor* actor = ...;
FVector pos;
FString biomeZoneName = "";
actor->RootComponentField()->GetWorldLocation(&pos);
auto GetBiomeZoneVolume = [](UWorld* World, const FVector* Location) { return NativeCall<ABiomeZoneVolume*, UWorld*, const FVector*>(nullptr, "ABiomeZoneVolume.GetBiomeZoneVolume", World, Location); };
ABiomeZoneVolume* biome = GetBiomeZoneVolume(ArkApi::GetApiUtils().GetWorld(), &pos);
if (biome != nullptr)
{
biomeZoneName = (*GetNativePointerField<FString*>(biome, "ABiomeZoneVolume.BiomeZoneName"));
} (edited)c++
this->config.orderReceivedText = FString(startup_config["my_text"].get<std::string>());
//debugging stuff...
std::ofstream debugUTF(ArkApi::Tools::GetCurrentDir() + "/ArkApi/Plugins/MyPlugin/debug.txt");
debugUTF << this->config.orderReceivedText.ToString();
debugUTF.close();
//debugging stuffc++
this->config.orderReceivedText = FString(startup_config["my_text"].get<std::string>());
//debugging stuff...
std::ofstream debugUTF(ArkApi::Tools::GetCurrentDir() + "/ArkApi/Plugins/MyPlugin/debug.txt");
debugUTF << this->config.orderReceivedText.ToString();
debugUTF.close();
//debugging stuff API::Tools::Utf8EncodeAPI::Tools::Utf8Encode c++
std::shared_ptr<int> new_customer = std::make_shared<int>(5);
this->customers.push_back(new_customer);bool APrimalDinoCharacter::CanFly (edited)std::chrono::milliseconds delayTime(430);
auto startTime = std::chrono::high_resolution_clock::now();
while (true) {
auto currentTime = std::chrono::high_resolution_clock::now();
auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - startTime);
if (elapsedTime >= delayTime) {
// Function
break;
}
}std::chrono::milliseconds delayTime(430);
auto startTime = std::chrono::high_resolution_clock::now();
while (true) {
auto currentTime = std::chrono::high_resolution_clock::now();
auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - startTime);
if (elapsedTime >= delayTime) {
// Function
break;
}
} void Hook_AShooterWeapon_BPFiredWeapon(AShooterWeapon* _this)
{
Tools::Timer::Get().DelayExec(shooted, 450, true, ArkApi::GetApiUtils().GetSteamIdFromController(_this->AssociatedPrimalItemField()->OwnerInventoryField()->GetOwnerController()));
AShooterWeapon_BPFiredWeapon_original(_this);
}1000 / tpsif() inside update to check for next execution and if it is higher than required then force update it.
if(function && now + std::chrono::milliseconds((int)round(deltatime * 1000)) > function->execTime && function->callback) (edited)whatever::me->key_partsc++
target->ServerSendChatMessage(&this->message, EChatSendMode::LocalChat);
As you can see it sends a message in the local chat and i wanted to know if there is a way to send from the server to send a Private message to the player and if it isn't the case is the localChat only visible for the player im targeting? (edited)template <typename T, typename... Args>
FORCEINLINE void SendChatMessage(AShooterPlayerController* player_controller, const FString& sender_name, const T* msg,
Args&&... args)
{
if (player_controller)
{
const FString text(FString::Format(msg, std::forward<Args>(args)...));
FChatMessage chat_message = FChatMessage();
chat_message.SenderName = sender_name;
chat_message.Message = text;
player_controller->ClientChatMessage(chat_message);
}
}
from api utils, sends a private chat message UWorld* world = ArkApi::GetApiUtils().GetWorld();
FString tek_path = FString("Blueprint'/Game/PrimalEarth/Structures/StorageBox_TekShield.StorageBox_TekShield'");
UClass* structure_class = UVictoryCore::BPLoadClass(&tek_path);
if (!structure_class)
Log::GetLog()->critical("There was an error while processing new structures");
AActor* new_actor = world->SpawnActor(structure_class, &loc, &rot, ¶ms);
Tek shield wont spawn, a metal foundation works. Is there any secret to spawn a tek shield?c++
FVector SpawnLocation(0, 0, 0);
FRotator SpawnRotation(0, 0, 0);
AShooterPlayerController* god = static_cast<AShooterPlayerController*>(ArkApi::GetApiUtils().GetShooterGameMode()->SpawnPlayerController(&SpawnLocation, &SpawnRotation));c++
FVector SpawnLocation(0, 0, 0);
FRotator SpawnRotation(0, 0, 0);
AShooterPlayerController* god = static_cast<AShooterPlayerController*>(ArkApi::GetApiUtils().GetShooterGameMode()->SpawnPlayerController(&SpawnLocation, &SpawnRotation)); ArkApi::GetApiUtils().GetWorld()->GetFirstPlayerController()APlayerController::ConsoleCommandUShooterCheatManager has some functions that are executed by commands without the need of players, might do what you wantc++
p->bIsAdmin() = true;
p->ConsoleCommand(&result, &fcommand, false);
p->bIsAdmin() = false;structure->PlacedOnFloorField(), and floor->StructuresPlacedOnFloorField()structure->PlacedOnFloorField(), and floor->StructuresPlacedOnFloorField() Firstly, the first onboarding question forces me to say I want to play on one or more games servers,Secondly, what happens when all those end users start saying "yes" to the development option and we start getting endless noise from end users instead of the clean dev-only environment we have now?Onboarding system you can hide all channels and only show API channels.onboarding and hide those channels to avoid confusion.onboarding and hide those channels to avoid confusion. Search feature.(Are all channels here still accessible to new users? natsu was saying earlier that he can't see the intermediate channels. And I don't see the role selection channel anymore)API::Requests classAPI::Requests::Get().Create[Get/Post]Request();"Requests.h" (edited)"Requests.h" (edited)API::Requests::Get()
1
1&ReqCllback (edited){ headerString }{ headerString }
Thank youFString* Hook_APlayerController_ConsoleCommand(APlayerController* _this, FString* result, FString* Cmd, bool bWriteToLog)
{
std::cout << Cmd->ToString() + "\n";
if (Cmd->ToString() == "fly") {
FString rt = "walk";
return &rt;
}
return APlayerController_ConsoleCommand_original(_this, result, Cmd, bWriteToLog);
}
Cmd->Empty()Cmd->Empty() void onTest(AShooterPlayerController* player, FString*, EChatSendMode::Type)
{
const int subtractPercentage = 10;
if (!player)return;
auto pCharacter = player->GetPlayerCharacter();
if (!pCharacter)return;
auto status = pCharacter->GetCharacterStatusComponent();
if (!status)return;
int level = status->GetCharacterLevel();
float currentEXP = status->ExperiencePointsField();
if (level <= 1 || currentEXP <= 0)return;
float lastEXP = status->GetExperienceRequiredForPreviousLevelUp();
int exLevel = status->GetExtraCharacterLevel();
float newEXP = currentEXP - (currentEXP * ((float)subtractPercentage / 100));
status->ExperiencePointsField() = newEXP;
while (newEXP < lastEXP || exLevel>0) {
status->SetExtraCharacterLevel(exLevel - 1);
resetPlayerLevelUpPoints(status);
status->RescaleAllStats();
lastEXP = status->GetExperienceRequiredForPreviousLevelUp();
exLevel = status->GetExtraCharacterLevel();
}
ArkApi::GetApiUtils().SendChatMessage(player, CHAT_MESSAGE_NAME, L"test");
}void onTest(AShooterPlayerController* player, FString*, EChatSendMode::Type)
{
const int subtractPercentage = 10;
if (!player)return;
auto pCharacter = player->GetPlayerCharacter();
if (!pCharacter)return;
auto status = pCharacter->GetCharacterStatusComponent();
if (!status)return;
int level = status->GetCharacterLevel();
float currentEXP = status->ExperiencePointsField();
if (level <= 1 || currentEXP <= 0)return;
float lastEXP = status->GetExperienceRequiredForPreviousLevelUp();
int exLevel = status->GetExtraCharacterLevel();
float newEXP = currentEXP - (currentEXP * ((float)subtractPercentage / 100));
status->ExperiencePointsField() = newEXP;
while (newEXP < lastEXP || exLevel>0) {
status->SetExtraCharacterLevel(exLevel - 1);
resetPlayerLevelUpPoints(status);
status->RescaleAllStats();
lastEXP = status->GetExperienceRequiredForPreviousLevelUp();
exLevel = status->GetExtraCharacterLevel();
}
ArkApi::GetApiUtils().SendChatMessage(player, CHAT_MESSAGE_NAME, L"test");
} UPrimalPlayerData::SavePlayerData(UWorld *)
on the players UPrimalPlayerData after you made the changes. pCharacter->GetPlayerData()->MyDataField()->MyPersistentCharacterStatsField()->CharacterStatusComponent_ExperiencePointsField() = newEXP;
pCharacter->GetPlayerData()->MyDataField()->MyPersistentCharacterStatsField()->CharacterStatusComponent_ExtraCharacterLevelField() = exLevel - 1;FieldArray<char, 12> CharacterStatusComponent_NumberOfLevelUpPointsAppliedField() { return { this, "FPrimalPersistentCharacterStatsStruct.CharacterStatusComponent_NumberOfLevelUpPointsApplied" }; }conditional_variable and have a blocking wait until the callback executes. (edited)
LOG->info("steam_id: {}", steam_id);LOG->info("steam_id: {}", steam_id); __try __except__try __except try catch isn't the same as __try __exceptif(!player_controller){
log("controller invalid");
return orignal_func(_tthis and stuff);
}
// and so on for all pointers
so you get a first feeling what is even valid and useable in the hook. If its really only for checking at first and you do nothing with the pointer you could also remove the return. (edited)FString crazyString = FString("aaäßßüüöö");
ArkApi::GetApiUtils().SendNotification(playerController, FColor(53, 194, 17), 1.6, 10,nullptr, *crazyString); std::wstring Utf8Decode(const std::string& str)
{
if (str.empty())
return std::wstring();
const int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.size()), nullptr, 0);
std::wstring wstr(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.size()), wstr.data(), size_needed);
return wstr;
}API::Tools::Utf8DecodeSetConsoleOutputCP(CP_UTF8); const int MinFoundations = 3200;
UWorld* world = ArkApi::GetApiUtils().GetWorld();
TArray<AActor*> new_actors;
TArray<AActor*> actors_ignore;
TArray<TEnumAsByte<enum EObjectTypeQuery>> types;
UKismetSystemLibrary::SphereOverlapActors_NEW(world, player_controller->RootComponentField()->RelativeLocationField(),
static_cast<float>((MinFoundations * 300)),
&types,
APrimalStructure::GetPrivateStaticClass(),
&actors_ignore,
&new_actors);
for (AActor* actor : new_actors) {
APrimalStructure* structure = static_cast<APrimalStructure*>(actor);
float TribeID = structure->TargetingTeamField();
Log::GetLog()->info("");
} if (!stryder) {
comp->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
}
else {
comp->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
void Hook_UPrimalInventoryComponent_ServerViewRemoteInventory(UPrimalInventoryComponent* _this, AShooterPlayerController* ByPC)
{
if (CheckActorActionInventory(_this, ByPC))
{
_this->ServerCloseRemoteInventory(ByPC);
return;
}
UPrimalInventoryComponent_ServerViewRemoteInventory_original(_this, ByPC);
}AActor* Hook_ChoosePlayerStart_Implementation(AShooterGameMode* _this, AController* Player)
{
int PlayersLevel = 1;
UPrimalCharacterStatusComponent* char_component = static_cast<APrimalCharacter*>(Player->CharacterField())->MyCharacterStatusComponentField();
if (char_component != nullptr)
{
PlayersLevel = char_component->BaseCharacterLevelField() + char_component->ExtraCharacterLevelField(); // Players Level
LOG->info("Hook_ChoosePlayerStart_Implementation->PlayersLevel:" + PlayersLevel);
char_component->UpdateStatusValue(EPrimalCharacterStatusValue::Type::Health, 5, false);// Health
char_component->UpdateStatusValue(EPrimalCharacterStatusValue::Type::Water, 5, false);// Water
char_component->UpdateStatusValue(EPrimalCharacterStatusValue::Type::Weight, 5, false);// Weight
}
return ChoosePlayerStart_Implementation_original(_this, Player);
}UPrimalCharacterStatusComponent* char_component = static_cast<APrimalCharacter*>(Player->CharacterField())->MyCharacterStatusComponentField();
After the role was created, this line of code caused the server to crash.UPrimalCharacterStatusComponent* char_component = static_cast<APrimalCharacter*>(Player->CharacterField())->MyCharacterStatusComponentField();
After the role was created, this line of code caused the server to crash. static_cast<APrimalCharacter*>(Player->CharacterField())->MyCharacterStatusComponentField();
If the problem is caused by null, it is most likely that the target converted to APrimalCharacter here has not been obtained.APlayerController::ClientTravel() that sort of get the job done. The player is sent to the other server, but some things are in a bad state (e.g., no auth token). I figure it's (at least partially) because some necessary online session management is getting skipped over. I'm not sure if it's possible to handle it all from the server though, looks like the client might need to initiate some calls to do it properly. Haven't spent a ton of time on it, but I'd be curious if anyone else has accomplished this (or knows for a fact that it's not possible). (edited)APlayerController::ClientTravel() the client gets connected to the other server and is able to play, but there are a few issues. UE's ClientTravel() can be called from the server to the client, but at least in ARK it seems to only ever be called locally on the client (in addition to some other calls we can't do directly on the server).c++
// Replace the IP and port as appropriate
FString cmd = "open 127.0.0.1:7777";
spc->ClientRunLocalConsoleCommand(&cmd, false);
But got the same behavior as just calling APlayerController::ClientTravel() directly (at least with the Steam client, didn't try Epic)static_cast<AShooterPlayerController>(my_player_controller);* to the end of AShooterPlayerController (edited)static_cast<AShooterPlayerController>(my_player_controller);