Guild icon
Ark Server Api
── ( Intermediate ) ── / 【💬】ᴅɪꜱᴄᴜꜱꜱɪᴏɴ-ɪ
Avatar
CaptainPeeples 2/21/2021 7:58 PM
hello all
7:59 PM
looking for help with this.. pretty simple really
7:59 PM
This plugin is now free and open sourced. All future updates will still be maintained by me. Be sure to join the Discord: barnwellrd's ArkApi Plugin Discord! Features: Protects new player STRUCTURES from damage Protects new player structures...
7:59 PM
need to know if I can get it to use a shared data base like permissions does
Avatar
jraServerAPI 5/18/2021 4:07 PM
@Lethal I've been searching all over but I'm unable to figure out how you got discord to display colors on a single line, like you do in your tlr plugin.. Can you point me in some direction as to how you figured this one out? I would like to use colors too.
Avatar
Avatar
jraServerAPI
@Lethal I've been searching all over but I'm unable to figure out how you got discord to display colors on a single line, like you do in your tlr plugin.. Can you point me in some direction as to how you figured this one out? I would like to use colors too.
A guide to Markdown on Discord. GitHub Gist: instantly share code, notes, and snippets.
Avatar
jraServerAPI 5/18/2021 4:19 PM
Yes I've seen these already, but these are all multi-line examples. I'm trying to figure out how it's done with one line. Displaying multiple colors on one line
4:20 PM
unless i'm completely blind
4:20 PM
which is also possible 😂
Avatar
Could look at md (markdown)
4:25 PM
Avatar
jraServerAPI 5/18/2021 4:44 PM
Ahh okay, i see now
4:44 PM
thank you
Avatar
Avatar
jraServerAPI
Ahh okay, i see now
Ya, it uses md for the entries
Avatar
jraServerAPI 6/4/2021 11:25 PM
Does anyone have the (new) Creature ID list for Genesis 2 yet? It's not published on the wiki yet. (edited)
Avatar
jraServerAPI 6/5/2021 12:12 AM
thank you @Lethal , I'm talking about the "Dino name tags" i guess they are called in the wiki. This is for the Cuddle plugin.
12:12 AM
Avatar
Those either you get them with a plugin to output them, or wait half a year for the devkit release
Avatar
jraServerAPI 6/5/2021 12:14 AM
figured as much.. do we have a utility plugin just for these matters?
Avatar
Hmm, not that I know of
Avatar
jraServerAPI 6/5/2021 12:14 AM
i can slap one together
12:14 AM
wait.. does the blink gun give you that info?
12:14 AM
hmmm
Avatar
Maybe
Avatar
jraServerAPI 6/5/2021 12:14 AM
i'll check it out
Avatar
jraServerAPI 6/5/2021 12:35 AM
that's a no, on the blink gun PepeHands
Avatar
jraServerAPI 6/5/2021 12:57 AM
I figured it out, it was quite easy. c++ FString dinoNamefieldClassName; dino->DinoNameTagField().ToString(&dinoNamefieldClassName); Log::GetLog()->info("NAME: {}", dinoNamefieldClassName.ToString()); Genesis 2 - Cuddle Plugin "Maewing":{ "CuddleIntervalTime":30, "CuddleIncreasePercent":0.5 }, "Lionfish Lion":{ "CuddleIntervalTime":30, "CuddleIncreasePercent":0.5 }, "TekWyvern":{ "CuddleIntervalTime":30, "CuddleIncreasePercent":0.5 }, "Astrodelphis":{ "CuddleIntervalTime":30, "CuddleIncreasePercent":0.5 } (edited)
Avatar
substitute 6/5/2021 1:27 AM
@jraServerAPIif you want bonus points
1:27 AM
you can add to the wiki :)
Avatar
jraServerAPI 6/5/2021 2:08 AM
Hmm how does one go about that? Is it on the arkapi website? I don't have the ARK role on the website, I can't post or change plugins..I did request the role/permissions though.. still waiting on that lol... 👴 (edited)
Avatar
jraServerAPI 6/18/2021 2:03 AM
Does anyone know how to update/refresh the display on tek storage after you've pulled some items from it? I tried a few things but it's not changing for me.
Avatar
jraServerAPI 6/18/2021 2:12 AM
I figured it out: item->InventoryRefreshCheckItem(); item->UpdatedItem(false); this updated the display for the tek storage. (edited)
Avatar
jraServerAPI 6/18/2021 3:01 AM
I'm trying to get the Crafting Requirements of an ascendant stego blueprint, but the BaseCraftingResourceRequirementsField() values are much to low (says 200 wood, but it actually needs 17,154 wood). I checked in CustomResourceRequirementsField() but that was empty. Does anyone know where the real numbers are stored?
Avatar
That number is correct
3:13 AM
The value for a blueprint is derived from the base value and various stats on the blueprint
Avatar
jraServerAPI 6/18/2021 3:40 AM
is there a formula that gets me to 17,154?
Avatar
jraServerAPI 6/18/2021 4:27 AM
I think I figured it out. The current updated quantities are stored: c++ TArray<unsigned short>actualCounts = currentItem->CraftingResourceRequirementsField(); This array has all the correct requirement values I was looking for. (edited)
Avatar
jraServerAPI 11/1/2021 1:12 AM
Is there anything in the API that determines if a player has gone idle or not? thx
Avatar
jraServerAPI 11/2/2021 3:41 AM
Avatar
Avatar
jraServerAPI
Is there anything in the API that determines if a player has gone idle or not? thx
There is not afaik
Avatar
jraServerAPI 11/2/2021 4:58 AM
thank you for the response kind sir 🙂
Avatar
Avatar
jraServerAPI
Is there anything in the API that determines if a player has gone idle or not? thx
on the game mode there's something called "KickIdlePlayersPeriod", inside ShooterPlayerController in the function TickActor the game does an idle check by looking at the time since ShooterPlayerController->LastLargeMoveTime, time since ShooterPlayerController->LastNotUnriddenDinoTime, and time since ShooterPlayerController->LastMultiUseInteractionTime and compares them to the KickIdlePlayersPeriod
Avatar
jraServerAPI 11/2/2021 6:22 AM
1136_ouch_my_pp
Avatar
and to check against players that arent spawned in they check against ShooterPlayerController->LastHadPawnTime
Avatar
jraServerAPI 11/2/2021 6:22 AM
and here i was about to track player position with a timer to see if they moved 😆
6:23 AM
thank you!
6:23 AM
i think it just uses
6:23 AM
UWorld->TimeSince(ShooterPlayerController->LastLargeMoveTime)
6:23 AM
etc
Avatar
jraServerAPI 11/2/2021 6:23 AM
okay.. i have a lot to look into ..thanks again! woohoo
Avatar
jraServerAPI 11/10/2021 5:47 PM
Good day! I'm looking for a hook that gets fired after you cryopod a dino. Has anyone had any experience with this? Thank you!
Avatar
There should be an OnCryo func on primal dino class
Avatar
jahydev.com 11/11/2021 2:10 PM
How i can get server QueryPort ?
Avatar
Avatar
jahydev.com
How i can get server QueryPort ?
Ask it nicely
Avatar
jraServerAPI 11/15/2021 8:51 PM
Hello! What is the preferred method of detecting if the player, or structure about to be placed is currently inside a cave? I searched the group but only came across this: https://discord.com/channels/513432877904691202/513822106639794196/712714070020587680 from over a year ago. There was some talk of checking the ZoneVolume but then the conversation went dead. Any guidance is appreciated! (edited)
Avatar
Cave damage is defined in AStructurePreventionZoneVolume, I believe you could hook the constructor (AStructurePreventionZoneVolume.AStructurePreventionZoneVolume) and check it's location. For the range it covers you might be able to calculate the radius based on actor's scale (volumes inherit from AActor so they have location, rotation as any other actor)
Avatar
jraServerAPI 11/15/2021 9:03 PM
peepoLove
Avatar
jraServerAPI 11/19/2021 1:37 AM
Good day to you all! Is it possible to change the location of a placed structure via code? I tried messing around with SetActorLocation(), but i'm not sure if this is supported on structures or not. But anytime I tried to use it, the server crashed on me. Thanks in advance
Avatar
I believe you have to do following to achieve that.
  • locate the actor
  • destroy it (or kill it)
  • add new at new location
