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
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)#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 externals
libcurl.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_HandleNewPlayer
void 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 SteamIdBannedMapField
if (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 extracted
ERROR 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 1
ERROR 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 2
AUTO_INCREMENT
ERROR 1101 (42000) at line 1: BLOB, TEXT, GEOMETRY or JSON column 'Groups' can't have a default value
ERROR 1273 (HY000) at line 1: Unknown collation: 'NOCASE'
COLLATE NOCASE
ERROR 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 found
if (_this->TargetingTeamField() > 10000 && character != nullptr && character && character->IsA(APrimalDinoCharacter::GetPrivateStaticClass()))
?if (EventInstigator && EventInstigator->CharacterField())
{
//Do the things
}
return original; //if EventInstigator = NULL
if (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);
}
GetOwnerController
if (_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() < 10000
if (_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 expression
void 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 compiled
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);
}
}
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 externals
TeamSelector.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 externals
void 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);
}
APrimalStructureClaimFlag::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?StaticClassField
void 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.iniSeverity 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=20
FString result;
FString command = FString::Format(L"ScriptCommand tcsar addarctotal steamid={} points={}", SteamID, Points);
player->ConsoleCommand(&result, &command, true);
APrimalDinoCharacter* _this
TargetingTeamField
- 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?TotalBans
ArkApi::GetApiUtils().GetShooterGameMode()->KickPlayerController(shooter_pc, &KickReason);
takes AShooterPlayerController and FStringhook DoMate
call domate_original()
call updatenextallowedmatingtime
ArkApi::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)AShooterPlayerController* 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_49
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");
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_0
GetAllBuffs
?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
*.user
APrimalCharacter_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
static 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 range
stmt = 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*);
cheat 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%5D
ComponentMap 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 deathcontroller->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->AddItem
player_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* dino
Hook_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_WARNING
Globals::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/AccessorFunc
namespace 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 notificationsAutoPluginsReload
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)UPrimalCharacterStatusComponent* defaultComp = _this->GetDefaultCharacterStatusComponent();
Actor.h
c++
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 UActorComponent
UPrimalCharacterStatusComponent* 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() = false
if (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 long
unordered_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 Flyers
having serious problems. (edited)GetShooterController
GetOwnerController()
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 world
UKismetSystemLibrary::SphereOverlapActors_NEW()
(edited)UVictoryCore::SphereOverlapFast
const 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_actors
UKismetSystemLibrary::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 area
ArkApi::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.h
error 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 externals
C:\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());
GetPrivateStaticClass
APrimalStructureTurret
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 install
C:\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 func
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);
// 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* msg
T
T
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 int
API::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_WARNING
c++
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.__fastcall
Load()
:
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 bool
AShooterPlayerController*, FString*, EChatSendMode::Type
is the actual argsvoid Commands::ReloadConfig(APlayerController* player_controller, FString*, bool)
{
Log::GetLog()->debug("Reloading Config");
NextConfig<ConfigBody>::Get().Load();
}
AddChatCommand
AddConsoleCommmand
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 externals
int& 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_Implementation
void 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%5D
for (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 ?AShooterPlayerController::StaticClass()->GetDefaultObject(true);
NativeCall
use __fastcall*
?__fastcall
x)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)Patch Notes: v310.29 - 15/4/2020
- Fixed multiple server crashes
might be a reason, hehc++
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/bYDK5IJphPUUnknownModule!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: 1114
Log::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::AddArkTributeItem
UPrimalLocalProfile::AddArkTributePlayerData
is for player characterArkItem
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);
}
.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"
#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
parameterC++
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();
PrimalGameDataOverrideField
PrimalGameDataField
cheat GFI bed_modern 1 0 0
cheat giveitemnum 128 1 0 0
giveitemnum
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*
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 — 76561198063581674
18446744073709551615
/**
* \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;
}
FUniqueNetIdSteam
FUniqueNetId
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;
}
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;
}
111
111
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;
}
FUniqueNetIdRepl
FUniqueNetIdRepl& 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
000000100010000000000000000000100111100010001100101010111110110
Example 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.dll
version.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!");
#endif
DEBUG_PLUGIN
), but will be useful.d:\programs\projects\
etc when we don't even run a D:
drive version.dll
DECLARE_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 withDECLARE_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_HOOK
void 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 AActor
func_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)8997470993440060352
8218251314968812020
DECLARE_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.ProcessRCONPacket
ShooterCharacter
, but the PlayerPawnTest
is all in BPScript.FName(L"your string here", EFindName::FNAME_Add, false);
TerminateThread
and keeping a list of active timersGameThread::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)parameters
callBlueprintFunction(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 EelBoss
struct 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 commandTEnumAsByte<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)%.2f
int 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)APrimalWorldSettings
. 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 bytesnew
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 itProcessEvent
UFunction
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 nullptrUPrimalPlayerData
to UPrimalPlayerDataBP_Base
TArray<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)bool 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: PrimalDinoCharacter
FString GetBlueprint(UObjectBase* object)
{
if (object != nullptr && object->ClassField() != nullptr)
{
FString path_name;
object->ClassField()->GetDefaultObject(true)->GetFullName(&path_name, nullptr);
if (int find_index = 0; path_name.FindChar(' ', find_index))
{
path_name = "Blueprint'" + path_name.Mid(find_index + 1,
path_name.Len() - (find_index + (path_name.EndsWith(
"_C", ESearchCase::
CaseSensitive)
? 3
: 1))) + "'";
return path_name.Replace(L"Default__", L"", ESearchCase::CaseSensitive);
}
}
return FString("");
}
??
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 : AActor
GetAllBuffs
, 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;
}
void*
unpacker using run-time reflection datastd::any
that just makes a char[]
the size of the propertyany cast
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);
}
KismetSystemLibrary
BPExec
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 levelingstd::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 Hunt
Use 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 pluginsstruct 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 resharper
std::cout << a << b << b
std::cout
sscout
#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); }
x
x
my_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.plus
success: 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} 5000
config.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_Implementation
Hook_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);
}
Localhost
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.Structure->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.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::CanStartMission
AMissionType::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::SpawnDino
DECLARE_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.- (329.45)
so you could use thatBuyer
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__
AMissionDispatcher
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); }
}
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.AShooterPlayerController* 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. std::any
and doing
hookableFunction<RT, VA, A...>& test()
{
return std::any_cast<hookableFunction<RT, VA, A...>&>(hookable);
}
hook
for(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 var
FORCEINLINE 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);
API::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, jsObject
jsObject
is either the previously defined type, a string, or a primitiveDictionary<string, Object>
map<std::string, std::any>
json.hpp
headerc++
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. if (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?APrimalDinoCharacter_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?UWorld::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)FString 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)]
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
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 V315
IOnlineSubsystem::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? UFunction* 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 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);
}
#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));
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.54
URCONServer
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();
UnicodeRcon
inventoryComp->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_Implementation
AShooterPlayerState::ServerRequestCreateTribe_Implementation
AShooterPlayerState::ServerRequestCreateTribe_Implementation
PlayerControllerListField
Blueprint'/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 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::CreateFromBytes
UPrimalItem::CreateFromBytes
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?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.cppbUnlocked
, 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_file
hook
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)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
}
resources
when 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. 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. Resources
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);
FUniqueNetIdEOS
Developer
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%
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.ClampItemStats=true
DestroyTamesOverLevelClamp=450
ItemStatClamps[1]=19800
ItemStatClamps[3]=19800
ClampItemStats=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. Game.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. c++
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.Fatal 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
?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?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->AddCustomFolder
ServerNotifyEditText
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)StructureSpawnPointMaxDistance
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? auto_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) UPrimalGlobals::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 ... thatProcessEvent
ProcessEvent
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 needCallFunction()
, 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 FOutParmRec
s 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 FOutParmRec
s 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, NoDestructor
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"); }
};
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.dll
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) 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 allowed
UFunction::InternalIndexField
throwing an intellisense issue, is now fixed! lolError (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_Implementation
AShooterPlayerController->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::ActorHasLineOfSight
AActor** 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); }
UVictoryCore
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 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 loaded
plugins.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). UProperty
s and UFunction
s. 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 Server
BPServerHandleNetExecCommand
DECLARE_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 Server
BPServerHandleNetExecCommand
DECLARE_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 catch
nickname, 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_Implementation
AShooterPlayerController::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)AActor* 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);
}
FUniqueNetIdSteam
FUniqueNetIdUInt64
IOnlinePlatformData
doesn't seem to give anything usable at alluint64 steamid = static_cast<FUniqueNetIdUInt64*>(UniqueId->Get())->UniqueNetIdField();
(edited)16140901064495857664
AShooterGameMode.PostLogin
AShooterGameMode.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 -Wait
Start-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.pdb
pretty
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.txt
class 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::ServerUseInventoryItem
UPrimalHarvestingComponent::GiveHarvestResource
UPrimalHarvestingComponent::GiveHarvestResource
Use
Using
int 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*
void 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 --recursive
UpdateComponentToWorld()
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 + FemaleMatingRangeAddition
AShooterGameMode::SaveWorld
TSharedPtr<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_Implementation
A-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_bool
auto 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 *this
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)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.txt
c++
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_WINDOW
start $C -ForceAllowCaveFlyers -useautoreporter -serverkey=$id -stdout >> launch.log 2>&1
DETACHED_PROCESS
or CREATE_NEW_CONSOLE
void 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 kernel32
kernel32
are safe-ish in dllmain
c:\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 ServerRequestDestroyTarget
c++
`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)virtual bool AtCapacity
AGameSession::MaxPlayers
and AGameSession::MaxSpectators
. Calls IOnlineSession::GetNumConnectedPlayersExcludingAuthToken
AGameSession::MaxPlayers
and AGameSession::MaxSpectators
. Calls IOnlineSession::GetNumConnectedPlayersExcludingAuthToken
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.c++
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 stuff
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 stuff
API::Tools::Utf8Encode
API::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 / tps
if()
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::ConsoleCommand
UShooterCheatManager
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()
&ReqCllback
(edited){ headerString }
{ headerString }
FString* 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 __except
if(!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::Utf8Decode
SetConsoleOutputCP(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);