Avatar
jraServerAPI 11/19/2021 3:28 PM
Thanks, yes I actually started to use that methodology once I gave up on SetActorLocation() (edited)
Avatar
Hello, I'm trying to replace passive taming food for the Voidwyrm (trying to replace Mutagen by Elements). I've found few functions that could be interesting in APrimalDinoCharacter class : bool CanTame(AShooterPlayerController* ForPC, bool bIgnoreMaxTamedDinos); void BPUntamedConsumeFoodItem(UPrimalItem* foodItem); AShooterCharacter* ConsumeInventoryFoodItem(UPrimalItem* foodItem, float* AffinityIncrease, bool bDontDecrementItem, float* FoodIncrease, float FoodAmountMultiplier, bool bConsumeEntireStack); But I don't know how to proceed and where to start exactly. Also there's a lot of functions related to food affinity and I think I will have to override all of them if I want max affinity for Elements 🤔 (edited)
12:02 PM
Maybe there's a global array containing allowed food (and associated affinity) per dino somewhere?
12:03 PM
I have a lot of questions right now so maybe someone that has already done something similar can give me few hints ^^
Avatar
I'm trying to implement APrimalDinoCharacter::GetFirstAffinityFoodItemClass but I have some errors : #define _DWORD uint32 #define _QWORD uint64 DECLARE_HOOK(APrimalDinoCharacter_GetFirstAffinityFoodItemClass, TSubclassOf<UPrimalItem>*, APrimalDinoCharacter*, TSubclassOf<UPrimalItem>*); TSubclassOf<UPrimalItem>* Hook_APrimalDinoCharacter_GetFirstAffinityFoodItemClass(APrimalDinoCharacter* _this, TSubclassOf<UPrimalItem>* result) { UClass* v2; int i; UStruct** v5; UStruct* v6; APrimalDinoCharacter* v7; TSubclassOf<UPrimalItem>* v8; v8 = result; v7 = _this; if (*((_QWORD*)_this + 806)) { for (i = 0; i < *(_DWORD*)(*((_QWORD*)v7 + 806) + 48i64); ++i) { if (*(float*)(*(_QWORD*)(*((_QWORD*)v7 + 806) + 40i64) + 48i64 * i + 12) > 0.0) { v5 = (UStruct**)(*(_QWORD*)(*((_QWORD*)v7 + 806) + 40i64) + 48i64 * i + 32); if (*v5 && (v2 = UPrimalItem::StaticClass(), UStruct::IsChildOf(*v5, (UStruct*)&v2->vfptr))) // ERROR HERE v6 = *v5; else v6 = 0i64; if (v6) { v8->uClass = *(UClass**)(*(_QWORD*)(*((_QWORD*)v7 + 806) + 40i64) + 48i64 * i + 32); return v8; } } } } v8->uClass = 0i64; return v8; //return APrimalDinoCharacter_GetFirstAffinityFoodItemClass_original(_this, result); } (edited)
Avatar
I would not try to copy and paste ida pseudo code into raw c++. If you want to modify the food class you should return it yourself based on what you need or want returned
Avatar
I'm not sure I understand
10:30 AM
x)
Avatar
Even if you could fix those errors, that code is not really readable and not sure what is going on on there either 😛
10:31 AM
Is this related to your yesterday's post?
Avatar
yes
10:32 AM
I want to modify taming food for Voidwyrms
10:32 AM
trying to find a simple workaround but I'm still a bit lost
10:33 AM
I was thinking of modifying the return value of the GetFirstAffinityFoodItemClass() but I also want to keep all the extra checks that's why I was trying to mimic it
Avatar
I believe the food class was hard coded in the void wyrm class (if I remember correctly from last time I looked at it, main reason as to why it was broken for stack mod elements)
10:34 AM
I would need to look into devkit, not sure if it follows the normal passive tame procedure
Avatar
Does that mean it's not possible to change it using server side plugin only? (requires a client side mod?)
Avatar
If it's hard coded in bp only, it might be possible (either changing property value, or hooking the bp function), if it's on c++ it is also doable. But I do not have the devkit on this pc so can't help you more until I get home
Avatar
Thank you
Avatar
As I said, I believe it was coded in bp
10:37 AM
Most stuff since genesis 1 is all bp
Avatar
So you need the devkit to look into blueprint's code, if I understand correctly
Avatar
Correct
Avatar
I will try to do it as well on my side, will let you know if I make some progress
Avatar
Alright (@ me if you find something)
👍 1
Avatar
Only 370Gb remaining 🙃
Avatar
Avatar
Pelayori
I would not try to copy and paste ida pseudo code into raw c++. If you want to modify the food class you should return it yourself based on what you need or want returned
5:01 PM
don't tell me what to do
Avatar
So I was able to install the devkit, and I found this :
5:13 PM
not sure if it's helping me yet ^^
Avatar
Is it what you wanted to look at @Pelayori?
Avatar
Avatar
substitute
Click to see attachment 🖼️
Not fair! AnimPepeFire
Avatar
Avatar
OSubMarin
Is it what you wanted to look at @Pelayori?
Not exactly, I will open devkit now
Avatar
Ok thank you
Avatar
Ok I think now I opened proper asset (TekWyvern_Character_BP) because there's a lot more info.
6:25 PM
Avatar
Yeah I've been looking at it for a while now
6:26 PM
There are no hard references to mutagen class except on the hud display that tells you to press E to feed mutagen
6:27 PM
You might be able to modify dino settings to add food tame affinity
Avatar
I just need to figure out how I can modify dino settings then x)
Avatar
Something like modifying dino settings class default object to add your entry might suffice
Avatar
But how do I find the Dino Settings class?
Avatar
On init game, load class, get default object, cast to UPrimalDinoSettings* and add your own entry to food effectiveness array
Avatar
Alright
Avatar
You can load it by path, or find a void wyrm ingame, get the my dino settings cdo, get the class, modify the default object (but this approach might force to get all void wyrms and update their respective dino settings cdo field)
6:30 PM
The path for the settings is Blueprint'/Game/Genesis2/Dinos/TekWyvern/DinoSettings_Carnivore_Huge_TekWyvern.DinoSettings_Carnivore_Huge_TekWyvern'
Avatar
I know how to load this class and get the default object (using UVicotyCore namespace)
6:31 PM
I've already done that for another class
👍 1
6:33 PM
but if I modify the default object, is it retroactive? in the sens, existing voidwyrms on the map will also support passive tame using the new food type?
6:34 PM
maybe that's silly question ^^
Avatar
It is retroactive for newly instanced dinos, if you do it when some dinos on the map have already initialized you will need to loop trough them to change it on those old ones
Avatar
ah ok
6:34 PM
thanks a lot
Avatar
void Load() { Log::Get().Init("Loading mod..."); // Get item class FString tekWyvernSettingsPath = "Blueprint'/Game/Genesis2/Dinos/TekWyvern/DinoSettings_Carnivore_Huge_TekWyvern.DinoSettings_Carnivore_Huge_TekWyvern'"; UClass* tekWyvernSettingsClass = UVictoryCore::BPLoadClass(&tekWyvernSettingsPath); if (tekWyvernSettingsClass != nullptr) { UObject* tekWyvernSettingsObj = tekWyvernSettingsClass->GetDefaultObject(true); if (tekWyvernSettingsObj != nullptr) { UPrimalDinoSettings* tekWyvernSettings = (UPrimalDinoSettings*)tekWyvernSettingsObj; tekWyvernSettings->FoodEffectivenessMultipliersField(); // ERROR here } } Log::GetLog()->info("Loaded mod."); } (edited)
6:45 PM
My cast from UObject* to UPrimalDinoSettings* seems wrong.
Avatar
Is load running in dll attach?
Avatar
I guess so, it's my mod entry point
6:54 PM
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: case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: Unload(); break; } return TRUE; }
6:54 PM
yes
Avatar
Most game related stuff should run after game has init'd, I tend to use AShooterGameMode::InitGame hook, from that moment everything should be ready to use (edited)
Avatar
ok I will move my code inside a hook for InitGame
6:56 PM
but my problem is in Visual Studio
6:56 PM
Error C2027: use of undefined type 'UPrimalDinoSettings'
Avatar
Ah, the class isn't defined there then. You can get the definition from ida
6:57 PM
struct UPrimalDinoSettings : UObject { TArray<FDinoFoodEffectivenessMultipliers,FDefaultAllocator> FoodEffectivenessMultipliers; TArray<FDinoFoodEffectivenessMultipliers,FDefaultAllocator> ExtraFoodEffectivenessMultipliers; float TamingAffinityNoFoodDecreasePercentageSpeed; TArray<FDamageTypeAdjuster,FDefaultAllocator> BaseDamageTypeAdjusters; TArray<FDamageTypeAdjuster,FDefaultAllocator> ExtraDamageTypeAdjusters; UTexture2D *DinoFoodTypeImage; FString DinoFoodTypeName; bool bWakingTameDisplayItemName; };
Avatar
Well, VisualStudio seems to use a definition from ATLAS/Actor.h
6:57 PM
so that must not be correct
Avatar
Yeah, because it doesn't have the struct defined / declared
Avatar
Ok will copy paste the struct thanks again
Avatar
Not sure if FDinoFoodEffectivenessMultipliers is defined either, I'd take a guess and say it isn't
6:58 PM
struct FDinoFoodEffectivenessMultipliers { float FoodEffectivenessMultiplier; float HealthEffectivenessMultiplier; float TorpidityEffectivenessMultiplier; float AffinityEffectivenessMultiplier; float AffinityOverride; float StaminaEffectivenessMultiplier; int FoodItemCategory; TSubclassOf<UPrimalItem> FoodItemParent; float UntamedFoodConsumptionPriority; };
Avatar
And this one is missing too FDamageTypeAdjuster
6:58 PM
:p
Avatar
Shot, didn't see it 😛
6:59 PM
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; };
Avatar
Ok now I have this: void Load() { Log::Get().Init("Loading mod..."); // Get Voidwyrm default object FString tekWyvernSettingsPath = "Blueprint'/Game/Genesis2/Dinos/TekWyvern/DinoSettings_Carnivore_Huge_TekWyvern.DinoSettings_Carnivore_Huge_TekWyvern'"; UClass* tekWyvernSettingsClass = UVictoryCore::BPLoadClass(&tekWyvernSettingsPath); if (tekWyvernSettingsClass != nullptr) { UObject* tekWyvernSettingsObj = tekWyvernSettingsClass->GetDefaultObject(true); if (tekWyvernSettingsObj != nullptr) { // Grab UPrimalItem for Element FString elementBP = "Blueprint'/Game/PrimalEarth/CoreBlueprints/Resources/PrimalItemResource_Element.PrimalItemResource_Element'"; UClass* elementBPUClass = UVictoryCore::BPLoadClass(&elementBP); if (elementBPUClass != nullptr) { TSubclassOf<UPrimalItem> elementBPSubClass = TSubclassOf<UPrimalItem>(elementBPUClass); // Prepare the new taming food type FDinoFoodEffectivenessMultipliers foodType; foodType.FoodEffectivenessMultiplier = 1.333F; foodType.HealthEffectivenessMultiplier = 0.0F; foodType.TorpidityEffectivenessMultiplier = 0.0F; foodType.AffinityEffectivenessMultiplier = 1.0F; foodType.AffinityOverride = 1000.0F; foodType.StaminaEffectivenessMultiplier = 0.0F; foodType.FoodItemCategory = 0; foodType.FoodItemParent = elementBPSubClass; foodType.UntamedFoodConsumptionPriority = 1.0F; // Set the new taming food type UPrimalDinoSettings* tekWyvernSettings = (UPrimalDinoSettings*)tekWyvernSettingsObj; tekWyvernSettings->FoodEffectivenessMultipliers.Add(foodType); } } } Log::GetLog()->info("Loaded mod."); }
7:11 PM
And VisualStudio is not complaining this time.
7:11 PM
I only need to move this inside InitGame hooking method (edited)
👍 1
Avatar
Make sure to call the function when game is inited, you can also use Timer::DelayExecute to run it at the first game tick, there it is also ready
👍 1
Avatar
I'm not sure how to use Timer::DelayExecute since the namespace is not defined, but I know how to hook GameInit function so I will go this way.
Avatar
It's an api lib, do #include "Timer.h"
Avatar
but what do you set for delay in seconds?
7:38 PM
and is it more optimized than a GameInit hook?
7:41 PM
API::Timer::Get().DelayExecute(&OverridePassiveTameFood, 0); // 0 Delay? (edited)
Avatar
Not sure if it's more optimized, but saves from hooking init game (edited)
Avatar
ok and the 0 delay value is correct?
7:42 PM
the DelayExecute() hangs till first game tick?
7:43 PM
sorry lot of questions x)
Avatar
Yeah, delay 0 means do now (or when available), and it will not execute until game is fully ready
Avatar
thanks
Avatar
Avatar
OSubMarin
sorry lot of questions x)
Not an issue 🙂
Avatar
May I ask how were you able to grab the formatted structures so fast?
8:04 PM
UPrimalDinoSettings, FDinoFoodEffectivenessMultipliers and FDamageTypeAdjuster
Avatar
Alt + T in IDA, paste struct name, enter, click edit, Ctrl + A and paste (edited)
👍 1
Avatar
Awesome
8:27 PM
I'm not able to start the server now, it freezes at initialization
8:28 PM
I need to investigate a bit
Avatar
I have tried both the Timer and the GameInit hook methods but my server freezes at initialisation without error messages in logs.
8:45 PM
Complete code:
Avatar
The problem is coming from there : FString tekWyvernSettingsPath = "Blueprint'/Game/Genesis2/Dinos/TekWyvern/DinoSettings_Carnivore_Huge_TekWyvern.DinoSettings_Carnivore_Huge_TekWyvern'"; UClass* tekWyvernSettingsClass = UVictoryCore::BPLoadClass(&tekWyvernSettingsPath); if (tekWyvernSettingsClass != nullptr) { UPrimalDinoSettings* tekWyvernSettings = (UPrimalDinoSettings*)tekWyvernSettingsClass->GetDefaultObject(true); // This cast seems incorrect, accessing tekWyvernSettings returns gibberish and eventually crashes server.
Avatar
I'd use c++ style casting instead of c casting, with static_cast
9:50 PM
But doubt that is the issue
Avatar
For example when I access tekWyvernSettings->DinoFoodTypeName I get 㘀躚ȕ
9:52 PM
and tekWyvernSettings->FoodEffectivenessMultipliers.Num() gives me 6815769
9:53 PM
for some other attributes it crashes the server
9:53 PM
x)
9:53 PM
seems like it's not a UPrimalDinoSettings
Avatar
Add this to the primal dino settings struct and try with this TArray<FDinoFoodEffectivenessMultipliers>& FoodEffectivenessMultipliersField() { return *GetNativePointerField<TArray<FDinoFoodEffectivenessMultipliers>*>(this, "UPrimalDinoSettings.FoodEffectivenessMultipliers") }; (edited)
Avatar
Right, I did it and now tekWyvernSettings->FoodEffectivenessMultipliersField().Num() returns 16 as expected 👍
10:05 PM
I'm gonna continue testing (edited)
Avatar
Okay it's looking good but I have another problem now ^^
10:18 PM
Didn't know it was also Biome restricted lol
Avatar
Could hook the function HasBuffWithCustomTag and if it's called with the gen2 lunar biome name return true
Avatar
I will try that thank you
Avatar
Not sure what shenanigams will cause (if any) lol
Avatar
haha
10:23 PM
what is the namespace for HasBuffWithCustomTag?
Avatar
APrimalBuff I suppose
Avatar
nvm found it
10:28 PM
I'm not sure of the gen2 lunar biome name tho
10:29 PM
I know there's this spawn name : DinoSpawnEntriesSpace_Gen2_C
Avatar
Hook it, print the tag, find it 🙂
10:30 PM
yep
Avatar
bingo [2021.11.24-21.51.33:840][964]2021.11.24_21.51.33: HOOK (TekWyvern_Character_BP_C_0)(Gen2SpaceBiomeBuff)
10:54 PM
bool Hook_APrimalCharacter_HasBuffWithCustomTag(APrimalCharacter* _this, FName buffCustomTag) { if (_this->NameField().ToString().StartsWith("TekWyvern_Character_BP_C") && buffCustomTag.ToString().Equals("Gen2SpaceBiomeBuff")) return true; return APrimalCharacter_HasBuffWithCustomTag_original(_this, buffCustomTag); }
10:54 PM
now let's try
👍 2
Avatar
still getting the wrong biome message :p I'm going to look at this with ida. (edited)
Avatar
I'm not able to find the string "Cannot be tamed outside of the space biome" with ida. (edited)
Avatar
Avatar
OSubMarin
I'm not able to find the string "Cannot be tamed outside of the space biome" with ida. (edited)
Might be implemented in BP
Avatar
It is implemented in bp. But then likely client side (edited)
9:36 AM
At last resort could add the gen 2 lunar biome buff I guess
Avatar
Can I add the gen 2 lunar biome buff from server side only? (also I'm not testing on Gen 2 map, I'm testing on Crystal Isles). (edited)
10:57 AM
How do I search for a specific string in BP code?
Avatar
Avatar
OSubMarin
Can I add the gen 2 lunar biome buff from server side only? (also I'm not testing on Gen 2 map, I'm testing on Crystal Isles). (edited)
Adding buffs can only be done sercer side afaik
Avatar
Avatar
OSubMarin
How do I search for a specific string in BP code?
Go to the bp file in devkit and search for it in find results tab
Avatar
Go to the bp file , there's not a "Search in all BPs" option?
Avatar
There eis but you will take an hour for each sear h
Avatar
Ah ok ^^
11:03 AM
Thanks again
Avatar
I found an example on this Discord, I will try it FString lunarBuff = L"Blueprint'/Game/Genesis2/CoreBlueprints/Buffs/AreaBuffs/Gen2_AreaBuff_Space.Gen2_AreaBuff_Space_C'"; TSubclassOf<APrimalBuff> buffObj; buffObj.uClass = UVictoryCore::BPLoadClass(&lunarBuff); APrimalBuff* buff = APrimalBuff::StaticAddBuff(buffObj, _this, nullptr, nullptr, true); (edited)
11:21 AM
"_this" being the APrimalCharacter* for the Voidwyrm. (edited)
11:22 AM
I just need to find the blueprint path for lunar biome buff. (edited)
11:26 AM
Does anyone know if there's a list of all available buffs somewhere? Because right now I think I will have to install Gen 2 and add debug logs then check for creatures in space biome in order to get the blueprint path of the buff (that will take me quite some time). (edited)
Avatar
Nvm, I found them in the devkit :
Avatar
FString lunarBuff = L"Blueprint'/Game/Genesis2/CoreBlueprints/Buffs/AreaBuffs/Gen2_AreaBuff_Space.Gen2_AreaBuff_Space_C'"; UVictoryCore::BPLoadClass(&lunarBuff); // Returns nullptr I will try to grab the proper BP path with some logging on Gen2 now. (edited)
Avatar
My debug output shows: BuffName(Gen2_AreaBuff_Space_C_452) BuffFullName(Gen2_AreaBuff_Space_C /Game/Maps/Genesis2/Gen2.Gen2:PersistentLevel.Gen2_AreaBuff_Space_C_452) BuffClassName(Gen2_AreaBuff_Space_C)
Avatar
Maybe I can't load this buff from another map?
Avatar
So I'm trying a different approach now: Trying to automatically tame the dino if player has some specific items in his inventory.
6:25 PM
Is it possible to force tame the dino using the API? I was thinking of testing something like that: void DoTame(APrimalDinoCharacter* dino, AShooterCharacter* shooterCharacter) { int tribeId = ArkApi::GetApiUtils().GetTribeID(shooterCharacter); dino->TamingTeamIDField() = tribeId; dino->BPSetupTamed(true); }
6:26 PM
But it looks too simple x)
Avatar
Nvm I just found the ForceTame() function in AShooterPlayerController namespace.
Avatar
I managed to make it works 🙂 Now I can tame Voidwyrm without using Mutagen. The taming mechanic is very different tho (now the Voidwyrm gets tamed if a player manages to make it sleep and if that player has specific amount of Elements in his inventory). (edited)
pepehype 1
Avatar
Seems like a great approach given the issues 🙂
Avatar
Yeah, the struggle with buffs and gen 2 was real ^^
8:11 PM
Way more easy like this 🙂 Complete code below if anyone interested: (edited)
8:12 PM
👍 1
Avatar
Hmm, not sure if that authority modification and force tame is necessary
8:13 PM
APrimalDinoCharacter has a TameDino function
👍 1
Avatar
about the Role modification I'm not sure, but I looked at ForceTame() code using IDA and it checks if user Role is >= 3.
8:14 PM
so I added that just in case
Avatar
I'd use said TameDino function
Avatar
ok I'll try it
8:14 PM
but since it's not supposed to be tameable in my conditions (other map other biome)
8:15 PM
I wanted to go straight for force tame
8:15 PM
will let you know if it works with the regular one
Avatar
The tame dino function is not overriden in void wyrm, so it should be working regardless
Avatar
alright thank you
Avatar
Do you know what should I put for the int OverrideTamingTeamID 2nd argument when calling TameDino()? @Pelayori If I put 0 the taming team will be the one of PlayerController that I gave as 1st argument?
Avatar
You can pass it the Player Controller's targeting team, never tried with 0
Avatar
ok thank you
Avatar
team id 0 is usually wild enemy stuff
👌 1
Avatar
I can confirm that it works well with the TameDino() function too, and without the need for role elevation 👍 I replaced // Backup player role auto currentRole = playerController->RoleField(); // Elevate player role playerController->RoleField() = TEnumAsByte<ENetRole>(ENetRole::ROLE_Authority); // Do force tame playerController->ForceTame(true, dino); // Restore player role playerController->RoleField() = currentRole; with // Do tame dino->TameDino(playerController, false, playerController->TargetingTeamField(), false, false, false); (edited)
👍 2
Avatar
Now I just need to add a little more realism to the taming process by making the Voidwyrm unable to move for a reasonable amount of time. I'm looking for a very simple way to do it. I was thinking of applying Cryo Sickness to it if it's easy enough but I'm not sure... Any thoughts on this?
Avatar
Add lots of stone to it!
😆 2
Avatar
That works very well good idea, but in that case I also need to deny removing the stone from the inventory :p
9:19 PM
And it doesn't prevent cryopoding it
Avatar
Not sure if there is a simple way of ticking a bool or a freeze function(might be worth a shot to search for it), oherwise yeah add a bunch of heavy items, and schedule a delay execute to remove the heavy items
9:19 PM
Are players allowed to access its inventory while wild?
Avatar
it's not wild, basically I want to block it for a while after it's tamed
9:20 PM
so the player needs to protect it a little
Avatar
Ahh, right then what I said it's not very good
Avatar
I think adding cryo sickness is perfect since you cannot move it and cannot cryopod it, but I don't know if applying cryo sickness is easy
Avatar
Oh, anyways wild dinos do not often have inventory component
Avatar
Avatar
OSubMarin
I think adding cryo sickness is perfect since you cannot move it and cannot cryopod it, but I don't know if applying cryo sickness is easy
Yeah, seems reasonable. It's just a buff to add
Avatar
yeah but I struggled a bunch of hours trying to apply Gen2 Space buff to a dino so now I'm not sure xD
Avatar
Not sure why it didn't load, that's not the usual behaviour tho
9:22 PM
You could loop the global objects array and find anything containing cryo sickness (until you find the class object which starts with Class /Game/...)
Avatar
I know I already used this method but now for some reason the GUObjectArray()() is not defined anymore 🤔
Avatar
Isn't it?
9:49 PM
I had included it at some point in one of the most recent commits
Avatar
maybe my lib is outdated then
Avatar
Avatar
OSubMarin
maybe my lib is outdated then
Server plugins support for ARK. Contribute to Michidu/ARK-Server-API development by creating an account on GitHub.
Avatar
thanks, my local copy was indeed outdated. (edited)
👍 1
Avatar
This displayed nothing: for (auto i = 0; i < Globals::GUObjectArray()().ObjObjects.NumElements; i++) { auto obj = Globals::GUObjectArray()().ObjObjects.GetObjectPtr(i)->Object; if (obj != nullptr) { FString fullName; obj->GetFullName(&fullName, nullptr); if (fullName.StartsWith("Class /Game/") && (fullName.Contains("sickness") || fullName.Contains("cryo") || fullName.Contains("buff"))) { FString toLog = "TEST (" + fullName + ")"; shooterGameMode->PrintToServerGameLog(&toLog, true); } } }
11:02 PM
calling it from hooked APrimalDinoCharacter_Die when I kill another dino (not the one that has the cryosickness buff, this one is still alive and affected when the for loop gets called). (edited)
Avatar
try removing the startswith
👌 1
Avatar
nvm I found the buff name using the server command ListMyBuffs and admin gun in inspection mode:
11:10 PM
11:11 PM
ah but I still need the full BP path :p
Avatar
the results :
11:28 PM
going for Blueprint'/Game/Extinction/CoreBlueprints/Buffs/Buff_SummoningSickness.Buff_SummoningSickness'
Avatar
it works 😎
11:45 PM
working code below: void ApplyCryosickness(APrimalDinoCharacter* dino) { FString classString = L"Blueprint'/Game/Extinction/CoreBlueprints/Buffs/Buff_SummoningSickness.Buff_SummoningSickness'"; UClass* classObj = UVictoryCore::BPLoadClass(&classString); if (dino != nullptr && classObj != nullptr) APrimalBuff::StaticAddBuff(TSubclassOf<APrimalBuff>(classObj), dino, nullptr, nullptr, false); } (edited)
😎 1
AwwEyes 1
Avatar
Hello, I'm trying to add an item inside a dino death inventory. For example when a Woolly Rhino dies we can access its inventory and there's a Woolly Rhino Horn inside. I would like to add another item inside the Woolly Rhino death inventory. I've looked a bit at the APrimalDinoCharacter (I can access it by hooking the Die() function), but I don't know how to interact with the DeathInventory itself. (edited)
3:58 PM
I've done this little debug logging: float chanceToUse = _this->DeathInventoryChanceToUseField(); std::string chanceToUseStr = std::to_string(chanceToUse); float qualityPerLevel = _this->DeathInventoryQualityPerLevelMultiplierField(); std::string qualityPerLevelStr = std::to_string(qualityPerLevel); std::string deathInventoryTemplatesStr = "Templates("; FWeightedObjectList& deathInventoryTemplates = _this->DeathInventoryTemplatesField(); int len = deathInventoryTemplates.AssociatedObjects.Num(); int i = 0; while (i < len) { UObject* currObj = deathInventoryTemplates.AssociatedObjects[i]; if (currObj != nullptr) { FString fullName = ""; currObj->GetFullName(&fullName, nullptr); deathInventoryTemplatesStr += "Fullname=(" + fullName.ToString() + ")Class=(" + ArkApi::GetApiUtils().GetBlueprint(currObj).ToString() + ") ; "; } i++; } deathInventoryTemplatesStr += ")"; FString toLog = L"Rhino ChanceToUse=(" + FString(chanceToUseStr) + L") QualityPerLvl=(" + FString(qualityPerLevelStr) + L") " + FString(deathInventoryTemplatesStr); ArkApi::GetApiUtils().GetShooterGameMode()->PrintToServerGameLog(&toLog, true); (edited)
3:59 PM
which gives me : [2021.11.30-01.53.49:760][298]2021.11.30_01.53.49: Rhino ChanceToUse=(1.000000) QualityPerLvl=(0.025000) Templates(Fullname=(Blueprint /Game/PrimalEarth/CoreBlueprints/Inventories/DinoDropInventoryComponent_Rhino.DinoDropInventoryComponent_Rhino)Class=(Blueprint'/Script/Engine.Bluepri') ; )
4:01 PM
I don't know what type of object is DinoDropInventoryComponent_Rhino.
4:04 PM
I suppose I have to modify the deathInventoryTemplates.AssociatedObjects in order to add my item, but I'm not sure and I don't know how to do it. (edited)
Avatar
Can you not just add the item to its inventory after the death hook?
Avatar
I will try
Avatar
Avatar
Lethal
Can you not just add the item to its inventory after the death hook?
Yes it worked thank you
Avatar
and if I want to do it on a dino that don't have an inventory?
7:23 PM
because I tried but it didn't work
7:24 PM
I will try to add one
Avatar
I tried this but it crashes server UPrimalInventoryComponent* invComp = new UPrimalInventoryComponent(); if (invComp != nullptr) { _this->SetMyInventoryComponent(invComp); // "_this" is a "APrimalDinoCharacter*" invComp->InitializeInventory(); } auto inventory = _this->MyInventoryComponentField(); if (inventory != nullptr) { FString toLog = "Success"; ArkApi::GetApiUtils().GetShooterGameMode()->PrintToServerGameLog(&toLog, false); } (edited)
Avatar
This is how to make a dino drops a clone fertilized egg if someone interested (at least that's how I do it): ADroppedItem* DropCloneFertilizedEgg(APrimalDinoCharacter* dino, const wchar_t* fertilizedEggBlueprint) { ADroppedItem* retVal = nullptr; UObject* object = Globals::StaticLoadObject(UObject::StaticClass(), nullptr, fertilizedEggBlueprint, nullptr, 0, 0, true); if (object != nullptr) { TSubclassOf<ADroppedItem> eggItem; eggItem.uClass = reinterpret_cast<UClass*>(object); FRotator rotation{0,0,0}; FVector location; dino->GetLandingLocation(&location); retVal = dino->CreateCloneFertilizedEgg(location, rotation, eggItem); } return retVal; } // Example: fertilizedEggBlueprint = "Blueprint'/Game/PrimalEarth/Test/PrimalItemConsumable_Egg_Dodo_Fertilized.PrimalItemConsumable_Egg_Dodo_Fertilized'"; (edited)
👍 1
Avatar
Avatar
OSubMarin
I tried this but it crashes server UPrimalInventoryComponent* invComp = new UPrimalInventoryComponent(); if (invComp != nullptr) { _this->SetMyInventoryComponent(invComp); // "_this" is a "APrimalDinoCharacter*" invComp->InitializeInventory(); } auto inventory = _this->MyInventoryComponentField(); if (inventory != nullptr) { FString toLog = "Success"; ArkApi::GetApiUtils().GetShooterGameMode()->PrintToServerGameLog(&toLog, false); } (edited)
Wild dinos do not have inventory component prior dead
12:07 PM
The comp is created when they are tamed or when they die, the dino drop comp adds it's items to the newly created comp
12:07 PM
The dino drop comp is basically like supply crates, on component creation add the item sets of the loot table of said inventory drop component
12:08 PM
(For that reason, you can override death dino item drops with INI settings, the same as you can do with supply crates)
Avatar
Avatar
Pelayori
The comp is created when they are tamed or when they die, the dino drop comp adds it's items to the newly created comp
Is it always created? Because when I tried on a dino that doesn't drop anything there was no option "Press E to access inventory". I did the same thing I did with the Woolly Rhino, adding the item in inventory after death (which worked). But this time there's just no option to view the inventory on the dead astrodelphis body, I can't interact with it (only option I have is "Drag body"). (edited)
2:14 AM
So maybe the item was properly added in the astrodelphis inventory, but since I can't access its inventory I could not tell.
2:15 AM
I've seen a function related to "AllowAccessInventory" something like that, so I will have to look that way I guess.
Avatar
Avatar
OSubMarin
Is it always created? Because when I tried on a dino that doesn't drop anything there was no option "Press E to access inventory". I did the same thing I did with the Woolly Rhino, adding the item in inventory after death (which worked). But this time there's just no option to view the inventory on the dead astrodelphis body, I can't interact with it (only option I have is "Drag body"). (edited)
If they are designed to have an inv comp yes, I haven't seen any dino not using the usual inv comp attachment so not sure why you can't access dolphins (edited)
Avatar
the astrodelphis never has an inventory except if it's tamed (edited)
4:22 PM
you can only drag its body
Avatar
I'm getting a nullptr on aprimaldinocharacter->MyInventoryComponentField();
7:31 PM
Even after firing the original Die() function.
Avatar
Avatar
Pelayori
(For that reason, you can override death dino item drops with INI settings, the same as you can do with supply crates)
I could not find the proper syntax to target astrodelphis from the INI settings. Some dino don't have a specific ID like the magmasaur and dodo rex (which both use the same SupplyCrateClassString="DinoDropInventoryComponent_Carnivore_Huge_C").
Avatar
It is possible that astro delphis does not have a dino drop inv comp
Avatar
true
8:36 PM
and it seems they don't have an inventory as well, even after dieing.
Avatar
Inventory is created when tamed or when they have a dino drop inv comp, otherwise it is not created
Avatar
they don't have any dino drop inv component
8:37 PM
they're not supposed to drop anything
Avatar
Then no inventory if wild 🙂
Avatar
yeah that's my problem haha
8:37 PM
^^
Avatar
I don't know what's the procedure to create an inv component, but using new with UObjects is no bueno
👌 1
Avatar
that's why I wanted to add an inventory manually, but maybe it's more simple to drop a bag on the dead body location? I don't know what would be the easiest way to go
8:39 PM
I know I can use the DropItem function from the API but this one despawns too fast (a bag would be better) (edited)
Avatar
There is a way to set inv comps actually
8:40 PM
You have to use a construct object function, then call APrimalDinoCharacter::SetMyInventoryComponent, call RegisterComponen (on the comp class I assume) and then call InventoryComponent->InitializeInventory
Avatar
wow
8:40 PM
awesome
Avatar
You might be lucky with that one, I've seen others do it like that in the dev kit and it worked
Avatar
I'll definitely give it a try thank you
Avatar
Oh yeah, the pegomastax does that
8:41 PM
so technically that snippet it's from wildcard itself (edited)
Avatar
ah so it must be alright (edited)
Avatar
should 😄
Avatar
should yeah ^^
8:42 PM
when you say I have to use a construct function I'm not sure I understand
8:43 PM
the goal is to instantiate a UPrimalInventoryComponent
8:43 PM
right?
Avatar
There should be one in UVictoryCore or KismetSystemLib
8:43 PM
Yes, load the inventory class you need, create a new object from class
8:43 PM
and then set it as the inventory component
8:44 PM
But creating objects in UE4 is not as easy as doing new Class() 😄
Avatar
haha well, I tried x)
Avatar
They have special procedures to instantiate themselves
Avatar
yeah I usually try to find a static creation function
8:45 PM
but couldn't find one for the UPrimalInventoryComponent
Avatar
I'm loading devkit I can give you the bp path for astrodelphis inv comp
Avatar
load the inventory class you need wait there's multiple types of UPrimalInventoryComponent?
Avatar
The bp ones 😛
Avatar
ah ok so I can load it the usual way with BPLoadClass I see
Avatar
No dino has the c++ class version of the component
8:46 PM
They are are custom bp classes inherited from the base primalinvcomponent
Avatar
ok from the C++ point of view only remains the C++ base class (UPrimalInventoryComp)
Avatar
Correct
Avatar
I understand thanks
8:48 PM
so loading the proper sub class with BPLoadCLass will make sure the base one is instantiated and initialized properly for that dino I guess (edited)
Avatar
Globals::StaticConstructObject is the function that can construct objects
Avatar
Avatar
OSubMarin
so loading the proper sub class with BPLoadCLass will make sure the base one is instantiated and initialized properly for that dino I guess (edited)
It wll make sure inv comp has the right settings for the dino, they have slight differences between them all yes
Avatar
perfect
Avatar
Avatar
Pelayori
Globals::StaticConstructObject is the function that can construct objects
When using this I believe only Class and Outer are truly used that we have interest on
8:49 PM
Outer should be the dino pawn
8:49 PM
Name and all the others just empty vars
Avatar
so I give the UPrimalDinoCharacter in outer and the Astrodelphis inventory BP path to the function ok
Avatar
Yes
Avatar
I'm thinking that maybe since it's not supposed to drop anything it does not have its own sub inventoryComponent class. (edited)
8:57 PM
Maybe it uses a generic one 🤔
Avatar
The tamed one should have its own sub class (edited)
8:58 PM
or use another sub class
Avatar
Yeah, maybe some UGenericFlyerInventoryComponent I don't know (edited)
Avatar
You are right it does not have an attached inv comp
Avatar
Avatar
Pelayori
I'm loading devkit I can give you the bp path for astrodelphis inv comp
Okay I could have started the devkit to see if I can find any linked inventory blueprint but since you offer to do it ^^ (also I don't know where to look at in the devkit)
9:02 PM
Ah
9:03 PM
So the function DoTame() is probably adding a generic one automatically if there's not any linked
Avatar
Not sure
Avatar
hmmm x)
9:05 PM
This becomes even more mysterious now
Avatar
You can get what comp it uses with TamedInventoryComponentTemplateField() (edited)
9:09 PM
Then you can create it yourself
Avatar
Nice I will try
Avatar
this->MyInventoryComponent = v6; AActor::AddOwnedComponent(this, this->MyInventoryComponent); UActorComponent::RegisterComponent(this->MyInventoryComponent); ((void (__fastcall *)(UPrimalInventoryComponent *))this->MyInventoryComponent->APrimalCharacter::vfptr[20].__vecDelDtor)(this->MyInventoryComponent); if ( this->MyCharacterStatusComponent ) UPrimalCharacterStatusComponent::UpdateWeightStat(this->MyCharacterStatusComponent, 0);
9:10 PM
That's a snippet from ida about how they do it
Avatar
I can copy paste the APrimalCharacter::vfptr[20].__vecDelDtor? looks a bit weird
Avatar
You can just probably ignore that file
9:12 PM
Just take a look at the functions they use (edited)
Avatar
ah ok
Avatar
More of a oritentative snippet rather than a copy paste one
9:13 PM
v6 being the newly created object from inventory comp class
Avatar
yes and its description is in TamedInventoryComponentTemplateField
9:14 PM
I mean its template
Avatar
Might be better to do APrimalDinoCharacter::SetInventoryComponent rather than assigning the variable
Avatar
void __fastcall APrimalCharacter::SetMyInventoryComponent(APrimalCharacter *this, UPrimalInventoryComponent *theInventoryComponent) { this->MyInventoryComponent = theInventoryComponent; }
9:16 PM
It seems it's just assigning it too
Avatar
I prefer calling ingame functions rather than assigning things myself 😛
9:16 PM
But as you prefer
Avatar
yeah I'll use the legit function too
9:16 PM
just in case
9:18 PM
so one last thing is, how exactly should I test the content of TamedInventoryComponentTemplateField()? Because it will return a UObject and I never know what to look at since there's so much names fields (FieldName(), Fullname(), Fullpath(), etc.).
Avatar
That field is basically an UClass* (edited)
Avatar
yeah but it's the same, so much name fields
Avatar
You can get its bp path with ArkApi::GetApiUtils().GetClassBlueprint(class);
Avatar
Sometimes I use the GetClassBlueprint() function from the API, but sometimes the returned path is useless (like 'Game /Class/Bluepri' something like that). (edited)
9:20 PM
Ah ok, so it should work in that case, alright.
Avatar
TL;DR; the path is this
9:20 PM
Blueprint'/Game/Genesis2/Dinos/SpaceDolphin/DinoTamedInventoryComponent_SpaceDolphin.DinoTamedInventoryComponent_SpaceDolphin' (edited)
Avatar
^^
9:20 PM
thank you
Avatar
But if you have the class ptr available somewhere rather use that than bp load class again
Avatar
ok
Avatar
Avatar
OSubMarin
Sometimes I use the GetClassBlueprint() function from the API, but sometimes the returned path is useless (like 'Game /Class/Bluepri' something like that). (edited)
I use NameField() many many times, quick representative name of objects and classes (since classes are objects)
👍 1
Avatar
because I usually call BPLoadClass in functions that are called multiple times*, so maybe it's time to move the BPLoadClass calls in some function that has a static array of pointers to already loaded class 🤔 (edited)
Avatar
Could also declare the bp load variables as static, so they only get loaded once and reused in later executions
👌 1
Avatar
void AddInventoryCompToAstrodelphis(APrimalDinoCharacter* dino) { FString astroInvCompPath = L"Blueprint'/Game/Genesis2/Dinos/SpaceDolphin/DinoTamedInventoryComponent_SpaceDolphin.DinoTamedInventoryComponent_SpaceDolphin'"; UClass* astroInvCompClass = UVictoryCore::BPLoadClass(&astroInvCompPath); if (astroInvCompClass != nullptr) { UObject* astroInvCompObj = Globals::StaticConstructObject(astroInvCompClass, dino, FName(), EObjectFlags::RF_NoFlags, nullptr, false, nullptr); if (astroInvCompObj != nullptr) { dino->SetMyInventoryComponent((UPrimalInventoryComponent*)astroInvCompObj); dino->AddOwnedComponent(dino->MyInventoryComponentField()); dino->MyInventoryComponentField()->RegisterComponent(); dino->MyInventoryComponentField()->InitializeInventory(); } } } (edited)
9:48 PM
I'm not sure about giving FName() to Globals::StaticConstructObject but I will try like this
Avatar
It doesn't matter which name you use I believe
Avatar
well done Pelayori, it works perfectly on first try
10:18 PM
thank you
10:18 PM
👍 1
Avatar
That's a surpise
🤓 1
10:18 PM
jk hah, np
Avatar
UClass* MyBPLoadClass(FString* blueprintPath) { static std::map<FString, UClass*> loadedClasses; std::map<FString, UClass*>::const_iterator found = loadedClasses.find(*blueprintPath); if (found != loadedClasses.end()) return (*found).second; UClass* toAdd = UVictoryCore::BPLoadClass(blueprintPath); loadedClasses[*blueprintPath] = toAdd; return toAdd; } (edited)
11:17 PM
That should do the trick (calling it for each classes I need when the mod loads up).
Avatar
would work yeah
Avatar
It worked but I had to call it after the AShooterGameMode_InitGame_original() call as you mentioned in an earlier conversation.
👍 1
Avatar
Deleted User 12/4/2021 8:52 AM
i waiting 2 days for the verivication email i dont recive (Forum) (edited)
Avatar
I tried to find the code handling new year event with IDA without success. I tried to search text "NewYear", "Years" and even the regular expression .*NewYear.*. (edited)
6:02 PM
Nothing shows up 🤔
6:05 PM
I guess that means it's in BP code, correct?
6:05 PM
Another problem is that I don't have a method to search in the entire BP code through devkit, but I'll keep searching for now. (edited)
Avatar
Might be in game mode's BP
6:07 PM
You can search in all bps, in find results tab within an open bp file, uncheck only this blueprint
👌 1
Avatar
Thank you Pelayori 👍
6:07 PM
I'm starting devkit and I will let you know if I find something (edited)
Avatar
I did search "NewYear" in BP code (only this blueprint unchecked) but it didn't find it. I tried to index all BP code in case it was not indexed => Not enough RAM exception 💩 (edited)
😆 1
8:57 PM
I'll have to try again another time with no application running in background.
Avatar
Here are some strings I found in ShooterGame.log if someone with a good setup can/wants to try: [2022.01.01-04.38.06:669][ 1]Server attempting to run new years event [2022.01.01-04.38.06:669][ 1]Set New Years UTC 1 to: 1641016832.000000 [2022.01.01-04.38.06:670][ 1]Set New Years UTC 2 to: 1641049216.000000 [2022.01.01-04.38.08:362][ 51]Set New Years event location: 85868,648 - -111300,875 - 41857,234 [2022.01.01-06.00.32:017][438]Starting New Years event 1 [2022.01.01-06.00.32:336][446]Spawning New Years Presents ... [2022.01.01-15.00.16:023][964]Starting New Years event 2
Avatar
So I'm continuing the conversation about scaling models here because it's getting more advanced now.
Avatar
After more tests it seems that during certain operations (like throwing the pet out of your shoulder in case of a shinehorn) the Mesh scaling gets restored. I don't know exactly why but it may be due to the animation resetting it.
12:58 PM
Some weird stuff happening here:
1:00 PM
And there is another problem, only the mesh gets reset so the colliding volumes for physics are still scaled.
1:02 PM
I was able to work around the issue by restoring the USceneComponent scale to 1.0 before calling AShooterCharacter_LaunchMountedDino_original(_this);. Then 5 seconds after the AShooterCharacter_LaunchMountedDino_original(_this); call I scale again to the desired ratio. (edited)
1:06 PM
I can reduce the delay to 1 or 2 seconds (5 seconds was just for testing purpose) but yeah, still work arounds. (edited)
Avatar
As I was expecting there's a lot related to scaling in the animation:
Avatar
@Pelayori I was looking at this example: static int tribeDataStructSize = GetStructSize<FTribeData>(); FTribeData* data = static_cast<FTribeData*>(FMemory::Malloc(tribeDataStructSize)); RtlSecureZeroMemory(data, tribeDataStructSize); ArkApi::GetApiUtils().GetShooterGameMode()->GetOrLoadTribeData(team, data); // use the tribe data // don't forget to free the memory! FMemory::Free(data); And I was wondering why not just allocate the struct on stack like this? FTribeData data = FTribeData(); ArkApi::GetApiUtils().GetShooterGameMode()->GetOrLoadTribeData(team, &data); // use the tribe data
Avatar
Avatar
OSubMarin
@Pelayori I was looking at this example: static int tribeDataStructSize = GetStructSize<FTribeData>(); FTribeData* data = static_cast<FTribeData*>(FMemory::Malloc(tribeDataStructSize)); RtlSecureZeroMemory(data, tribeDataStructSize); ArkApi::GetApiUtils().GetShooterGameMode()->GetOrLoadTribeData(team, data); // use the tribe data // don't forget to free the memory! FMemory::Free(data); And I was wondering why not just allocate the struct on stack like this? FTribeData data = FTribeData(); ArkApi::GetApiUtils().GetShooterGameMode()->GetOrLoadTribeData(team, &data); // use the tribe data
The function expects heap memory
7:24 PM
Stack memory will cause a crash
Avatar
Ok thank you
7:44 PM
You have a method to identify when heap is required?
7:44 PM
Looking with ida I can now see this:
7:46 PM
but I don't know..
7:49 PM
it seems to me that the given LoadedTribeData is treated as a regular pointer to structure, and the heap allocator thing is used on the AShooterGameMode object.
Avatar
Even when I simply try to read the data it crashes the server for some reason pMeh
Avatar
jraServerAPI 3/1/2022 8:12 PM
Does anyone know where this data is stored? Been looking for a while now 😕
Avatar
jraServerAPI 3/1/2022 10:52 PM
must be on client side, not server lethalthink
Avatar
jraServerAPI 3/2/2022 8:34 PM
Wooohoo c++ auto maxHP = myStructure->MaxHealthField(); auto currentHP = myStructure->HealthField(); if ((currentHP < maxHP) && myStructure->ConsumesPrimalItemField().uClass) { const float myPercent = ((1.0 - (currentHP / maxHP)) / 2); auto item2 = ((UPrimalItem*)(myStructure->ConsumesPrimalItemField().uClass->GetDefaultObject(true))); if(item2) { if (item2->BaseCraftingResourceRequirementsField().Num()) { for (int i = 0; i < item2->BaseCraftingResourceRequirementsField().Num(); ++i) { const int x1 = (item2->BaseCraftingResourceRequirementsField()[i].BaseResourceRequirement * myPercent) + 1; DLog("Need = {}", x1); DLog("ResourceItemType = {}", ArkApi::IApiUtils::GetClassBlueprint(item2->BaseCraftingResourceRequirementsField()[i].ResourceItemType.uClass).ToString()); } } } } I figured it out!! (edited)
8:34 PM
DLog is my custom logging function
Avatar
jraServerAPI 3/5/2022 9:01 PM
Hmm..well I sort of figured it out.. the above code is not 100% bulletproof... it seems there a different Percent value calculated for each required resource.. I'm still trying to get that formula..
9:02 PM
i'm not sure what v81[23].Outer is, but I think that's my missing puzzle piece
Avatar
jraServerAPI 3/5/2022 11:24 PM
so there's a OverrideRepairingRequirementsField array, that is used on special structures (LIke the heavy Turret), that gives different base numbers to calculate from.. instead of 400 metal.. you need 410 etc.. And when it's empty (like for foundations) you use the calculations in the BaseCraftingResourceRequirementsField array .. so that was my missing piece 🙂
👍 1
11:25 PM
Avatar
jraServerAPI 3/11/2022 7:21 AM
Could someone help me figure out what I've done wrong? I've been reading through the chat history and it looks like UPrimalLocalProfile::AddArkTributePlayerData is not in the api yet. So I was trying to add it manually and hook it in my plugin. I have never done this before so I'm not sure what is going on yet. But to my surprise the hook seemed to work and was called on the first test/try, but then the server crashed hard right after I got my logging message. c++ struct UPrimalLocalProfile { void AddArkTributePlayerData(FArkTributePlayerData* ArkPlayerData) { NativeCall<void, FArkTributePlayerData*>(this, "UPrimalLocalProfile.AddArkTributePlayerData", ArkPlayerData); } }; DECLARE_HOOK(UPrimalLocalProfile_AddArkTributePlayerData, void, FArkTributePlayerData*); void Hook_UPrimalLocalProfile_AddArkTributePlayerData(FArkTributePlayerData* _this) { if (_this) Log::GetLog()->warn("has value"); else Log::GetLog()->warn("Null"); UPrimalLocalProfile_AddArkTributePlayerData_original(_this); // crashes } ArkApi::GetHooks().SetHook("UPrimalLocalProfile.AddArkTributePlayerData", &Hook_UPrimalLocalProfile_AddArkTributePlayerData, &UPrimalLocalProfile_AddArkTributePlayerData_original); ArkApi::GetHooks().DisableHook("UPrimalLocalProfile.AddArkTributePlayerData", &Hook_UPrimalLocalProfile_AddArkTributePlayerData); as always, thank you 1136_ouch_my_pp (edited)
Avatar
jraServerAPI 3/11/2022 7:36 AM
i think i figured it out 🙂
Avatar
jraServerAPI 3/11/2022 8:24 AM
Nope, i lied.. The hook is called, but is always crashes (edited)
8:24 AM
🤷‍♂️
8:29 AM
I'm thinking maybe it's my struct definition struct UPrimalLocalProfile : NeedSomethingHereRight? { ...
Avatar
Your DECLARE_HOOK() and Hook definition are missing a UPrimalLocalProfile*
Avatar
jraServerAPI 3/11/2022 8:53 AM
i assumed that is just an ida thing
8:53 AM
Avatar
Not just ida, ArkApi hooks have similar signatures. A UPrimalLocalProfile* _this in your case
9:05 AM
That's where the reference comes from for whatever object youre manipulating
Avatar
jraServerAPI 3/11/2022 9:18 AM
Thank you
Avatar
jraServerAPI 3/11/2022 9:28 AM
here is the working code in case someone is looking for it: c++ struct UPrimalLocalProfile { void AddArkTributePlayerData(UPrimalLocalProfile* localProfile, FArkTributePlayerData* ArkPlayerData) { NativeCall<void, UPrimalLocalProfile*, FArkTributePlayerData*>(this, "UPrimalLocalProfile.AddArkTributePlayerData", localProfile, ArkPlayerData); } }; DECLARE_HOOK(UPrimalLocalProfile_AddArkTributePlayerData, void, UPrimalLocalProfile*, FArkTributePlayerData*); void Hook_UPrimalLocalProfile_AddArkTributePlayerData(UPrimalLocalProfile* _this, FArkTributePlayerData* PlayerData) { UPrimalLocalProfile_AddArkTributePlayerData_original(_this, PlayerData); } ArkApi::GetHooks().SetHook("UPrimalLocalProfile.AddArkTributePlayerData", &Hook_UPrimalLocalProfile_AddArkTributePlayerData, &UPrimalLocalProfile_AddArkTributePlayerData_original); ArkApi::GetHooks().DisableHook("UPrimalLocalProfile.AddArkTributePlayerData", &Hook_UPrimalLocalProfile_AddArkTributePlayerData);
Avatar
Avatar
jraServerAPI
here is the working code in case someone is looking for it: c++ struct UPrimalLocalProfile { void AddArkTributePlayerData(UPrimalLocalProfile* localProfile, FArkTributePlayerData* ArkPlayerData) { NativeCall<void, UPrimalLocalProfile*, FArkTributePlayerData*>(this, "UPrimalLocalProfile.AddArkTributePlayerData", localProfile, ArkPlayerData); } }; DECLARE_HOOK(UPrimalLocalProfile_AddArkTributePlayerData, void, UPrimalLocalProfile*, FArkTributePlayerData*); void Hook_UPrimalLocalProfile_AddArkTributePlayerData(UPrimalLocalProfile* _this, FArkTributePlayerData* PlayerData) { UPrimalLocalProfile_AddArkTributePlayerData_original(_this, PlayerData); } ArkApi::GetHooks().SetHook("UPrimalLocalProfile.AddArkTributePlayerData", &Hook_UPrimalLocalProfile_AddArkTributePlayerData, &UPrimalLocalProfile_AddArkTributePlayerData_original); ArkApi::GetHooks().DisableHook("UPrimalLocalProfile.AddArkTributePlayerData", &Hook_UPrimalLocalProfile_AddArkTributePlayerData);
One step too far I think 🙂 Your struct UPrimalLocalProfile def looked right to me the first time. NativeCall gives you the UPrimalLocalProfile* arg for free. It could be that your second example happens to work out with calling conventions and an extra argument somewhere, but I wouldn't leave it that way.
Avatar
Oops, sorry. Earlier I spoke without really understanding how ArkServerApi hooks work. Disregard that bit about extra args and calling conventions, the struct definition doesn't play the role I thought I did. You still had it right the first time though.
Avatar
jraServerAPI 3/17/2022 4:26 PM
Has anyone tried connecting to the Steam API thru a plugin? I'm wondering if it's possible at all, and if anything useful can be retrieved. Any feedback is appreciated. (edited)
Avatar
jraServerAPI 3/17/2022 4:34 PM
I think it would be useful if you could obtain the number of hours the player has played ARK on their steam account.. to recognize noobs and veterans etc... and on the flipside.. you could also potentially detect cheater accounts with this information.. if a noob is merking everyone lol.. anyway.. just an idea.. 🙂
Avatar
Avatar
jraServerAPI
Has anyone tried connecting to the Steam API thru a plugin? I'm wondering if it's possible at all, and if anything useful can be retrieved. Any feedback is appreciated. (edited)
what's stopping you 😄
4:37 PM
you can obtain any data if you have the steamID
Avatar
jraServerAPI 3/17/2022 4:50 PM
Well I think I tried to access the API a while back and was not getting any results, and that was just testing in a browser.. but now I just tested and it's working.. But you know.. Sometimes I get these ideas and I like to share them, especially if it can deter cheating 🙂
Avatar
🐨Dream Doctor🦘 3/21/2022 6:44 AM
I'm working on a plugin that needs to keep track of and limit total counts for certain specific structures. Counts are per tribe. The specific structures to be tracked are specified by BP in a config file. I can run a GAAC at startup and count each type of structure, which is fine. I can also add or remove from the count of each type of structure as it's placed or destroyed, which is also fine. What I'm trying to work out is the most efficient way of adding and removing from that data, as it needs to happen often during run time. The way I've gone so far is to split it into two parts. The first is just a simple array of strings, taken from the config file. Each time a structure is placed, I can easily loop through the array and see if its BP is there. For the second part, I've made an unordered_map like this: std::unordered_map<uint64, int[20]> tribe_counts;. The uint64 is the tribe/team id, and the int array is a count of each structure type using the same index from the first array of structures. I can use the index of the relevant structure in the first array to store/retrieve the count for a specific tribe in the map. Does this make sense, and can anyone suggest a more intuitive way of doing this efficiently? (edited)
Avatar
std::unordered_map is the fastest way and think the way you want to go
Avatar
Avatar
🐨Dream Doctor🦘
I'm working on a plugin that needs to keep track of and limit total counts for certain specific structures. Counts are per tribe. The specific structures to be tracked are specified by BP in a config file. I can run a GAAC at startup and count each type of structure, which is fine. I can also add or remove from the count of each type of structure as it's placed or destroyed, which is also fine. What I'm trying to work out is the most efficient way of adding and removing from that data, as it needs to happen often during run time. The way I've gone so far is to split it into two parts. The first is just a simple array of strings, taken from the config file. Each time a structure is placed, I can easily loop through the array and see if its BP is there. For the second part, I've made an unordered_map like this: std::unordered_map<uint64, int[20]> tribe_counts;. The uint64 is the tribe/team id, and the int array is a count of each structure type using the same index from the first array of structures. I can use the index of the relevant structure in the first array to store/retrieve the count for a specific tribe in the map. Does this make sense, and can anyone suggest a more intuitive way of doing this efficiently? (edited)
if you only require to track the count and not in any way track individual structures themselves your approach looks good
11:50 AM
although i would make a second unordered map a value of your unordered map and have the second unordered map have the structure bp as key (string) and the count as value
11:51 AM
this way i'd be able to look up how many of a structure are placed by a team of a specific bp
Avatar
Avatar
🐨Dream Doctor🦘
I'm working on a plugin that needs to keep track of and limit total counts for certain specific structures. Counts are per tribe. The specific structures to be tracked are specified by BP in a config file. I can run a GAAC at startup and count each type of structure, which is fine. I can also add or remove from the count of each type of structure as it's placed or destroyed, which is also fine. What I'm trying to work out is the most efficient way of adding and removing from that data, as it needs to happen often during run time. The way I've gone so far is to split it into two parts. The first is just a simple array of strings, taken from the config file. Each time a structure is placed, I can easily loop through the array and see if its BP is there. For the second part, I've made an unordered_map like this: std::unordered_map<uint64, int[20]> tribe_counts;. The uint64 is the tribe/team id, and the int array is a count of each structure type using the same index from the first array of structures. I can use the index of the relevant structure in the first array to store/retrieve the count for a specific tribe in the map. Does this make sense, and can anyone suggest a more intuitive way of doing this efficiently? (edited)
The first part I would convert to an unordered set (edited)
6:41 PM
That way instead of always O(n) lookups you may be able to get O(1) lookups (edited)
6:43 PM
Basically looping the array is always O(n)
6:43 PM
But a lookup from a set is at best O(1) and at worst O(n)
6:43 PM
So a small performance gain to be had
Avatar
🐨Dream Doctor🦘 3/21/2022 10:58 PM
Thanks everyone. Some great ideas there. Much appreciated.
Avatar
jraServerAPI 3/23/2022 8:53 AM
Is there a way to find out what player used the whistle/group command last? When someone whistles a dino to attack something, I'm trying to get the player that sent that command. So I've been trying to see if dino->IsOwnedOrControlledBy(AActor* TestOwner) will work, but I can't seem to get a valid AActor reference from AShooterPlayerController to pass to the function, if even possible. c++ if (dino->IsOwnedOrControlledBy(player_controller->RootComponentField()->GetOwner())) { } this doesnt work.. I'm not even sure if IsOwnedOrControlledBy is the right function. Thanks!
10:32 AM
class AShooterPlayerController* AttackMyTargetForPlayerController; on primaldinocharacter, or maybe hook the function telling it to attack target
Avatar
jraServerAPI 3/23/2022 11:59 AM
Hmmm I tried dino->AttackMyTargetForPlayerControllerField() and it returns nullptr, and I looked for the hook, but was unable to find it
Avatar
Avatar
jraServerAPI
Is there a way to find out what player used the whistle/group command last? When someone whistles a dino to attack something, I'm trying to get the player that sent that command. So I've been trying to see if dino->IsOwnedOrControlledBy(AActor* TestOwner) will work, but I can't seem to get a valid AActor reference from AShooterPlayerController to pass to the function, if even possible. c++ if (dino->IsOwnedOrControlledBy(player_controller->RootComponentField()->GetOwner())) { } this doesnt work.. I'm not even sure if IsOwnedOrControlledBy is the right function. Thanks!
void Hook_AShooterCharacter_ServerCallAttackTarget_Implementation(AShooterCharacter* _this, AActor* TheTarget)
12:42 PM
you can just not return original in this hook and the dino won't attack anything btw (edited)
Avatar
jraServerAPI 3/23/2022 4:16 PM
Hmm.. so I'm trying to figure out the dino or dinos that were whistled, or is currently under a whistle command.. This gives me the target of the whistle, but not the dinos doing the deed (edited)
Avatar
jraServerAPI 3/23/2022 5:09 PM
was really hoping for something on the dino that represents if the dino is currently under a whistle command and by what player.... But I think I'll have to figure out a work around (edited)
Avatar
Could hook what Wetbatman said, make your own cached data, and retrieve it when needed
5:10 PM
Hook triggered -> store in a map<dino, player> as sort of "last player who whistled the dino" -> do your things with it (edited)
5:14 PM
Maybe not that hook now that I double check it lol 🤐
Avatar
jraServerAPI 3/23/2022 5:16 PM
The problem is, the hook does not include the dino
5:16 PM
TheTarget is the object getting attacked, not the dino
Avatar
Try to find another
Avatar
jraServerAPI 3/23/2022 5:17 PM
yeah, i've been looking
5:18 PM
really thought this was it dino->IsOwnedOrControlledBy(), but I can't get anything but null from it
5:18 PM
Avatar
Avatar
jraServerAPI
yeah, i've been looking
decompile this func in ida
5:29 PM
and check how it tells the dino to attack the target
5:30 PM
then just rewrite that on your own
Avatar
jraServerAPI 3/23/2022 5:31 PM
monkaW
Avatar
Avatar
jraServerAPI
monkaW
check out void ServerDinoOrder(class APrimalDinoCharacter* aDino, EDinoTamedOrder::Type OrderType, AActor* target ); This gets called inside the function wetbatman mentioned (edited)
5:41 PM
And for the OrderType just look for EDinoTamedOrder::SetAggressionAttackTarget
5:46 PM
i think theres serverdinoorder_group too you might wanna capture
Avatar
jraServerAPI 3/23/2022 6:41 PM
hmm I hooked ServerDinoOrder, but It only seems to fire when a group is selected and whistled a global command with no target.. like Aggressive, or Passive, using the hotkeys or the dino behavior menu.. When I have a group selected and I target something to attack using the . key.. that's what i'm trying to capture, the player that made the attack command and the dino that is attacking (edited)
Avatar
Avatar
dougy
check out void ServerDinoOrder(class APrimalDinoCharacter* aDino, EDinoTamedOrder::Type OrderType, AActor* target ); This gets called inside the function wetbatman mentioned (edited)
jraServerAPI 3/23/2022 6:42 PM
also ty for your help 🙂 (edited)
Avatar
jraServerAPI 3/25/2022 9:29 PM
How do I get to, and alter FWeaponData for a specific Item? I'd like see if I can modify things like: bInfiniteAmmo, TimeBetweenShots etc.. I'm assuming the field I need to access is UPrimalItem->AssociatedWeaponField() however that is always null when I check it... Where is this data hiding? 🙂
Avatar
Avatar
jraServerAPI
How do I get to, and alter FWeaponData for a specific Item? I'd like see if I can modify things like: bInfiniteAmmo, TimeBetweenShots etc.. I'm assuming the field I need to access is UPrimalItem->AssociatedWeaponField() however that is always null when I check it... Where is this data hiding? 🙂
In the balls
10:37 PM
Jk will see if I can’t find it
Avatar
Avatar
substitute
In the balls
jraServerAPI 3/25/2022 10:50 PM
haha 🙂 I'm specifically trying to change some settings on the cryopod, so when I spawn one via code and use it once, it wont get removed (as it currently does).. I found the cryopods FWeaponData in the DevKit and see that it's set like the image below, so I need to replicate this in my code. (edited)
10:54 PM
Because i think by default it will inherit the FWeaponData settings of a grenade
Avatar
It should use whatever is in the blueprint
10:59 PM
Weird
Avatar
jraServerAPI 3/25/2022 11:01 PM
I cant get to the value to see what it is
11:02 PM
11:03 PM
AssociatedWeaponField() is null 😦
Avatar
That field is only populated when ur holding the weapon
11:06 PM
Or when a player is holding the weapon
Avatar
jraServerAPI 3/25/2022 11:06 PM
ok
11:06 PM
let me try to equip first
Avatar
U could jusr do get current weapon too to get the weapon itself and modify those values
11:07 PM
But yeah tru equipping
11:07 PM
The client will still think the values are the same tho
11:08 PM
U need a mod or something to change it client side
Avatar
Avatar
jraServerAPI
haha 🙂 I'm specifically trying to change some settings on the cryopod, so when I spawn one via code and use it once, it wont get removed (as it currently does).. I found the cryopods FWeaponData in the DevKit and see that it's set like the image below, so I need to replicate this in my code. (edited)
Cryo's don't disappear by default you have to set them to be one time use.
Avatar
jraServerAPI 3/25/2022 11:09 PM
I'm not seeing that setting Lethal
Avatar
jraServerAPI 3/25/2022 11:30 PM
okay, it was populated after equip (and a small delay) I changed the values, but it did not work. @Lethal Looking at the cryopod code in ArkShop, i do not see this setting you are talking about. When I throw out the dino, the cryopod still gets removed right away. (edited)
Avatar
If you copied my code from that then it is working as intended.
11:34 PM
There is an FName added that makes it one time use
Avatar
jraServerAPI 3/25/2022 11:36 PM
oooh is that what MissionTemporary means?
11:37 PM
i will have to test... thanks!
11:38 PM
well i'll be
Avatar
Avatar
jraServerAPI
okay, it was populated after equip (and a small delay) I changed the values, but it did not work. @Lethal Looking at the cryopod code in ArkShop, i do not see this setting you are talking about. When I throw out the dino, the cryopod still gets removed right away. (edited)
yeah those values arent replicated if u just change them on server
4:58 AM
the client will remain w/ the original values
Avatar
Aaurizon (Ryan) 3/30/2022 2:48 AM
How can I get the principal HeavyTurret ( the APrimalStructure used to create others ) I tried this, but nothing... UWorld* World = ArkApi::GetApiUtils().GetWorld(); for (UObject* object : World->ExtraReferencedObjectsField()) { if (object != nullptr) { // never called... } }
2:51 AM
To explain what I'm trying to do, I would like to change the default behavior of all turrets, I think there is a default one that is used for all those placed?
Avatar
Avatar
Aaurizon (Ryan)
How can I get the principal HeavyTurret ( the APrimalStructure used to create others ) I tried this, but nothing... UWorld* World = ArkApi::GetApiUtils().GetWorld(); for (UObject* object : World->ExtraReferencedObjectsField()) { if (object != nullptr) { // never called... } }
jraServerAPI 3/30/2022 5:56 AM
I'm not sure if that is possible or not. I think you need to use the UGameplayStatics::GetAllActorsOfClass function to find all the turrets in the game and change them there. Or maybe hook the event that fires when you place them and change the settings there.
Avatar
Avatar
jraServerAPI
I'm not sure if that is possible or not. I think you need to use the UGameplayStatics::GetAllActorsOfClass function to find all the turrets in the game and change them there. Or maybe hook the event that fires when you place them and change the settings there.
Aaurizon (Ryan) 3/30/2022 6:02 AM
I think it's possible, because when I do structureFound->ClassField()->GetDefaultObject(false) that give me the default object, but I get it from a placed structure... That require the structure already placed on the server. Ark server have bad perfs, so I would have liked to save perfs by doing the action only at startup and not every time :/ I probably have to find myself the offset where are listed the original structures
Avatar
try GetDefaultObject(true)
6:23 AM
or am i reading what your asking wrong
6:28 AM
oh nvm i see what you mean
Avatar
Aaurizon (Ryan) 3/30/2022 6:29 AM
Isn't that, but I found a dirty solution, it's to spawn a structure and use the spawned structure to get the DefaultObject
Avatar
Like you want the default object for BlueprintGeneratedClass StructureTurretBaseBP_Heavy.StructureTurretBaseBP_Heavy_C right
6:33 AM
the placed heavy turret
Avatar
Aaurizon (Ryan) 4/2/2022 1:03 PM
Hello, what's the best way to display text on a specific position of the screen ? It's AHUD or better way exist ?
Avatar
Aaurizon (Ryan) 4/2/2022 2:43 PM
I'm trying to modify the notification text, to display the players online counter, on a side of the screen like KalsSpyGlass Or to modify the LeftSide Text (the player HUD when we press H)
Avatar
I'm not aware of any positional text areas we can push custom data into from the server side.
Avatar
Avatar
Aaurizon (Ryan)
Hello, what's the best way to display text on a specific position of the screen ? It's AHUD or better way exist ?
TheMollusk 4/3/2022 4:29 PM
The nicest way I've found to persistently display and modify text on a player's screen is with AShooterPlayerController::ClientServerNotificationSingle(). It's attached to the top of the screen though, not quite as flexible as what you're looking for. C++ AShooterPlayerController::ClientServerNotificationSingle(FString* MessageText, FLinearColor MessageColor, float DisplayScale, float DisplayTime, UTexture2D* MessageIcon, USoundBase* SoundToPlay, int MessageTypeID) You can do things like: C++ // Display a notification spc->ClientServerNotificationSingle(&message1, FColorList::Green, 0.6f, FLT_MAX, nullptr, nullptr, MY_MSG_ID); // Edit the notification to display new text spc->ClientServerNotificationSingle(&message2, FColorList::Green, 0.6f, FLT_MAX, nullptr, nullptr, MY_MSG_ID); // Hide the notification spc->ClientServerNotificationSingle(&message2, FColorList::Green, 0.6f, 0, nullptr, nullptr, MY_MSG_ID);
👌 1
Avatar
jraServerAPI 5/1/2022 5:17 AM
Is it possible to paint a structure? I know we can paint dino's, but what about structures? I've been looking around, trying a few things, but no luck yet.
Avatar
jraServerAPI 5/1/2022 6:22 AM
my problem was I'm testing on structures that cannot be painted.. "oops"
6:23 AM
😆
Avatar
Hello. I am saving inventory items to the disk. I don't know it faster to save to disk or to mysql database. I assume it would be fast to save to disk because the mysql have to save to disk too. Does anyone have some insight on this topic?
Avatar
sql for sure, it's not to disc at first
9:51 PM
disc will always be the slower option
👍 1
Avatar
i am trying to add to a cryopod durability, when i do item->AddItemDurability((item->ItemDurabilityField()), the cryopod time goes to 30 days, but after a few seconds it breaks. This is a cryopod with a dino loaded from another map
12:26 AM
setting NextSpoilingTimeField does nothing. Does anyone know why it breaks and the creature ends up dead after a few seconds?
Avatar
jraServerAPI 5/2/2022 12:28 AM
is it a cryopod from the game, or one you are creating via code?
Avatar
from the game
Avatar
jraServerAPI 5/2/2022 12:29 AM
isn't it 30 days by default?
12:29 AM
i forget
Avatar
yes, 30 days
12:30 AM
for soem reason when i AddItemDurability, it dies after a few seconds
Avatar
jraServerAPI 5/2/2022 12:30 AM
are you trying to recharge it?
Avatar
yes, i want to make it full 30 days
12:31 AM
o did no test with a cryopod created from the code, do you think it will do any different ?
Avatar
jraServerAPI 5/2/2022 12:33 AM
i think you just want to set it directly item->ItemDurabilityField() = floatNewValue;
12:34 AM
and then maybe item->UpdatedItem(false);
Avatar
is i doit, the charge goes for 157 for one map and 1 hour for another
12:34 AM
i cant make any sense of it
Avatar
Avatar
Uaca
is i doit, the charge goes for 157 for one map and 1 hour for another
only after a few seconds, it starts with about 500 days (edited)
Avatar
jraServerAPI 5/2/2022 12:34 AM
lol
12:35 AM
did you check the dev kit? maybe see how the recharging structure does it
Avatar
no, I did no mess around with the dev kit
Avatar
jraServerAPI 5/2/2022 12:36 AM
i havent tried messing around with that yet, so I dont have any experience.. it seems like something easy to do, tho
12:36 AM
but the dev kit might show you the proper usage, if you can find it
Avatar
i am going to try a little more, if I cant find anything will try the dev kit, I hear it is uses a lot of ram
Avatar
jraServerAPI 5/2/2022 12:41 AM
oh yeah.. it takes about 2 weeks to load up
12:41 AM
lol
12:44 AM
have a look at this..
Avatar
yeah, it feels odd to change the ItemDurabilityField, it looks like it is the max Durability, like it you set it on armor, it is the durability maximum armor and not the current durability
1:19 AM
but for cryopods it is the current durability
Avatar
UVictoryCore::ServerOctreeOverlapActors(&OutActors, ArkApi::GetApiUtils().GetWorld(), , radius, EServerOctreeGroup::STRUCTURES, false);
5:53 AM
this does not find missiondispatcher on genesis 1 and 2 (edited)
5:53 AM
the mission dispatcher is not a structure?
Avatar
jraServerAPI 5/20/2022 5:56 AM
could be a dino.. just like a raft is a dino right?
5:56 AM
although idk
Avatar
It is an AActor, not a structure
Avatar
well, that is a surprise
Avatar
ok, now I am trying to figure out how to find near by mission dispatcher, I would assume the EServerOctreeGroup::MAX would list everything, but it also does not list the mission dispatcher
Avatar
Avatar
Uaca
ok, now I am trying to figure out how to find near by mission dispatcher, I would assume the EServerOctreeGroup::MAX would list everything, but it also does not list the mission dispatcher
You could just use UKismetSystemLibrary::SphereOverlap_NEW and set the class as AMissionDispatcher::GetPrivateStaticClass() (edited)
Avatar
Avatar
Pelayori
You could just use UKismetSystemLibrary::SphereOverlap_NEW and set the class as AMissionDispatcher::GetPrivateStaticClass() (edited)
i dotn have a AMissionDispatcher::GetPrivateStaticClass(), but APrimalStructureItemContainer::GetPrivateStaticClass() worked! Ty!
👍 1
Avatar
jraServerAPI 8/20/2022 2:36 AM
Can someone help me understand what is goin on here? I wanted to test out sockpp as a way to communicate to my plugin on other maps, and all I did was add the include to my project and I get 161 errors having to do with winsock etc.. 6847_feelsglassesman I don't even know where to begin 3389_peepoDetective
2:39 AM
Modern C++ socket library. Contribute to fpagliughi/sockpp development by creating an account on GitHub.
Avatar
Avatar
jraServerAPI
Can someone help me understand what is goin on here? I wanted to test out sockpp as a way to communicate to my plugin on other maps, and all I did was add the include to my project and I get 161 errors having to do with winsock etc.. 6847_feelsglassesman I don't even know where to begin 3389_peepoDetective
I would start with a simple hello world app
4:55 AM
And work backwards from there
Avatar
jraServerAPI 8/20/2022 4:57 AM
yeah i just found a youtube video..i'm going to watch and do just that
Avatar
Also I like what you’re doing, I suggest though maybe trying to make it a standard
4:57 AM
Like how permissions is
4:57 AM
So everyone isn’t making a million sockets for their plugins
Avatar
jraServerAPI 8/20/2022 4:57 AM
he';s using VS 2015 (edited)
Avatar
Just reuse the existing socket
Avatar
jraServerAPI 8/20/2022 4:58 AM
yeah good idea 🙂
Avatar
Avatar
jraServerAPI
Can someone help me understand what is goin on here? I wanted to test out sockpp as a way to communicate to my plugin on other maps, and all I did was add the include to my project and I get 161 errors having to do with winsock etc.. 6847_feelsglassesman I don't even know where to begin 3389_peepoDetective
add #define WIN32_LEAN_AND_MEAN in preprocessor definitions
👍 1
12:47 PM
or before your first socketpp include
12:47 PM
12:47 PM
then includes look like this
12:52 PM
you can ignore the pluaes.hpp HWIDBans.h and the random include
12:52 PM
rest are sockpp (edited)
Avatar
jraServerAPI 10/2/2022 7:25 PM
Can someone tell me the best way to capture this action?
7:25 PM
7:26 PM
I tried hooking *Hook_UPrimalInventoryComponent_TransferAllItemsToInventory * but it does not get fired when I press the transfer all button (edited)
Avatar
jraServerAPI 10/2/2022 10:14 PM
Seems like Hook_UPrimalInventoryComponent_RemoteInventoryAllowAddItems is the only viable solution
Avatar
does anyone know the plugin for kill stats?
Avatar
jraServerAPI 10/4/2022 7:19 PM
did you check the website?
7:19 PM
This resource category offers resource content for the video game "Ark Survival Evolved".
Avatar
Avatar
jraServerAPI
Seems like Hook_UPrimalInventoryComponent_RemoteInventoryAllowAddItems is the only viable solution
what about ServerTransferAllToRemoteInventory_Implementation or ServerTransferAllFromRemoteInventory_Implementation
Avatar
Avatar
dougy
what about ServerTransferAllToRemoteInventory_Implementation or ServerTransferAllFromRemoteInventory_Implementation
jraServerAPI 10/5/2022 10:47 PM
i'll have to test it.. I tested the versions without _Implementation and they never got fired
Avatar
ah yeah, try the _implementation ones they 100% should get fired
5:04 AM
the ones w/ out it are for the client to call like client calls -> ServerTransferAllFromRemoteInventory server runs -> ServerTransferAllFromRemoteInventory_Validate (if it exists) and ServerTransferAllFromRemoteInventory_Implementation
5:07 AM
for any function thats flagged as being a server rpc, then its opposite way for client rpcs
5:08 AM
idk if ark really makes use of the WithValidation flag tho so theres prob not many _Validate functions
Avatar
https://docs.unrealengine.com/4.26/en-US/ProgrammingAndScripting/GameplayArchitecture/Functions/ There's some good information about _Implementation functions here. They get declared when C++ functions are specified as certain types of UFunctions. They get called by the auto-generated code used to call native UFunctions from Blueprint scripts. So if there's an _Implementation version of the function, that's usually what you want. _Implementation functions can sometimes be overridden in Blueprint, or be client-only. I happen to know the native ServerTransferAll.... UFunctions are called on the server in this case, so hooking those native _Implementation functions should do the trick.
Reference for creating and implementing functions for gameplay Classes
👍 1
Avatar
jraServerAPI 10/6/2022 7:34 PM
Awesome.. thank you both for the helpful information!!
Avatar
jraServerAPI 10/24/2022 11:17 PM
I wanted to fiddle with line tracing and after searching the group I found a conversation from 2020 with Pelayori and Lethal that got me going. I just wanted to share a snippet of code I just got working. This snippet should trace a small line in the direction your character is facing and return a hit result. If you are riding a dino, it will draw the line from the dino instead. c++ auto world = ArkApi::GetApiUtils().GetWorld(); FLinearColor red = FLinearColor(1, 0, 0); auto playerComponent = player_controller->GetPlayerCharacter()->RootComponentField(); auto ridingDino = player_controller->GetPlayerCharacter()->RidingDinoField().Get(); FVector ForwardVector; playerComponent->GetForwardVector(&ForwardVector); FVector StartLocation = playerComponent->RelativeLocationField(); if (ridingDino) { StartLocation = ridingDino->RootComponentField()->RelativeLocationField(); } FVector EndLocation = ((ForwardVector * 1000.f) + StartLocation); Log::GetLog()->warn("StartLocation={},{},{}", StartLocation.X, StartLocation.Y, StartLocation.Z); Log::GetLog()->warn("EndLocation={},{},{}", EndLocation.X, EndLocation.Y, EndLocation.Z); static int FHitResultStructSize = GetStructSize<FHitResult>(); FHitResult* hit = static_cast<FHitResult*>(FMemory::Malloc(FHitResultStructSize)); RtlSecureZeroMemory(hit, FHitResultStructSize); player_controller->MulticastDrawDebugLine(StartLocation, EndLocation, red, 30, 10.0, true); // show trace line auto hit2 = UVictoryCore::VTraceSingleBP(world, hit, &StartLocation, &EndLocation, ECollisionChannel::ECC_Visibility, 0, FName("None", EFindName::FNAME_Add), true, nullptr); if (hit) { if (hit->bBlockingHit()()) // we hit something { auto actor = hit->GetActor(); if (actor) { auto blueprint = ArkApi::GetApiUtils().GetBlueprint(actor); Log::GetLog()->warn("Actor={}", blueprint.ToString()); // what did we hit? } } } FMemory::Free(hit); (edited)
Avatar
Is there a way to list structures for the whole map? Something like ServerOctreeOverlapActors but with no radius or maybe a array with all structures on map?
Avatar
UGameplayStatics::GetAllActorsOfClass
12:24 AM
You can also octree the entire map with a radius of millions of unit, someone said it was more performant than GAAOC
Avatar
I was trying to get all c4 on the map to remove when enabling PVE mode, i was under the impression that I could list all c4, but you need to list all structures and interate to find all c4. Does not sound like a good ideia anymore
Avatar
Avatar
Uaca
I was trying to get all c4 on the map to remove when enabling PVE mode, i was under the impression that I could list all c4, but you need to list all structures and interate to find all c4. Does not sound like a good ideia anymore
If it's not done just on startup you will need to iterate (if you do on startup you could hook begin play and find c4 until some seconds after full startup)
1:40 PM
Also there is ways to make that and no cause server hiccups, you could GAAOC, and destroy them on batches, or octree the whole map and destroy in batches as well
1:41 PM
If you use the primal structure explosive class filter, you'd only get c4 and therefore not waste iterations on non c4
Avatar
the structure explosive class filter is odd, it list all the Halloween stuff but does not list c4
Avatar
Placed c4 are child of primal structure explosive, I know that for a fact
1:47 PM
Unless the get class function is not redefined for that class
Avatar
Avatar
Uaca
the structure explosive class filter is odd, it list all the Halloween stuff but does not list c4
Try using this: static UClass* StaticClass() { return NativeCall<UClass*>(nullptr, "APrimalStructureExplosive.StaticClass"); }
2:05 PM
Since get private static class is not defined, although could define it as well as static UClass* GetPrivateStaticClass() { return NativeCall<UClass*>(nullptr, "APrimalStructureExplosive.GetPrivateStaticClass"); } (edited)
Avatar
That is nice! Ty!
Avatar
When using the get static class of a not so used class, it's a good practise to check if the function is redefined for that particular class, or is inherited from parent (which isn't bad either, but wont give the results you expect)
Avatar
I just got the last version of the source from Game Servers Hub, I think I am missing something here, it says APrimalDinoCharacter has no member FindProperty
Avatar
Did you try compiling?
11:44 PM
That's usually intellisense being dumb for me
Avatar
Avatar
Pelayori
Did you try compiling?
yes, is is not compiling (edited)
Avatar
Hmm, I haven't seen anything weird recently
Avatar
do you have the last version from github?
Avatar
I think so
12:44 AM
Definetely doesn't seem that was changed any time recently
Avatar
restarted everything and compiled the arkapi
12:51 AM
now it is working
Avatar
Is there still a way to load plugin while the server is live ?
Avatar
Avatar
Cryda
Is there still a way to load plugin while the server is live ?
yeah, here's the config
147 bytes
5:30 PM
it is broken on some systems like Windows 11 (edited)
5:31 PM
But perfectly works on Windows 10
Avatar
yea thnx ! im running on win 10
Avatar
Hello can someone help me how to download and install API for tebex please ? So i cn have shop in the game ?
Avatar
yes but problem is...when i open ShooterGame\Binaries\Win64\ArkApi\Plugins so there is max Win64. When i open win64 so there is not arkapi
7:32 PM
so where i have put it ?
Avatar
jraServerAPI 1/31/2023 7:34 PM
Ark Server API Original Author: @Michidu Maintainer: @Lethal @Pelayori @Foppa @WETBATMAN Product Description: This tool allows you to load plugins into your gaming communities; this is an open-source community-supported "API" required for...
Avatar
I do everythink like in video and my game crah before start. Its a Fatal error. Weird
Avatar
jraServerAPI 1/31/2023 9:20 PM
You need to install "Microsoft Visual C++ 2019 Redistributable Package" for the API to load correctly.
Avatar
Avatar
Scrappy
I do everythink like in video and my game crah before start. Its a Fatal error. Weird
substitute 2/1/2023 2:34 AM
Your GAME?
2:34 AM
You’re doing it wrong then
2:34 AM
It goes on the server
2:34 AM
Also this is the wrong discord for these questions
Avatar
hello, on ARK DEV KIT i want create a buttom to get a item to the player inventory who can help me ? i have creat the menu and the buttom i juste want to click and get item (for exemple pickaxe) to the player inventory
Avatar
Any way to get command input in AddChatCommand? like in /shop command if i put /shop 2 shows next page, like detects if ill add a number after command and save it
Avatar
Avatar
Loki
Any way to get command input in AddChatCommand? like in /shop command if i put /shop 2 shows next page, like detects if ill add a number after command and save it
TheMollusk 2/9/2023 2:45 AM
The signature for a chat command function is void AChatCmd(AShooterPlayerController* spc, FString* input, EChatSendMode::Type). So you can get the command from input
Avatar
Avatar
TheMollusk
The signature for a chat command function is void AChatCmd(AShooterPlayerController* spc, FString* input, EChatSendMode::Type). So you can get the command from input
substitute 2/9/2023 6:20 AM
More specifically the input contains the command and the args if I am remembering correctly
6:20 AM
So you’ll have to tokenize it yourself
Avatar
jraServerAPI 2/9/2023 6:34 AM
Yes, the ArkShop is a great example of parsing the command line/args like that
Avatar
is there any way to modify RandomMutationChanceField() and MaxAllowedRandomMutationsField() from a Fertilized egg?
Avatar
Avatar
Loki
is there any way to modify RandomMutationChanceField() and MaxAllowedRandomMutationsField() from a Fertilized egg?
dont think so from the egg state, the calculations are done tomake the egg, hooking DoMate where egg is made is what i just did.
Avatar
Using this hook bool Hook_AShooterGameMode_HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* player, UPrimalPlayerData* PlayerData, AShooterCharacter* PlayerCharacter, bool bIsFromLogin) { What is the best way to check if AShooterPlayerController* player is a structure? (Laying in a bed) I am trying to drop an inventory on login, it works fine unless they are laying in a bed.
Avatar
ThonkEyes A Controller isn't a structure. Ever.
Avatar
That is what I thought, but for some reason if they are in a bed, it crashes. if they are out of a bed, it will drop fine.
Avatar
crashes on what
Avatar
as soon as the player loads in
Avatar
We'd need to see your implementation.
Avatar
Avatar
Xeakial
as soon as the player loads in
on what function
Avatar
okay, I actually just rewrote it, one sec.
7:50 PM
APrimalStructureItemContainer* drop(APrimalCharacter* player, UPrimalInventoryComponent* inv, uint64 steamid) { if (inv) { if (MysticUser::database->checkoverflow(steamid)) { APrimalStructureItemContainer* cache = nullptr; FVector plocal = player->RootComponentField()->RelativeLocationField(); inv->DropInventoryDeposit(ArkApi::GetApiUtils().GetWorld()->GetTimeSeconds() + 7200, false, true, nullptr, nullptr, &cache, nullptr, FString(""), FString(""), -1, 300, false, -1, false, &plocal, true); //player->GetPlayerInventory()->DropInventoryDeposit(ArkApi::GetApiUtils().GetWorld()->GetTimeSeconds() + 7200, false, true, nullptr, nullptr, &cache, nullptr, FString(""), FString(""), -1, 300, false, -1, true, &plocal, true); Log::GetLog()->info("Dropping inventory for player id {}", steamid); MysticUser::database->resetoverflow(steamid); } } } bool Hook_AShooterGameMode_HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* player, UPrimalPlayerData* PlayerData, AShooterCharacter* PlayerCharacter, bool bIsFromLogin) { if (player && bIsFromLogin) { UPrimalInventoryComponent* inv = player->GetPlayerInventory(); APrimalCharacter* pchar = static_cast <APrimalCharacter*>(PlayerCharacter); uint64 steamid = ArkApi::GetApiUtils().GetSteamIdFromController(player); Log::GetLog()->info("player id {}", steamid); drop(pchar, inv, steamid); } return AShooterGameMode_HandleNewPlayer_original(_this, player, PlayerData, PlayerCharacter, bIsFromLogin); }
Avatar
and it crashes where?
Avatar
on inv->drop... but only if they are in a bed, if they are not in a bed, it works perfectly.
7:54 PM
I did the GetLog()->info to make sure steamid is present at all times, and it is. Just seems like its trying to drop the inventory of the bed instead of the player when they are sleeping in the bed. very odd.
7:58 PM
I use the same hook for other things and never have an issue, only seems to be when trying to interact with inventory.
Avatar
from what i can see on death they input a zero vector instead of the player location maybe you can try this too?
8:03 PM
Avatar
Dodo Enthusiast 3/28/2023 8:10 PM
Just a random guess but maybe using UPrimalInventoryComponent* inv = PlayerCharacter->MyInventoryComponentField(); is better in this case than using the controller to get the inventory;
Avatar
I will try both and get back to you, thank you.
Avatar
Well when I use UPrimalInventoryComponent* inv = PlayerCharacter->MyInventoryComponentField(); It crashes instantly when it gets to that line, that is in or out of a bed.
Avatar
Had to do the following to avoid crash, it wants InventoryComponentField() to only come from APrimalCharacter APrimalCharacter* pchar = static_cast <APrimalCharacter*>(PlayerCharacter); UPrimalInventoryComponent* inv = pchar->MyInventoryComponentField();
Avatar
Avatar
WETBATMAN
from what i can see on death they input a zero vector instead of the player location maybe you can try this too?
No luck with the FVector::ZeroVector, Using the above stops it from crashing if you are in a bed, but now the inventory just disappears if you are in a bed lol. Just can't win. is there any way to check if the playing is in a APrimalStructureBed that anyone knows of?
Avatar
Avatar
Xeakial
Well when I use UPrimalInventoryComponent* inv = PlayerCharacter->MyInventoryComponentField(); It crashes instantly when it gets to that line, that is in or out of a bed.
Dodo Enthusiast 3/29/2023 12:57 AM
With the following code it works for me in both cases without crash. It just drops the bag inside the foundation if you layed in a bed. Probably one of the many latter options can fix that. I will continue to try a bit aswell. void drop(AShooterCharacter* player, UPrimalInventoryComponent* inv, uint64 steamid) { if (!(inv && player)) return; FVector targetLoc; player->GetTargetingLocation(&targetLoc, player); APrimalStructureItemContainer* cache = nullptr; inv->DropInventoryDeposit(ArkApi::GetApiUtils().GetWorld()->GetTimeSeconds() + 7200, false, true, nullptr, nullptr, &cache, nullptr, FString(""), FString(""), -1, 300, false, -1, false, &targetLoc, true); Log::GetLog()->info("Dropping inventory for player id {}", steamid); } bool Hook_AShooterGameMode_HandleNewPlayer(AShooterGameMode* _this, AShooterPlayerController* player, UPrimalPlayerData* PlayerData, AShooterCharacter* PlayerCharacter, bool bIsFromLogin) { if (!(player && bIsFromLogin && PlayerCharacter)) return AShooterGameMode_HandleNewPlayer_original(_this, player, PlayerData, PlayerCharacter, bIsFromLogin); UPrimalInventoryComponent* invChar = PlayerCharacter->MyInventoryComponentField(); if (!invChar) return AShooterGameMode_HandleNewPlayer_original(_this, player, PlayerData, PlayerCharacter, bIsFromLogin); uint64 steamid = ArkApi::GetApiUtils().GetSteamIdFromController(player); Log::GetLog()->info("player id {}", steamid); drop(PlayerCharacter, invChar, steamid); return AShooterGameMode_HandleNewPlayer_original(_this, player, PlayerData, PlayerCharacter, bIsFromLogin); } (edited)
Avatar
Worst case you can do a delay execute with 0 delay and it will probably be good
Avatar
Avatar
Pelayori
Worst case you can do a delay execute with 0 delay and it will probably be good
Dodo Enthusiast 3/29/2023 1:01 AM
Yeah it somehow does not see the foundation as far as I can tell. Don't know if its a "need some time" issue or one of the many settings.
Avatar
Handle new player might be too early
Avatar
I have already tried with void Hook_AShooterCharacter_PossessedBy(AShooterCharacter* _this, AController* InController) as well , I am kind of taken back on how the following is working for youUPrimalInventoryComponent* invChar = PlayerCharacter->MyInventoryComponentField(); I kept getting complete crashes with it, but will try again, and incorporate a delay.
1:05 AM
Thank you all for the help though, I really appreciate it.
Avatar
Have you tried calling the original first.
1:07 AM
Then doing your execution?
Avatar
I have not that I know of, I have tried several different methods though. (edited)
Avatar
jraServerAPI 3/29/2023 2:20 AM
it works with a delay, i just tested with a 5 second delay and it does not crash
2:20 AM
2:20 AM
API::Timer::Get().DelayExecute(&drop, 5, player_character);
2:21 AM
i just changed it to do all the inventory work inside the function
2:22 AM
2:22 AM
👍
Avatar
nice, I am loading it now, but only did a 3 second delay in mine. I should have considered the delay because I use it in my other plugin for getting usernames, just figured since I know steam id is available it would be quick enough.
2:29 AM
If not, I will try a 5 second, thank you.
Avatar
Dodo Enthusiast 3/29/2023 2:37 AM
what also seems to work is to explicitly set the cache location, which seems a bit more hacky to be fair ^^ void drop(AShooterCharacter* player, UPrimalInventoryComponent* inv, uint64 steamid) { if (!(inv && player)) return; FVector targetLoc; player->GetTargetingLocation(&targetLoc, player); APrimalStructureItemContainer* cache = nullptr; inv->DropInventoryDeposit(ArkApi::GetApiUtils().GetWorld()->GetTimeSeconds() + 7200, false, true, nullptr, nullptr, &cache, nullptr, FString(""), FString(""), -1, 300, false, -1, false, &targetLoc, true); if (cache) { targetLoc.Z -= 100; //because the locations seems to be more where the head would be cache->SetActorLocation(&targetLoc, false); } Log::GetLog()->info("Dropping inventory for player id {}", steamid); }
Avatar
Avatar
Dodo Enthusiast
what also seems to work is to explicitly set the cache location, which seems a bit more hacky to be fair ^^ void drop(AShooterCharacter* player, UPrimalInventoryComponent* inv, uint64 steamid) { if (!(inv && player)) return; FVector targetLoc; player->GetTargetingLocation(&targetLoc, player); APrimalStructureItemContainer* cache = nullptr; inv->DropInventoryDeposit(ArkApi::GetApiUtils().GetWorld()->GetTimeSeconds() + 7200, false, true, nullptr, nullptr, &cache, nullptr, FString(""), FString(""), -1, 300, false, -1, false, &targetLoc, true); if (cache) { targetLoc.Z -= 100; //because the locations seems to be more where the head would be cache->SetActorLocation(&targetLoc, false); } Log::GetLog()->info("Dropping inventory for player id {}", steamid); }
The delay works good, I am going to try your method too, honestly the more visible it is the better, then no one can say they "could not find it".
Avatar
jraServerAPI 3/29/2023 2:50 AM
you're also going to want to check the inv->ItemSlotsField(); for items on the player hotbar.. you will need to loop thru them and add them to the cache bag 👍
2:51 AM
because they wont drop by default
Avatar
I actually am leaving hotbar and armor, its for a self help of bufferoverflow when they transfer with too many items. (edited)
Avatar
jraServerAPI 3/29/2023 2:52 AM
i mean this hotbar
2:52 AM
2:52 AM
those will not drop with DropInventoryDeposit
2:52 AM
oh okay you're leaving it
2:52 AM
np
Avatar
yeah, it can stay, I am fine with that. main idea is get the 300 soulballs they keep transfering with
2:53 AM
saves my admins from logging in to rescue people all the time.
Avatar
@Pelayori tried to go with the idea you had about nullifying item drops on dinos, hooked initialize of inventory component, and identifying drops using dinodrop would work, but it doesnt seem to show the loot thats dropping. I killed bronto here and no item listed. neither from kill that went to dinos inventory nor ranged kill where it stayed in the brontos inv, so this is too early. ultimately gonna need to hook where loot can be generated i think. Going to bed now just wanted to drop while fresh on mind / screenshot. void Hook_UPrimalInventoryComponent_InitializeInventory(UPrimalInventoryComponent* _this) { UPrimalInventoryComponent_InitializeInventory_original(_this); LOG->info("Initialize: " + _this->ClassField()->NameField().ToString().ToString()); for (auto &&item: _this->InventoryItemsField()) { LOG->info("Item: " + item->NameField().ToString().ToString()); } }
10:08 AM
also holy hell this method gets called a lot for tamed stuff too
10:08 AM
game seems maybe buggy on calling it over and over again?
10:09 AM
even on stuff that should be in stasis
Avatar
There’s another function called Generate Crate Items which I’m not sure if it’s used by Dino drop invs
10:09 AM
It’s used for supply crates but the principle behind supply crates and Dino drop invs is pretty much the same
Avatar
Avatar
Aikar
@Pelayori tried to go with the idea you had about nullifying item drops on dinos, hooked initialize of inventory component, and identifying drops using dinodrop would work, but it doesnt seem to show the loot thats dropping. I killed bronto here and no item listed. neither from kill that went to dinos inventory nor ranged kill where it stayed in the brontos inv, so this is too early. ultimately gonna need to hook where loot can be generated i think. Going to bed now just wanted to drop while fresh on mind / screenshot. void Hook_UPrimalInventoryComponent_InitializeInventory(UPrimalInventoryComponent* _this) { UPrimalInventoryComponent_InitializeInventory_original(_this); LOG->info("Initialize: " + _this->ClassField()->NameField().ToString().ToString()); for (auto &&item: _this->InventoryItemsField()) { LOG->info("Item: " + item->NameField().ToString().ToString()); } }
Dodo Enthusiast 4/1/2023 1:38 PM
I played around with the problem a bit aswell. Maybe the following does what you want to do from a different angle. struct FSupplyCrateItemEntry { uint8 _padding[0x90]; TArray<TSubclassOf<UPrimalItem>>& ItemsField() { return *GetNativePointerField<TArray<TSubclassOf<UPrimalItem>>*>(this, "FSupplyCrateItemEntry.Items"); } float& ChanceToActuallyGiveItemField() { return *GetNativePointerField<float*>(this, "FSupplyCrateItemEntry.ChanceToActuallyGiveItem"); } }; struct FSupplyCrateItemSet { uint8 _padding[0x40]; TArray<FSupplyCrateItemEntry>& ItemEntriesField() { return *GetNativePointerField<TArray<FSupplyCrateItemEntry>*>(this, "FSupplyCrateItemSet.ItemEntries"); } }; void removeItems(UClass* baseInventoryClass, TArray<UClass*>& itemsToRemove) { for (auto i = 0; i < Globals::GUObjectArray()().ObjObjects.NumElements; i++) { auto obj = Globals::GUObjectArray()().ObjObjects.GetObjectPtr(i)->Object; if (obj != nullptr) { if (obj->IsA(baseInventoryClass)) { UProperty* setProperty = Dodo::UObjectUtils::findProperty(obj,"AdditionalItemSets"); if (!setProperty) continue; TArray<FSupplyCrateItemSet> itemSets = setProperty->Get<TArray<FSupplyCrateItemSet>>(obj); for (auto& itemSet : itemSets) { for (auto& entry : itemSet.ItemEntriesField()) { for (auto& item : entry.ItemsField()) { if (itemsToRemove.Contains(item.uClass)) { entry.ChanceToActuallyGiveItemField() = 0; } } } } setProperty->Set<TArray<FSupplyCrateItemSet>>(obj, itemSets); } } } } (edited)
1:38 PM
TArray<UClass*> setupItemsToRemove() { // probably best to make a loop from a config file TArray<UClass*> returnArr; FString itemPath = FString("Blueprint'/Game/PrimalEarth/CoreBlueprints/Resources/PrimalItemResource_ApexDrop_Sauro.PrimalItemResource_ApexDrop_Sauro'"); UClass* itemClass = UVictoryCore::BPLoadClass(&itemPath); if (!itemClass) return returnArr; returnArr.Add(itemClass); itemPath = FString("Blueprint'/Game/PrimalEarth/CoreBlueprints/Resources/PrimalItemResource_ApexDrop_Rex.PrimalItemResource_ApexDrop_Rex'"); itemClass = UVictoryCore::BPLoadClass(&itemPath); if (!itemClass) return returnArr; returnArr.Add(itemClass); return returnArr; } void Plugin_ServerReadyInit() { // for example inside shootergamemode begin play hook FString path = FString("Blueprint'/Game/PrimalEarth/CoreBlueprints/Inventories/DinoDropInventoryComponent_BP_Base.DinoDropInventoryComponent_BP_Base'"); UClass* baseInventoryClass = UVictoryCore::BPLoadClass(&path); if (!baseInventoryClass) return; TArray<UClass*> itemsToRemove = setupItemsToRemove(); if (itemsToRemove.Num() == 0) return; removeItems(baseInventoryClass, itemsToRemove); }
Avatar
@Dodo Enthusiast that seems to work for some things, like the apex, is there adiff property the loot like stone hatchets and stuff is in?
9:43 PM
looks like recipe notes arent in this pool either
Avatar
Avatar
Aikar
@Dodo Enthusiast that seems to work for some things, like the apex, is there adiff property the loot like stone hatchets and stuff is in?
Dodo Enthusiast 4/1/2023 10:03 PM
Yes it seems there are AdditionalItemSets with the Apex stuff and ItemSets where the other loot is in. The once I have checked out all use the property override itemset and use some default itemset lootitemset_survivor which has the usual berries and recipes and stone hatches in it. I might make a little free plugin out of it but didn't get around to really dig deeper into it for now. (edited)
Avatar
yeah i had just gotten to some the code in decompiler to see that prop right as i seen your msg lol
10:23 PM
looks like its finding stuff there just it crashed on setproperty so im trying w/o that as it shouldnt even be needed since mutating the object reference
10:25 PM
looks like its even finding stuff at plugin load time too but i do have it running again at beginplay still
10:25 PM
did it at onload to handle reloads
10:26 PM
interesting it crashed during start still
10:28 PM
DECLARE_HOOK(AShooterGameMode_BeginPlay, void, AShooterGameMode*); void removeProperty(UObject* obj, const char* property) { UProperty* setProperty = obj->FindProperty(FName(property, EFindName::FNAME_Find)); if (!setProperty) return; TArray<FSupplyCrateItemSet> itemSets = setProperty->Get<TArray<FSupplyCrateItemSet>>(obj); for (auto& itemSet : itemSets) { for (auto& entry : itemSet.ItemEntriesField()) { for (auto& item : entry.ItemsField()) { auto name = item.uClass->NameField().ToString(); if (name.Contains("_ApexDrop_") || name.Contains("RecipeNote_") || name.Contains("PrimalItemCostume_") || name.Contains("PrimalItemSkin_") || name.Contains("PrimalItemArmor_Cloth") || name.Contains("PrimalItemArmor_Hide") || name.Contains("PrimalItemArmor_Fur") || name.Contains("PrimalItemArmor_Chitin") || name.Contains("PrimalItemArmor_Metal") || name.Contains("PrimalItemArmor_Scuba") || name.Contains("PrimalItemConsumable_Berry") || name.Contains("PrimalItem_WeaponStone") || name.Contains("PrimalItem_WeaponMetal") || name.Contains("PrimalItem_WeaponGPS") || name.Contains("PrimalItem_WeaponCompass") || name.Contains("PrimalItem_WeaponSickle") || name.Contains("PrimalItem_WeaponBow_") || name.Contains("PrimalItem_WeaponTorch_") || name.Contains("PrimalItem_WeaponCrossBow_") || name.Contains("PrimalItem_WeaponBoomerang") || name.Contains("PrimalItem_WeaponMachined") || name.Contains("PrimalItem_WeaponGun") || name.Contains("PrimalItem_WeaponPike") || name.Contains("PrimalItem_WeaponGrenade") || name.Contains("PrimalItem_WeaponProd_") || name.Contains("PrimalItem_WeaponSpear") || name.Contains("PrimalItem_WeaponSlingshot") ) { LOG->info("Removed2: " + name.ToString()); entry.ChanceToActuallyGiveItemField() = 0; } else { LOG->info("Kept: " + name.ToString()); } } } } //setProperty->Set<TArray<FSupplyCrateItemSet>>(obj, itemSets); } void removeItems() { FString path = FString("Blueprint'/Game/PrimalEarth/CoreBlueprints/Inventories/DinoDropInventoryComponent_BP_Base.DinoDropInventoryComponent_BP_Base'"); UClass* baseInventoryClass = UVictoryCore::BPLoadClass(&path); for (auto i = 0; i < Globals::GUObjectArray()().ObjObjects.NumElements; i++) { auto obj = Globals::GUObjectArray()().ObjObjects.GetObjectPtr(i)->Object; if (obj == nullptr) { continue; } if (!obj->IsA(baseInventoryClass)) { continue; } removeProperty(obj, "AdditionalItemSets"); removeProperty(obj, "ItemSets"); } } void Hook_AShooterGameMode_BeginPlay(AShooterGameMode* mode) { AShooterGameMode_BeginPlay_original(mode); removeItems(); } void Load() { SET_HOOKV2(AShooterGameMode, BeginPlay); removeItems(); }
Avatar
Try adding a delay execute after the game mode begin play
Avatar
API::Timer::Get().DelayExecute(&removeItems, 1);
Avatar
since this only runs at start and not every drop dont think blueprint loading is useful here, easier to just do text matches
10:34 PM
are timers ran after beginplay? if so prob no benefit to hooking it then (edited)
10:35 PM
yeah seems like they are
Avatar
Dodo Enthusiast 4/1/2023 10:36 PM
I think you cant treat both itemset properties the same. Under additional you really directly have the set, but under itemsets the real set (atleast for most cases) is behind some itemsetoverride which is usually lootitemset_survivor. (edited)
Avatar
well codes currently appearing to find the items the same still
10:37 PM
it def logged stuff, but if it is using a diff struct the entry.ChanceToActuallyGiveItemField() = 0; could be wrong
10:38 PM
unless im crashing as it gets to one of those 'other' sets you are meaning
10:43 PM
any ideas what i can check in here and abort scanning those? it seems the parts that are consistent have the parts i care about atm
Avatar
Dodo Enthusiast 4/1/2023 10:43 PM
Yes I think the ChanceToActuallyGiveItemField=0 can affect more than one item. Which does not matter for apexdrops because there is usually just one and is maybe nice for the many recipes, but might not be the thing you want all the time.
10:43 PM
im on Omega mod so the vanilla stuffs pretty much useless here and just clutter for us
10:44 PM
it crashed at this point
10:44 PM
even with delay
10:45 PM
how do you get ida free to actually show structs?
10:46 PM
10:46 PM
structs tab doesnt show it
Avatar
Dodo Enthusiast 4/1/2023 10:46 PM
For me the view is called "local types"
Avatar
ohh that opened something new
Avatar
ultimately trying to learn so i can figure this stuff out on own - this is what I see: it has item entries at offset 10, yet you did uint8 _padding[0x40]; Why? like if I wanted to also read the overrides, i assume thats what i need to skip on atm to stop crashing right? though still confused what would make it crash since only seems to be 1 struct
Avatar
Dodo Enthusiast 4/1/2023 11:00 PM
Tbh the padding stuff is something I also just learned recently and other people know more about it. The padding is in this case the size of the struct because a TArrays needs to know the size at compile time. Usually with pointers you dont need that but in this case we need it. I think for this particular issue it would be really helpful to look at the devkit.
Avatar
yeah see the issue im seeing is your padding 0x40 to match the games struct, but then adding yet another field, so it no longer aligns with the games data size. This code should have had 10 byte padding before, then 20 byte padding after
11:06 PM
but im trying w/ the full struct
Avatar
Dodo Enthusiast 4/1/2023 11:12 PM
The way I understand it is that you need the padding because you actually don't declare a field with the getsomefield() function. But this is the time for someone else with more knowledge to step in^^
Avatar
ah because they are functions and not fields hmm
11:15 PM
struct FSupplyCrateItemEntry { uint8 _padding[0x18]; TArray<TSubclassOf<UPrimalItem>> Items; uint8 _padding2[0x5C]; float ChanceToActuallyGiveItem; uint8 _padding3[0x2]; }; is what i was expecting. long as my math wasnt off somewhere there lol
11:16 PM
otherwise what makes it know where the offset is, PDB?
Avatar
Dodo Enthusiast 4/1/2023 11:20 PM
I mean you could wonder that with basically all of the structs. How does AShooterController without any paddings know where everything is. I dont have an answer but would not mind getting one^^
Avatar
well ty for telling me about local types thats def a good view for seeing and copying the struct, maybe can get back to some other things wanted to poke now i can get ahold of structs
11:28 PM
im trying some things with the struct, ive done this kind of work many years ago, but used the pattern ^ above, but dunno if any black magic of this framework is changing expectations
11:28 PM
extracting out some things so i can find better where its crashing
Avatar
Dodo Enthusiast 4/1/2023 11:30 PM
To be fair in this case i think its not the padding that causes the crash. I played around with it a bit and it never crashed. Its probably some nullpointer thing if I had to guess. Do you have the devkit installed?
Avatar
im actually gonna want to remove the item vs drop chance anyways incase theres other items in that pool that are fine. and i do but no damn clue how to use it
Avatar
Dodo Enthusiast 4/1/2023 11:36 PM
I mean thats one more tool in the toolchain which is kinda annoying to learn xD and again I'm far from an expert but it helps you often times to know what ark is actually using to achieving something. (edited)
11:42 PM
For example in this case if you just search for sauropod you can find the base bp for the dino and open it. If you then search the default properties for "death" you see it uses a death inventory template "carnivorehuge...." and and you can open that and dig deeper basically^
Avatar
Dodo Enthusiast 4/1/2023 11:52 PM
Maybe one little tip if you really never used the devkit. If you look at the properties there is sometimes a little yellow arrow behind them which means someone (from wildcard) took the time to change the default value. Which usually is a good sign to start looking.
Avatar
I may have it, didnt crash this time
12:17 AM
struct FSupplyCrateItemEntry { uint8 _padding[0x18]; TArray<TSubclassOf<UPrimalItem>> Items; uint8 _padding2[0x68]; }; struct UPrimalSupplyCrateItemSet : UObject { FSupplyCrateItemSet ItemSet; }; struct FSupplyCrateItemSet { FString SetName; TArray<FSupplyCrateItemEntry,FDefaultAllocator> ItemEntries; float MinNumItems; float MaxNumItems; float NumItemsPower; float SetWeight; bool bItemsRandomWithoutReplacement; TSubclassOf<UPrimalSupplyCrateItemSet> ItemSetOverride; }; bool shouldFilter(FString& name) { return (.... truncated for paste); } struct RemoveUndesiredItems { bool operator()(const TSubclassOf<UPrimalItem>& item) const { if (!item.uClass) { return false; } auto name = item.uClass->NameField().ToString(); if (shouldFilter(name)) { //LOG->info("Removed: " + name.ToString()); return true; } else { //LOG->info("Kept: " + name.ToString()); return false; } } }; void filterItems(FSupplyCrateItemEntry& entry) { entry.Items.RemoveAll(RemoveUndesiredItems()); } void removeProperty(UObject* obj, const char* property) { UProperty* setProperty = obj->FindProperty(FName(property, EFindName::FNAME_Find)); if (!setProperty) return; TArray<FSupplyCrateItemSet> itemSets = setProperty->Get<TArray<FSupplyCrateItemSet>>(obj); for (auto& itemSet : itemSets) { LOG->info("ItemSet: " + itemSet.SetName.ToString()); for (auto entry : itemSet.ItemEntries) { filterItems(entry); } } }
12:17 AM
i think if (!item.uClass) { return false; } was source of crashes, i had a crash trying to ToString the FName there
12:17 AM
lack of that check i mean
12:18 AM
guessing there is a buggy entry in the pool
Avatar
behavior itself didnt work though hmm
Avatar
Dodo Enthusiast 4/2/2023 12:33 AM
Do you still use the same way of handling both AdditionalItemset and ItemSet?
Avatar
yeah but even the apex part didnt work, does itemset use a diff struct all together? the codes been looping over the itemset with same struct as additional just fine
Avatar
Dodo Enthusiast 4/2/2023 12:46 AM
the way i see it is that an itemset has some itemsetproperties and a link to another itemset which should be used instead. the additional are "a real" itemsets which have the information themselfes and the normal itemsets are imposters and just use a default itemset while still having the default properties of an itemset but are not using them.
Avatar
now i got the proper structs i can make it jump into ItemSetOverride too so ill try that
12:48 AM
but unless its unused copies not sure why it wouldnt work still as im mutating the objects
Avatar
Dodo Enthusiast 4/2/2023 12:48 AM
yes the stone pickaxe etc should be inside the itemsetoverride itemset
Avatar
yeah im consistently least not crashing now, now can get those sets filtered too
Avatar
Avatar
Aikar
otherwise what makes it know where the offset is, PDB?
yes
Avatar
@Dodo Enthusiast so this entire time i thought you was referencing the Override part of that struct, i now see its additional properties. where did you find that AdditionalItemSets was a TArray<FSupplyCrateItemSet>? Im searching all through the decompiler but struggling to find where this specific type is defined for the property to see what the Override ones are.
Avatar
dont know how to look at generated code in ida yet so using ghidra and ida both now lol, i see the adds here but it seems like they are all using the same: OuterClass = APrimalStructureItemContainer_SupplyCrate::StaticClass();
4:08 AM
ohh i spot one difference, UArrayProperty on ItemSets and UClassProperty on Override
Avatar
how does this UArrayProperty link to TArray's
Avatar
Avatar
Aikar
dont know how to look at generated code in ida yet so using ghidra and ida both now lol, i see the adds here but it seems like they are all using the same: OuterClass = APrimalStructureItemContainer_SupplyCrate::StaticClass();
F5 to generate the code if you are in like the HEX view
Avatar
yeah i just figured that one out
Avatar
You can right click most structs from decompiled code and click goto locals
4:37 AM
then right click and edit the struct to get a clean view of it
Avatar
Anyone got any tips on what i need to do to read the Override params?
5:50 AM
dev kit keeps crashing trying to open a dang blueprint spending ages discovering assets
Avatar
I'm pretty sure the functions you are trying to build are allowed already in the INI of the ark server. There is a program named Beacon that allows editing supply crates etc.
Avatar
Avatar
Aikar
how does this UArrayProperty link to TArray's
TheMollusk 4/2/2023 5:46 PM
UArrayProperty is a child of UProperty. UProperties are part of the UE reflection system. All properties reflected by a UArrayProperty object are represented in memory as TArrays (but not all TArrays are in the reflection system). So if you're using ArkServerApi's UProperty::Get() on a UArrayProperty, the return type of Get() will need to be a TArray<[ElementType]>.
Avatar
And class property is single object, I just need to figure out exact structure. I see supplycrateset and supplycratesets that seem to be relevant, but away from pc atm so I'll test more when home
Avatar
TheMollusk 4/2/2023 6:33 PM
I haven't looked at item sets much. Like Lethal pointed out, you have some control over dino drops with the ConfigOverrideSupplyCrateItems ini option, but I don't know if you can use that to remove everything you're trying to remove. (edited)
Avatar
Avatar
Dodo Enthusiast
I mean you could wonder that with basically all of the structs. How does AShooterController without any paddings know where everything is. I dont have an answer but would not mind getting one^^
TheMollusk 4/2/2023 8:03 PM
So when WildCard compiles the game, classes/structs like AShooterPlayerController have a size that's based on their (non-static) member variables. Member functions don't affect class size, those are held elsewhere in memory. Each variable in an instance of the class exists at a particular offset within the class's total size. We can see these sizes/offsets in reverse engineering tools like IDA. When we develop plugins and want to read/write a variable in an object, we need to somehow know that variable's offset so we can access the variable at "object's base address" + " variable offset". There are a couple options. Option 1) We could try to build classes/structs in our plugins that have the same size as WildCard's compiled classes/structs. And we'd also need to organize the member variables so that they fall at the same offsets as the variables in WildCard's server build. That's a little tricky, we'd have to use padding in place of variables that we don't have complete type definitions for and we'd potentially have to deal with alignment/packing issues. Another issue is that if WildCard changes their class/struct definitions (less likely now the ARK:SE development is winding down), our plugin definitions will be out of date and we'd have to update and recompile our plugins. Option 2) We could just get variable offsets at runtime. This is what ArkServerApi does using debug symbols from the pdb file. Most game classes defined in ArkServerApi just use accessor functions in place of actual variables. E.g.: c++ int& ModifedButtonCountField() { return *GetNativePointerField<int*>(this, "AShooterPlayerController.ModifedButtonCount"); } GetNativePointerField() calls the GetAddress() function (exported by ArkServerApi) which adds the offset of the "ModifiedButtonCount" (from pdb) to the object's base address (this) to get an absolute address for the variable. (We're still not completely immune from WC changing their defs, but it's more robust than option 1)
8:04 PM
Since classes in ArkServerApi have no variables, they get a size of 1 byte (C++ objects need to be uniquely addressable, so their size can't be 0). This works (in most use cases) since we have a base address (this/_this, an address from an object property, etc) and accessor functions that use "base address" + "offset found in pdb". There are some weird one-off class definitions in ArkServerApi like: c++ struct UFunction : UStruct { unsigned int FunctionFlags; unsigned __int16 RepOffset; char NumParms; unsigned __int16 ParmsSize; unsigned __int16 ReturnValueOffset; unsigned __int16 RPCId; unsigned __int16 RPCResponseId; UProperty* FirstPropertyToInit; }; This basically looks correct at a glance, but it doesn't actually work because UFunction has a UStruct base class (which has a size of 1 in ArkServerApi), so the UFunction variable offsets are incorrect. Struct definitions (i.e., type names that start with the letter 'F') in ArkServerApi are a little more haphazard. Some of them use option 1 so they actually have the correct size (although some of them are incorrect or out of date), some of them use the option 2 accessor functions. I believe option 1 is used sometimes because it's common to have TArrays of struct types, and TArrays need to use the correct type size at compile time (TArrays of class objects, as opposed to structs, are typically TArrays of pointers to class instances, which we know are 8 bytes).
Avatar
Avatar
TheMollusk
So when WildCard compiles the game, classes/structs like AShooterPlayerController have a size that's based on their (non-static) member variables. Member functions don't affect class size, those are held elsewhere in memory. Each variable in an instance of the class exists at a particular offset within the class's total size. We can see these sizes/offsets in reverse engineering tools like IDA. When we develop plugins and want to read/write a variable in an object, we need to somehow know that variable's offset so we can access the variable at "object's base address" + " variable offset". There are a couple options. Option 1) We could try to build classes/structs in our plugins that have the same size as WildCard's compiled classes/structs. And we'd also need to organize the member variables so that they fall at the same offsets as the variables in WildCard's server build. That's a little tricky, we'd have to use padding in place of variables that we don't have complete type definitions for and we'd potentially have to deal with alignment/packing issues. Another issue is that if WildCard changes their class/struct definitions (less likely now the ARK:SE development is winding down), our plugin definitions will be out of date and we'd have to update and recompile our plugins. Option 2) We could just get variable offsets at runtime. This is what ArkServerApi does using debug symbols from the pdb file. Most game classes defined in ArkServerApi just use accessor functions in place of actual variables. E.g.: c++ int& ModifedButtonCountField() { return *GetNativePointerField<int*>(this, "AShooterPlayerController.ModifedButtonCount"); } GetNativePointerField() calls the GetAddress() function (exported by ArkServerApi) which adds the offset of the "ModifiedButtonCount" (from pdb) to the object's base address (this) to get an absolute address for the variable. (We're still not completely immune from WC changing their defs, but it's more robust than option 1)
Dodo Enthusiast 4/2/2023 10:44 PM
Thanks for the detailed answer.
Avatar
ChewbaccaFR 4/3/2023 12:05 AM
Hello, I am looking for a developer or even a plugin that allows me to give rewards or points when a player votes for my server (on the site: top-serveurs.net) My mps are open for any proposition. (it's urgent).
Avatar
k so i figured out the override field is a TSubclassOf, its just a ref to a class, not an object to actually go over.
3:12 AM
but overall this method just doesnt appear to work
3:13 AM
void filterItems(FSupplyCrateItemSet& itemSet) { auto items = itemSet.ItemEntriesField(); LOG->info("ItemSet: " + itemSet.SetNameField().ToString() + " - " + STR(items.Num())); std::string after = ""; for (auto& entry : items) { entry.Items.RemoveAll(RemoveUndesiredItems()); for (auto& i : entry.Items) { if (i.uClass) { after = after + (i.uClass->NameField().ToString().ToString()) + ", "; } } } LOG->info("After: " + after); i verified the entries are being properly removed. but they still drop
Avatar
any one else have a issue with this hook not preventing item cache from dropping on only certain structures (mainly mod ones like dino storage v2 terminals, but also a few others) void Hook_APrimalStructure_Destroyed(APrimalStructure* _this) { if (no_drop) { if (_this->IsA(APrimalStructureItemContainer::GetPrivateStaticClass())) { auto invetory = static_cast <APrimalStructureItemContainer*>(_this); invetory->bDropInventoryOnDestruction() = false; } } APrimalStructure_Destroyed_original(_this); } are their other classes than Item Containers that I am not aware of?
Avatar
I tried to do the same but couldn't succeed.
5:34 PM
You could remove all items on the inventory alternatively.
Avatar
okay, that was my next step, was just wondering if it was a known issue.
5:35 PM
Its odd that it works on most, I am starting to wonder if the terminal is not considered a crop plot, but I would figure that APrimalStructureItemContainer* would cover that anyways.
Avatar
I ended up going with config approach to remove trash drops, really didnt want to though as i dunno if Beacon properly loaded all the existing loot pools for stuff and prob removed more than i wanted eh. i tried hooking InitializeInventory, and it doesnt see anything in Items field, and i also fear hooking init inventory wouldnt have stopped giving the items if a dino got the melee kill either since it goes directly to the killer vs a death bag.
Avatar
Avatar
Pelayori
I tried to do the same but couldn't succeed.
I have been working with this, but any time I try to access the structure container it causes a crash, I tried to use the following hook to just deal with it once it had dropped DECLARE_HOOK(UPrimalInventoryComponent_DropInventoryDeposit, bool, UPrimalInventoryComponent*, long double, bool, bool, TSubclassOf<APrimalStructureItemContainer>, APrimalStructureItemContainer*, APrimalStructureItemContainer**, AActor*, FString, FString, unsigned __int64, float, bool, int, bool, FVector*, bool); but it gives me an error on the following bool Hook_UPrimalInventoryComponent_DropInventoryDeposit(UPrimalInventoryComponent* _this, 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) { return UPrimalInventoryComponent_DropInventoryDeposit_original(_this, (HERE ->>>>>> double <<<<<<), bDoPreventSendingData, bIgnorEquippedItems, OverrideInventoryDepositClass, CopyStructureValues, DepositStructureResult, GroundIgnoreActor, CurrentCustomFolderFilter, CurrentNameFilter, __int64, DropInventoryOnGroundTraceDistance, bForceDrop, OverrideMaxItemsDropped, bOverrideDepositLocation, DepositLocationOverride, bForceLocation); } says that Type name is not allowed for "double" did they change this hook at some point? do I need to find a new that is not in the hooker creator (edited)
Avatar
The hook creator is not perfect, since the type of the 2nd parameter is long double it thinks the param name is double instead of DestroyAtTime
Avatar
okay, I will try that, thank you
Avatar
Changed it as followed and it does compile now, had to change the __int64 as well return UPrimalInventoryComponent_DropInventoryDeposit_original(_this, DestroyAtTime, bDoPreventSendingData, bIgnorEquippedItems, OverrideInventoryDepositClass, CopyStructureValues, DepositStructureResult, GroundIgnoreActor, CurrentCustomFolderFilter, CurrentNameFilter, DeathCacheCharacterID, DropInventoryOnGroundTraceDistance, bForceDrop, OverrideMaxItemsDropped, bOverrideDepositLocation, DepositLocationOverride, bForceLocation); (edited)
Avatar
Avatar
Aikar
I ended up going with config approach to remove trash drops, really didnt want to though as i dunno if Beacon properly loaded all the existing loot pools for stuff and prob removed more than i wanted eh. i tried hooking InitializeInventory, and it doesnt see anything in Items field, and i also fear hooking init inventory wouldnt have stopped giving the items if a dino got the melee kill either since it goes directly to the killer vs a death bag.
I took a quick shot at removing raw meat (just for an example) from dino drop item sets. Didn't test it too much besides killing a bunch of dinos, seemed to work. I also didn't mess with the "Override" fields because I'm guessing those are populated from the ini file. Didn't look too close your code or the previous conversation, so I can't say why yours wasn't working (one guess: maybe you were removing items from a copy of an item set instead of the item set itself?). First, I defined FSupplyCrateItemEntry and completed the currently empty definition of FSupplyCrateItemSet in Inventory.h. c++ struct UPrimalSupplyCrateItemSet { FSupplyCrateItemSet& ItemSetField() { return *GetNativePointerField<FSupplyCrateItemSet*>(this, "UPrimalSupplyCrateItemSet.ItemSet"); } }; struct FSupplyCrateItemEntry { FString ItemEntryName; float EntryWeight; TArray<TSubclassOf<UPrimalItem>> Items; TArray<FString> ItemClassStrings; TArray<float> ItemsWeights; TArray<int32> ItemQuantityOverrides; float MinQuantity; float MaxQuantity; bool bApplyQuantityToSingleItem; float QuantityPower; float MinRandomQuality; float MinQuality; float MaxQuality; float QualityPower; uint32 bForceBlueprint : 1; uint32 bForcePreventGrinding : 1; float ChanceToBeBlueprintOverride; float ItemStatClampsMultiplier; float ChanceToActuallyGiveItem; float RequiresMinQuality; }; struct FSupplyCrateItemSet { FString SetName; TArray<FSupplyCrateItemEntry> ItemEntries; float MinNumItems; float MaxNumItems; float NumItemsPower; float SetWeight; bool bItemsRandomWithoutReplacement; TSubclassOf<UPrimalSupplyCrateItemSet> ItemSetOverride; };
11:25 PM
Then I wrote plugin code that loops over all UObjects, finds class default objects of dino classes, then goes through the APrimalDinoCharacter::DeathInventoryTemplates field to remove meat from all associated item sets. Kind of a redundant approach since the same item sets can be associated with multiple dino classes, but it just runs once.
Avatar
I suspect that DeathInventoryTemplatesField is the key part
11:27 PM
the method i was doing targetted the dino drop inventory i
11:28 PM
getting the field off of it
Avatar
Avatar
Aikar
I suspect that DeathInventoryTemplatesField is the key part
Well that's what I used at to get at the item sets in the first place, but you could avoid using that (e.g., when looping over all UObjects, I could have just found UDinoDropInventoryComponent_BP_Base_C objects instead of APrimalDinoCharacter CDOs, that removes a couple steps).
Avatar
thats what doesnt work
11:29 PM
thats what the code i was doing did
11:30 PM
the code FINDS the sets and removes them, but the data must have been cloned before the code ran already and the code isnt finding the cloned refs
11:32 PM
im guessing that deathtemplates is a ref to the clones
11:33 PM
UPrimalInventoryComponent* component = (UPrimalInventoryComponent*)bp->GeneratedClassField().uClass->ClassDefaultObjectField(); what is this class default object?
11:33 PM
i thought the class reference is that, just the uninstantiated class def, no instantiation state
11:33 PM
this seems like theres some instance set as a base default on the class?
11:35 PM
what i think is going on is this ClassDEfaultObjectField you accessed isnt registered itself in the global object array so my code just never hit that same object
Avatar
A UClass is basically the definition of the class, represented as a UObject. The CDO is an instance of the class that holds default values that are copied to other instances of the class when they are constructed.
Avatar
well dodos code, dodo passed that to me
11:36 PM
so it instantiates the class once for defaults then it memcpy's it to make a new one?
11:36 PM
so constructor only runs once
11:36 PM
if so yeah that makes sense then
Avatar
Yeah that's basically the idea
Avatar
i was never seeing the default instance as it is unlikely to be in the GUObjectArray directly itself
Avatar
As for the UDinoDropInventoryComponent_BP_Base_C objects, those seemed to only exist as CDOs, there weren't other instances. So I'm not sure what else you would have been modifying.
Avatar
that code absolutely found those objects, it told me everything was doing exactly what i wanted, i saw all the apex drops etc.
Avatar
Couldn't you just hook beginplay and see if it is a supply crate then remove unwanted items?
Avatar
bosses, carnivore huge, etc
11:38 PM
thats what were talking about lethal
11:38 PM
just getting the correct supplycrate object was the issue, it makes copys to the default instance
11:38 PM
mollusk found code to cleanup those copies, thats the part i was missing
Avatar
I'm talking about begin play of AActor or something more specific.
Avatar
Yeah there's definitely got to be another point where you could hook something like beginplay and just remove items from the inventory.
Avatar
well i def like the idea of modifying the source pools, thats no additional performance cost post startup
11:41 PM
and no additional code running per dino beginplay
Avatar
Personally, when it's possible, I try to write plugin code that just runs once and modifies data in the server and avoid using gameplay hooks. That's harder to clean up nicely if you want to be able to unload your plugin and return to the normal state, but I'm usually just writing plugins for my own use.
Avatar
yep ^ that was my goal
Avatar
APrimalStructureItemContainer_SupplyCrate should have a BeginPlay you can hook it just isn't defined already but it inherits from APrimalStructureItemContainer which does have one.
Avatar
isthat init once at start? but what if that inits before plugin is ready
Avatar
What i'm talking about is you hook begin play which is called when a supply crate is spawned. You get a reference to its inventory and modify it.
Avatar
but long as mollusks code is acting on all 'possible dino classes' and not like touching 'currently in the world' dinos, which i think it is, i think their code is the best way to do it for now
11:45 PM
yeah thats what were trying to avoid, and this is dino death inventories
11:45 PM
i think we got a working solution for it
Avatar
ah ok, same principal applies to dinos but it can be done several ways sure
Avatar
well this task sure taught me a lot even if i caved and did it by config haha
11:46 PM
ive never worked in UE before
Avatar
I think when a dino dies the drop is just generated based off the associated UDinoDropInventoryComponent_BP_Base_C CDOs that I modified the item sets in. I'm not sure about the "cloned data" theory, but I didn't spend a ton of time investigating it all.
Avatar
yeah the CDO is the important part, and maybe slight modification of my code would be same thing, as its currently targetting the non CDO objects
11:50 PM
ohh another thing you did was for (FSupplyCrateItemSet& set : component->ItemSetsField()) mine was pulling those by the Property
11:50 PM
maybe property is the real issue
11:51 PM
i can test in a bit if slight tweak gets it working
11:52 PM
also // If the server is ready, call OnServerReady() for post-"server ready" initialization if (ArkApi::GetApiUtils().GetStatus() == ArkApi::ServerStatus::Ready) OnServerReady(); And BeginPlay for gamemode, from what I gathered, using a task timer and just setting delay to 0 seems to achieve the same thing - the code doesnt run until after server is ready, and works perfectly fine for reload scenarios too.
11:52 PM
so ive been doing that
Avatar
I just hook AShooterGameMode::BeginPlay() because that's when ServerStatus::Ready is set in ArkServerApi. I believe those delay executes are called from UWorld::Tick(). I'm not actually sure exactly when the server is really initialized in relation to AShooterGameMode::BeginPlay() and the first UWorld::Tick(), but either option seems to work. (edited)
Avatar
yeah i think it would only be an issue if its critical your code runs before the first world tick, but any code that sensitive isnt gonna work on reload anyways lol
Avatar
Avatar
TheMollusk
I just hook AShooterGameMode::BeginPlay() because that's when ServerStatus::Ready is set in ArkServerApi. I believe those delay executes are called from UWorld::Tick(). I'm not actually sure exactly when the server is really initialized in relation to AShooterGameMode::BeginPlay() and the first UWorld::Tick(), but either option seems to work. (edited)
I cache CDOs in a delay execute
Avatar
Yeah in any case, the delay execute is a few less lines of code, which is nice lol.
Avatar
k did a test using the primal inventory method vs property: auto obj = Globals::GUObjectArray()().ObjObjects.GetObjectPtr(i)->Object; if (obj == nullptr) { continue; } if (!obj->IsA(baseInventoryClass)) { continue; } auto inv = CAST(UPrimalInventoryComponent*, obj); auto itemSets = FORCECAST(TArray<SAOmega::Loot::FSupplyCrateItemSet>, inv->ItemSetsField()); auto additionalSets = FORCECAST(TArray<SAOmega::Loot::FSupplyCrateItemSet>, inv->AdditionalItemSetsField()); for (auto& set : itemSets) { for (auto& entry : set.ItemEntriesField()) { entry.Items.RemoveAll(RemoveUndesiredItems()); } } for (auto& set : additionalSets) { for (auto& entry : set.ItemEntriesField()) { entry.Items.RemoveAll(RemoveUndesiredItems()); } } still doesnt work, so i think the CDO on the death template seems to be an important part.
Avatar
TheMollusk 4/4/2023 1:41 AM
@Aikar You know what. My first example didn't actually prove anything. It just hit me that dinos don't actually drop raw meat in their inventories, you harvest it from them. Didn't think that one through haha.
1:41 AM
Although if I change it to t-rex arms instead of raw meat, it does work. Phew.
1:42 AM
I don't know why the code you just posted doesn't work though. That looks right.
1:46 AM
And taking a closer look now, yeah there are non-CDO instances of the various dino drop inventory components. Although I'm thinking the CDO is the only one you need to modify. But those are in the global objects array too, so it seems like your code should be modifying them.
Avatar
@TheMollusk yeah i just tested it too with my code, and your method seems to work good
Avatar
TheMollusk 4/4/2023 1:50 AM
Ahh. c++ auto itemSets = FORCECAST(TArray<SAOmega::Loot::FSupplyCrateItemSet>, inv->ItemSetsField()); auto additionalSets = FORCECAST(TArray<SAOmega::Loot::FSupplyCrateItemSet>, inv->AdditionalItemSetsField()); I think you're copying the TArray and modifying the copy.
Avatar
no this is me forcing it to my local defined type vs the empty one in the api
1:51 AM
i dunno of another way to make it use my local type vs force
1:52 AM
but that part is fine, i got current code working: (edited)
1:53 AM
oh ffs discord doesnt let you expand whole file
1:53 AM
void removeItems() { for (auto i = 0; i < Globals::GUObjectArray()().ObjObjects.NumElements; i++) { auto obj = Globals::GUObjectArray()().ObjObjects.GetObjectPtr(i)->Object; if (obj == nullptr) { continue; } // Skip invalid UObjects if (!obj->IsValidLowLevelFast(true)) continue; // Skip over UObjects that aren't CDOs if (obj != obj->ClassField()->ClassDefaultObjectField()) continue; // Skip over UObjects that aren't an APrimalDinoCharacter if (!obj->IsA(APrimalDinoCharacter::StaticClass())) continue; APrimalDinoCharacter* dinoCDO = (APrimalDinoCharacter*)obj; for (UObject* listItem : dinoCDO->DeathInventoryTemplatesField().AssociatedObjects) { // DeathInventoryTemplates.AssociatedObjects is an array of UBlueprint* UBlueprint *bp = (UBlueprint *) listItem; // The BP class is a sublcass of UPrimalInventoryComponent if (!bp->GeneratedClassField().uClass->IsChildOf(UPrimalInventoryComponent::StaticClass())) { continue; } // Get the CDO for this inventory component and remove meat from its item sets UPrimalInventoryComponent *component = (UPrimalInventoryComponent *) bp->GeneratedClassField().uClass->ClassDefaultObjectField(); auto itemSets = FORCECAST(TArray<SAOmega::Loot::FSupplyCrateItemSet>, component->ItemSetsField()); auto additionalSets = FORCECAST(TArray<SAOmega::Loot::FSupplyCrateItemSet>, component->AdditionalItemSetsField()); for (auto &set: itemSets) { for (auto &entry: set.ItemEntriesField()) { entry.Items.RemoveAll(RemoveUndesiredItems()); } } for (auto &set: additionalSets) { for (auto &entry: set.ItemEntriesField()) { entry.Items.RemoveAll(RemoveUndesiredItems()); } } } } } (edited)
1:54 AM
struct FSupplyCrateItemEntry { uint8 _padding[0x18]; TArray<TSubclassOf<UPrimalItem>> Items; uint8 _padding2[0x68]; }; struct FSupplyCrateItemSet { uint8 _padding[0x40]; TArray<FSupplyCrateItemEntry,FDefaultAllocator>& ItemEntriesField() { return *GetNativePointerField<TArray<FSupplyCrateItemEntry,FDefaultAllocator>*>(this, "FSupplyCrateItemSet.ItemEntries"); } }; bool shouldFilter(FString& name) { return (name.Contains("_ApexDrop_") || name.Contains("RecipeNote_") || name.Contains("PrimalItemCostume_") || name.Contains("PrimalItemSkin_") || name.Contains("PrimalItemArmor_Cloth") || name.Contains("PrimalItemArmor_Hide") || name.Contains("PrimalItemArmor_Fur") || name.Contains("PrimalItemArmor_Chitin") || name.Contains("PrimalItemArmor_Metal") || name.Contains("PrimalItemArmor_Scuba") || name.Contains("PrimalItemConsumable_Berry") || name.Contains("PrimalItem_WeaponStone") || name.Contains("PrimalItem_WeaponMetal") || name.Contains("PrimalItem_WeaponGPS") || name.Contains("PrimalItem_WeaponCompass") || name.Contains("PrimalItem_WeaponSickle") || name.Contains("PrimalItem_WeaponBow_") || name.Contains("PrimalItem_WeaponTorch_") || name.Contains("PrimalItem_WeaponCrossBow_") || name.Contains("PrimalItem_WeaponBoomerang") || name.Contains("PrimalItem_WeaponMachined") || name.Contains("PrimalItem_WeaponGun") || name.Contains("PrimalItem_WeaponPike") || name.Contains("PrimalItem_WeaponGrenade") || name.Contains("PrimalItem_WeaponProd_") || name.Contains("PrimalItem_WeaponSpear") || name.Contains("PrimalItem_WeaponSlingshot") || name.Contains("_Wishbone_") ); } struct RemoveUndesiredItems { bool operator()(const TSubclassOf<UPrimalItem>& item) const { if (!item.uClass) { return false; } auto name = item.uClass->NameField().ToString(); return shouldFilter(name); } };
1:55 AM
thats all the relevant parts of my code mixed with your approach that appears to be working
1:55 AM
if someone wants to release this as a plugin def encourage the configs to allow simple string matches like that
1:55 AM
but could also do it by entire set name too
1:56 AM
since most apex's are Apex Drop and theres like 2 named Survivor something
1:56 AM
but i was ok with keeping like the stone arrows part of the survivor drops, just wanted the other junk gone
1:56 AM
playing ARK Omega so those arrows save you crafting them yourself lol
Avatar
Avatar
Aikar
void removeItems() { for (auto i = 0; i < Globals::GUObjectArray()().ObjObjects.NumElements; i++) { auto obj = Globals::GUObjectArray()().ObjObjects.GetObjectPtr(i)->Object; if (obj == nullptr) { continue; } // Skip invalid UObjects if (!obj->IsValidLowLevelFast(true)) continue; // Skip over UObjects that aren't CDOs if (obj != obj->ClassField()->ClassDefaultObjectField()) continue; // Skip over UObjects that aren't an APrimalDinoCharacter if (!obj->IsA(APrimalDinoCharacter::StaticClass())) continue; APrimalDinoCharacter* dinoCDO = (APrimalDinoCharacter*)obj; for (UObject* listItem : dinoCDO->DeathInventoryTemplatesField().AssociatedObjects) { // DeathInventoryTemplates.AssociatedObjects is an array of UBlueprint* UBlueprint *bp = (UBlueprint *) listItem; // The BP class is a sublcass of UPrimalInventoryComponent if (!bp->GeneratedClassField().uClass->IsChildOf(UPrimalInventoryComponent::StaticClass())) { continue; } // Get the CDO for this inventory component and remove meat from its item sets UPrimalInventoryComponent *component = (UPrimalInventoryComponent *) bp->GeneratedClassField().uClass->ClassDefaultObjectField(); auto itemSets = FORCECAST(TArray<SAOmega::Loot::FSupplyCrateItemSet>, component->ItemSetsField()); auto additionalSets = FORCECAST(TArray<SAOmega::Loot::FSupplyCrateItemSet>, component->AdditionalItemSetsField()); for (auto &set: itemSets) { for (auto &entry: set.ItemEntriesField()) { entry.Items.RemoveAll(RemoveUndesiredItems()); } } for (auto &set: additionalSets) { for (auto &entry: set.ItemEntriesField()) { entry.Items.RemoveAll(RemoveUndesiredItems()); } } } } } (edited)
TheMollusk 4/4/2023 1:59 AM
Nice 👍
Avatar
I had log lines before I pasted that,
2:00 AM
so its still finding al lthe same items but works this time lol
2:01 AM
vanilla bosses already pointless in omega but i took the tributes out of their requirements and made it artifacts only so these things are just an annoyance here is why i want em gone.
2:02 AM
and with a loot pickup mod, your inventory fills with stone hatchets so damn fast
2:08 AM
oh yeah wanted to share a util class added, class BlueprintCache { private: FString path; UClass* cls; public: BlueprintCache(char* path) { this->path = path; } BlueprintCache(FString path) { this->path = path; } UClass* Get() { if (!cls) { cls = UVictoryCore::BPLoadClass(&path); } return cls; } }; Then can do in namespace/static prop BlueprintCache dinoDropBP("Blueprint'/Game/PrimalEarth/CoreBlueprints/Inventories/DinoDropInventoryComponent_BP_Base.DinoDropInventoryComponent_BP_Base'"); and reuse over multiple methods obj->IsA(dinoDropBP.Get()) notably for like the spyglass thing worked with Sub on before, needed same blueprints in 2 diff methods so the static cache method doesnt get shared there, this will let it share the cache.
2:09 AM
and those cast macros, #define CAST(as, from) static_cast<as>(from) #define FORCECAST(as, from) *CAST(as*, CAST(void*, &from)) bit rusty with C++, thats pretty much best way to handle force casting right?
2:09 AM
it def worked for auto itemSets = FORCECAST(TArray<SAOmega::Loot::FSupplyCrateItemSet>, component->ItemSetsField());
2:11 AM
@TheMollusk how did you override the FSupplyCrateItemSet in your test? or did it just override the API's version because you defined it locally
2:11 AM
but thought the ->ItemSetsField would still pull in the API's version
2:11 AM
or did you update the definition in your local copy of the api
Avatar
TheMollusk 4/4/2023 2:25 AM
Yeah I just changed the definition in my local copy of Inventory.h
Avatar
Avatar
TheMollusk
I just hook AShooterGameMode::BeginPlay() because that's when ServerStatus::Ready is set in ArkServerApi. I believe those delay executes are called from UWorld::Tick(). I'm not actually sure exactly when the server is really initialized in relation to AShooterGameMode::BeginPlay() and the first UWorld::Tick(), but either option seems to work. (edited)
This doesn't handle hot loading or reloading/updating a plugin after the server has started as it only runs once during server startup.
2:45 AM
You can use this during plugin load in case you want to run the logic in these instances. if (ArkApi::GetApiUtils().GetStatus() == ArkApi::ServerStatus::Ready)
Avatar
TheMollusk 4/4/2023 2:45 AM
Yeah I have an "OnServerReady()" function, I call it from Plugin_Init() if the server is already ready, otherwise I call it from my AShooterGameMode::BeginPlay() hook. (edited)
Avatar
Avatar
Aikar
but that part is fine, i got current code working: (edited)
TheMollusk 4/4/2023 2:47 AM
So this works for me: c++ void OnServerReady() { UClass* dinoDropInvClass = UVictoryCore::BPLoadClass("Bluprint'/Game/PrimalEarth/CoreBlueprints/Inventories/DinoDropInventoryComponent_BP_Base.DinoDropInventoryComponent_BP_Base'"); for (int i = 0; i < Globals::GUObjectArray()().ObjObjects.NumElements; i++) { UObject* obj = Globals::GUObjectArray()().ObjObjects.GetObjectPtr(i)->Object; if (!obj->IsValidLowLevelFast(true)) continue; if (!obj->IsA(dinoDropInvClass)) continue; if (obj != obj->ClassField()->ClassDefaultObjectField()) continue; UPrimalInventoryComponent* dinoDropInv = (UPrimalInventoryComponent*)obj; for (FSupplyCrateItemSet& set : dinoDropInv->ItemSetsField()) for (FSupplyCrateItemEntry& entry : set.ItemEntries) if (entry.Items.RemoveAll(RemoveArms()) > 0) Log::GetLog()->info("Removed arms from {} ItemSets", dinoDropInv->NameField().ToString().ToString()); for (FSupplyCrateItemSet& set : dinoDropInv->AdditionalItemSetsField()) for (FSupplyCrateItemEntry& entry : set.ItemEntries) if (entry.Items.RemoveAll(RemoveArms()) > 0) Log::GetLog()->info("Removed arms from {} AdditionalItemSets", dinoDropInv->NameField().ToString().ToString()); } }
2:47 AM
But this doesn't: c++ void OnServerReady() { UClass* dinoDropInvClass = UVictoryCore::BPLoadClass("Bluprint'/Game/PrimalEarth/CoreBlueprints/Inventories/DinoDropInventoryComponent_BP_Base.DinoDropInventoryComponent_BP_Base'"); for (int i = 0; i < Globals::GUObjectArray()().ObjObjects.NumElements; i++) { UObject* obj = Globals::GUObjectArray()().ObjObjects.GetObjectPtr(i)->Object; if (!obj->IsValidLowLevelFast(true)) continue; if (!obj->IsA(dinoDropInvClass)) continue; if (obj != obj->ClassField()->ClassDefaultObjectField()) continue; UPrimalInventoryComponent* dinoDropInv = (UPrimalInventoryComponent*)obj; // Doesn't work // itemSets->GetData() and dinoDropInv->ItemSetsField()->GetData() return different addresses auto itemSets = dinoDropInv->ItemSetsField(); auto additionalItemSets = dinoDropInv->AdditionalItemSetsField(); for (FSupplyCrateItemSet& set : itemSets) for (FSupplyCrateItemEntry& entry : set.ItemEntries) if (entry.Items.RemoveAll(RemoveArms()) > 0) Log::GetLog()->info("Removed arms from {} ItemSets", dinoDropInv->NameField().ToString().ToString()); for (FSupplyCrateItemSet& set : additionalItemSets) for (FSupplyCrateItemEntry& entry : set.ItemEntries) if (entry.Items.RemoveAll(RemoveArms()) > 0) Log::GetLog()->info("Removed arms from {} AdditionalItemSets", dinoDropInv->NameField().ToString().ToString()); } } If I reload this second version without restarting my server, I get the log every time. [info] Removed arms from Default__DinoDropInventoryComponent_Carnivore_Huge_Rex_C AdditionalItemSets The reason is that this copy constructor is being used: c++ FORCEINLINE TArray(const TArray& Other) { CopyToEmpty(Other.GetData(), Other.Num(), 0, 0); }
Avatar
using your orig code seems like it works fine
5:30 AM
your bottom code is essentially what code i was using that doesnt work i think
Avatar
actually both of those are
5:55 AM
ah so your saying in my orig code that didnt work it was Because this: TArray<FSupplyCrateItemSet> itemSets = setProperty->Get<TArray<FSupplyCrateItemSet>>(obj); Was making the copy, and it needed to be like TArray<FSupplyCrateItemSet>& itemSets = setProperty->Get<TArray<FSupplyCrateItemSet>>(obj); to be a reference instead of a copy?
5:58 AM
the current code for forcecast is: #define CAST(as, from) static_cast<as>(from) #define FORCECAST(as, from) *CAST(as*, CAST(void*, &from))` But it seems its working though. stuffs not dropping. does this cast logic here avoid the copy somehow?
Avatar
I'm still learning a bit for C++, so use to java everything just being a by ref and no magic copy invocations going on lol, but is the fact its not a raw TArray foo = someOtherToArray to trigger the TArray =& that maps to the TArray(&TArray)? Is it normal for a A = someInstanceOfA; to Trigger the constructor like that, and needs to be A& a = otherA; to trigger a byref?
Avatar
TArray foo = someArray; // copy TArray& foo = someArray; // byref TArray* foo = &someArray // pointer (converts to byref if you use the * operator)
3:39 PM
If you don't explicitly tell it to take the reference it will attempt to copy it, unless the class has the copy constructor deleted (edited)
Avatar
k thats what I figured
3:45 PM
so is my FORCECAST macro avoiding the copy due to the pointer redirections?
Avatar
How is that macro defined?
Avatar
i did update the CAST to reinterpret_cast, that is preferred right?
3:46 PM
look right above in chat
Avatar
Oh lol
3:46 PM
No, static_cast is preferred
3:46 PM
It's safer, as reinterpret cast won't throw compile error on types not compatible
Avatar
ah ok, and compiler considers it compat if size looks same right?
3:47 PM
like i mainly used the force cast where the API doesnt have the correct struct for the supply crate thing, to force it to my local struct def
3:47 PM
and it was working with static
Avatar
As long as you have a pointer to something, the casting will suceed no matter the struct size (edited)
3:48 PM
It's at access time where it matters
3:48 PM
And that's where you could prefer using the pdb field reader rather than direct member access
Avatar
the API doesnt provide the field methods at all for this, so added my own to a local struct
Avatar
You can add your own at any time
Avatar
struct FSupplyCrateItemEntry { uint8 _padding[0x18]; TArray<TSubclassOf<UPrimalItem>> Items; uint8 _padding2[0x68]; }; struct FSupplyCrateItemSet { uint8 _padding[0x40]; TArray<FSupplyCrateItemEntry,FDefaultAllocator>& ItemEntriesField() { return *GetNativePointerField<TArray<FSupplyCrateItemEntry,FDefaultAllocator>*>(this, "FSupplyCrateItemSet.ItemEntries"); } }; Didnt get to updating ItemEntry one yet
Avatar
For class attributes you can do: struct MyArkStruct { float& someField() { return *GetNativePointerField<float*>(this, "MyArkStruct.some"); } }
Avatar
yeah i already have that for the itemset
Avatar
FDefaultAllocator is not needed as it's the default if you want to clean that up a bit
Avatar
API has a blank FSupplyCrateItemSet defined was the issue
Avatar
A lot of api definitions are empty to allow compiling since not everything was defined initially
Avatar
right so thats what i meant i was doing, using the API's UPrimalInventoryComponent ->GetItemEntriesField() and just recasting it so it sees my struct vs the blank one in api
3:52 PM
its working ok atm just making sure i understand how/why things are working
3:52 PM
as i now at least understand why my previous attempts failed, was due to unexpected copies being made
Avatar
Also, if you ever happen to use auto keyword, that will copy almost always (unless it's a pointer), so you would need auto& for references and not copies
Avatar
my primary 3 languages are java, PHP and JS.... where objects are forced by ref and cloning requires explicit instruction lol, so caught me off guard.
Avatar
Yeah implicit copy sometimes gets you off guard lol
Avatar
so getNativePointerField vs GetNativeField, is pointer mainly going to be used for refs to structs, and GetNativeField for primitives? ie your example above, wouldnt that be GetNativeField if the field was actually 'float' and youd only use PointerField if the struct defines it as float* ?
Avatar
Looking at the definition GetNativeField just forces the type to be pointer, and GetNativePointerField forces you to specify if you want a pointer or not
4:00 PM
Most of us always use GetNativePointerField because it's what has always been used in the API definitions made originally. But both should be of use if you know one forces a pointer while the other does not
4:01 PM
There's no differences between them for primitives or complex types
Avatar
Does checking actor for nullptr return false if it is no longer in the world? Was working on a plugin to check all dinos on a map to see which tribe is taming what. I was doing it through server ticks with a timer which was working through a TArray, but it seems to crash if a dino in the list is no longer in the world even when I check it for nullptr. I can't get the code right now as I am not near my PC, just wondering if it is the null check or the timer. (edited)
Avatar
Checking against nullptr will just check if the pointer is assigned to an address greater than 0x000000000...
1:14 AM
You should store weak references rather than raw pointers
Avatar
Okay, I figured as much. it works great if done instantly, but comes with a lag spike and I assumed that was because nothing had time to die, or be picked up via soul ball or otherwise just not exist in the world anymore. I will try another way as mentioned. (edited)
Avatar
substitute 4/7/2023 2:15 AM
A weak pointer decays into either a shared pointer or a nullptr depending on if the reference is still valid
2:15 AM
UE4 weak pointer probably works the same way
2:16 AM
Converts this weak pointer to a shared pointer that you can use to access the object (if it hasn't expired yet.) Remember, if there are no more shared references to the object, the returned shared pointer will not be valid.
2:16 AM
Checks to see if this weak pointer actually has a valid reference to an object
2:16 AM
So you want
2:16 AM
IsValid()
2:16 AM
And then Pin()
2:17 AM
Avatar
Would using TWeakObjectPtr and checking for nullptr be the same with less steps? I have them stored in a map auto st = all_wild.begin(); if (st->second.Get() != nullptr) { APrimalDinoCharacter* cd = st->second.Get(); if (cd->TargetingTeamField() < 50000 && cd->TamingTeamIDField() < 50000) { //dostuff } } all_wild.erase(st->first); (edited)
Avatar
Guess that is a no, still crashing. Will read more into the TWeakPtr tomorrow. I am honestly not even sure if its the dino's, timers, or memory issues at this point, crash log is always pointing to timers, might just be having 1 plugin do too many things.
Avatar
Avatar
Xeakial
Guess that is a no, still crashing. Will read more into the TWeakPtr tomorrow. I am honestly not even sure if its the dino's, timers, or memory issues at this point, crash log is always pointing to timers, might just be having 1 plugin do too many things.
Weak pointers will return a true nullptr if the Dino is no longer in the world. The way the get function works is by checking the global objects list so see if the Dino is still there, and not pending garbage collection.
10:15 AM
If you post your crash we might be able to see something else
Avatar
Fatalerror! VERSION:357.11 ShooterGameServer.exe!AActor::ThrottledTick()(0x00007ff773d2a4e0)+0bytes[f:\build\lostisland\projects\shootergame\intermediate\build\win64\shootergameserver\inc\engine\engine.generated.1.cpp:1778] ShooterGameServer.exe!AShooterGameState::Tick()(0x00007ff772157898)+0bytes[f:\build\lostisland\projects\shootergame\source\shootergame\private\shootergamestate.cpp:519] ShooterGameServer.exe!AActor::TickActor()(0x00007ff7737969ee)+0bytes[f:\build\lostisland\engine\source\runtime\engine\private\actor.cpp:789] ShooterGameServer.exe!FActorTickFunction::ExecuteTick()(0x00007ff77379518a)+30bytes[f:\build\lostisland\engine\source\runtime\engine\private\actor.cpp:154] ShooterGameServer.exe!TGraphTask<FTickTaskSequencer::FTickFunctionTask>::ExecuteTask()(0x00007ff773a63d4c)+28bytes[f:\build\lostisland\engine\source\runtime\core\public\async\taskgraphinterfaces.h:871] ShooterGameServer.exe!FNamedTaskThread::ProcessTasksNamedThread()(0x00007ff7731e4325)+0bytes[f:\build\lostisland\engine\source\runtime\core\private\async\taskgraph.cpp:939] ShooterGameServer.exe!FNamedTaskThread::ProcessTasksUntilQuit()(0x00007ff7731e3c4e)+0bytes[f:\build\lostisland\engine\source\runtime\core\private\async\taskgraph.cpp:680] ShooterGameServer.exe!FTaskGraphImplementation::WaitUntilTasksComplete()(0x00007ff7731e5b24)+0bytes[f:\build\lostisland\engine\source\runtime\core\private\async\taskgraph.cpp:1777] ShooterGameServer.exe!FTickTaskSequencer::ReleaseTickGroup()(0x00007ff773a360d3)+0bytes[f:\build\lostisland\engine\source\runtime\engine\private\ticktaskmanager.cpp:205] ShooterGameServer.exe!FTickTaskManager::RunTickGroup()(0x00007ff773a38fac)+0bytes[f:\build\lostisland\engine\source\runtime\engine\private\ticktaskmanager.cpp:867] ShooterGameServer.exe!UWorld::RunTickGroup()(0x00007ff7738fc33e)+0bytes[f:\build\lostisland\engine\source\runtime\engine\private\leveltick.cpp:697] ShooterGameServer.exe!UWorld::Tick()(0x00007ff7738fd93b)+13bytes[f:\build\lostisland\engine\source\runtime\engine\private\leveltick.cpp:1210] ShooterGameServer.exe!UGameEngine::Tick()(0x00007ff7738682c1)+0bytes[f:\build\lostisland\engine\source\runtime\engine\private\gameengine.cpp:1195] ShooterGameServer.exe!FEngineLoop::Tick()(0x00007ff771617e12)+0bytes[f:\build\lostisland\engine\source\runtime\launch\private\launchengineloop.cpp:2647] ShooterGameServer.exe!GuardedMain()(0x00007ff771613bcc)+0bytes[f:\build\lostisland\engine\source\runtime\launch\private\launch.cpp:140] ShooterGameServer.exe!GuardedMainWrapper()(0x00007ff771618d9a)+5bytes[f:\build\lostisland\engine\source\runtime\launch\private\windows\launchwindows.cpp:125] ShooterGameServer.exe!WinMain()(0x00007ff771618ee9)+8bytes[f:\build\lostisland\engine\source\runtime\launch\private\windows\launchwindows.cpp:213] ShooterGameServer.exe!__tmainCRTStartup()(0x00007ff774903619)+21bytes[f:\dd\vctools\crt\crtw32\dllstuff\crtexe.c:618] KERNEL32.DLL!UnknownFunction(0x00007ff93fab7974)+0bytes[UnknownFile:0] ntdll.dll!UnknownFunction(0x00007ff954e5a351)+0bytes[UnknownFile:0] ntdll.dll!UnknownFunction(0x00007ff954e5a351)+0bytes[UnknownFile:0] LastRemoteFunctionSpike_Lower_Visual
Avatar
ChewbaccaFR 4/8/2023 12:20 PM
Hello, I intend to start programming C++ to create plugins on ARK, I am motivated but I do not know much, I have never developed. I would like to get some documentation to learn if you have links to send me I'm interested. (edited)
Avatar
Avatar
ChewbaccaFR
Hello, I intend to start programming C++ to create plugins on ARK, I am motivated but I do not know much, I have never developed. I would like to get some documentation to learn if you have links to send me I'm interested. (edited)
This guide is based on the Visual Studio Community 2019 version install Prerequisites: 1. https://visualstudimicrosofto..com/vs/ 2. https://github.com/Michidu/ARK-Server-API/archive/master.zip Step N1: Install Visual Studio by the link given on the first prerequisite. When the inst...
What is a Hook? a hook is a way intercepting a function when it gets called by the server it will execute your hook before returning back to the original function giving you the ability to modify the return or manipulate the arguments or do your own task Automatic Hook Generator Tool (Easy...
Hello, I made a video for people who want to check the code source and compile plugins their selfs So for paranoic people like me this video will help you Sorry for my english and the noise on the video Hope it will help you Thanks to Michidu for he's help cause he's the one who taked from...
👌 1
Avatar
@GSH | MrOwlSky Could we get some bot command to output those links when prompted? ^^
Avatar
Avatar
Pelayori
@GSH | MrOwlSky Could we get some bot command to output those links when prompted? ^^
GSH | MrOwlSky 4/8/2023 5:27 PM
Sure, I can work on that
👍 1
Avatar
Does anyone know how to reload the lottery plugin on ARK? I want to avoid turning the servers off
1:38 PM
There is no reload rcon on the plugin page
Avatar
Avatar
Dul
Does anyone know how to reload the lottery plugin on ARK? I want to avoid turning the servers off
substitute 5/8/2023 6:03 PM
This is not the discord for plugin configuration questions
Avatar
Working on sending in info from my plugin to my mod, Everything seems to run through fine as I had Log's check each stage, but am getting nothing in game. I think I might be doing the CDO part wrong? static FString f("Blueprint'/Game/Mods/Mystic/Test_CCA.Test_CCA'"); UClass* load = UVictoryCore::BPLoadClass(&f); if (!load) return; UObject* CDO = load->GetDefaultObject(true); if (!CDO) return; UFunction* cca = CDO->FindFunctionChecked(FName("SetInfo", EFindName::FNAME_Add)); if (!cca) return; CDO->ProcessEvent(cca, &DName);
5:01 AM
I also tried sending it with a stuct, but there is only one arg on the function.
Avatar
You are sending data to the class default object
10:40 AM
You need the actual instance of the singleton
Avatar
I figured the CDO was where it was wrong. Will change it to find the actor itself and try that way
Avatar
Avatar
Pelayori
You are sending data to the class default object
Works perfect now, thank you as always!
Avatar
Is it possible to send arrays using this same method with ProcessEvent? having an issue sending multiple arrays using a struct to group them. My bool sends fine but the arrays do not.
Avatar
Well never mind, just did some logging and the data is going in to the arrays, problem must be somewhere else.
Exported 980 message(s)
Timezone: UTC+1