Skip to content

Commit eaa2d18

Browse files
committed
Improvements
- All blueprint paths use the same format. - New spawn template options: imprint %, follow, aggression level, ignore all whistles, ignore ally look, facing direction. - Default values for many spawn template options. - Stamina and oxygen now set to max on spawn. - Bug fix: Experience calculation corrected. - Bug fix: Dino stats were not correctly saved between server restarts.
1 parent 5c57c8b commit eaa2d18

8 files changed

Lines changed: 441 additions & 142 deletions

File tree

ArkGameTestingCommands/ArkGameTestingCommands.cpp

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ void CustomGiveItem(APlayerController* aPlayerController, FString* cmd, bool bWr
7272
std::string bpPathStr = bpPath.ToString();
7373
if (!bpPathStr.empty())
7474
{
75-
wchar_t* bpPathWStr = ConvertToWideStr(bpPath.ToString());
75+
wchar_t* bpNameWStr = GetBlueprintNameWideStr(bpPath.ToString());
7676

77-
UObject* object = Globals::StaticLoadObject(UObject::StaticClass(), nullptr, bpPathWStr, nullptr, 0, 0, true);
77+
UObject* object = Globals::StaticLoadObject(UObject::StaticClass(), nullptr, bpNameWStr, nullptr, 0, 0, true);
7878
if (object)
7979
{
8080
TSubclassOf<UPrimalItem> archetype;
@@ -116,7 +116,7 @@ void CustomGiveItem(APlayerController* aPlayerController, FString* cmd, bool bWr
116116
SendDirectMessage(aShooterController, L"Successfully spawned item");
117117
}
118118

119-
delete[] bpPathWStr;
119+
delete[] bpNameWStr;
120120
}
121121
}
122122
}
@@ -149,43 +149,64 @@ void SpawnTemplate(APlayerController* aPlayerController, FString* cmd, bool bWri
149149
int dinoBaseLevelHealth, dinoBaseLevelStamina, dinoBaseLevelOxygen, dinoBaseLevelFood, dinoBaseLevelWeight, dinoBaseLevelMeleeDamage, dinoBaseLevelMovementSpeed;
150150
int dinoTamedLevelHealth, dinoTamedLevelStamina, dinoTamedLevelOxygen, dinoTamedLevelFood, dinoTamedLevelWeight, dinoTamedLevelMeleeDamage, dinoTamedLevelMovementSpeed;
151151
float saddleArmor;
152+
float imprint;
152153
int count;
153154
float radius;
155+
bool follow;
156+
bool ignoreAllWhistles;
157+
bool ignoreAllyLook;
154158
std::list<GiveItemDefinition> items;
155159

156160
std::string bpPath = templateEntry["blueprint"];
157-
std::string bpPathSaddle = templateEntry["saddleBlueprint"];
161+
std::string bpPathSaddle = templateEntry.value("saddleBlueprint", std::string());
162+
163+
std::string aggressionLevelStr = str_tolower(templateEntry.value("aggressionLevel", std::string()));
164+
AggressionLevel aggressionLevel = AggressionLevel::Passive;
165+
if (aggressionLevelStr.compare("passive") == 0) aggressionLevel = AggressionLevel::Passive;
166+
else if (aggressionLevelStr.compare("neutral") == 0) aggressionLevel = AggressionLevel::Neutral;
167+
else if (aggressionLevelStr.compare("aggressive") == 0) aggressionLevel = AggressionLevel::Aggressive;
168+
else if (aggressionLevelStr.compare("attackmytarget") == 0) aggressionLevel = AggressionLevel::AttackMyTarget;
169+
170+
std::string facingStr = str_tolower(templateEntry.value("facing", std::string()));
171+
FacingDirection facing = FacingDirection::Forward;
172+
if (facingStr.compare("forward") == 0) facing = FacingDirection::Forward;
173+
else if (facingStr.compare("outwards") == 0) facing = FacingDirection::Outwards;
174+
else if (facingStr.compare("inwards") == 0) facing = FacingDirection::Inwards;
158175

159176
try
160177
{
161-
saddleArmor = templateEntry["saddleArmor"];
162-
dinoBaseLevelHealth = templateEntry["baseLevelHealth"];
163-
dinoBaseLevelStamina = templateEntry["baseLevelStamina"];
164-
dinoBaseLevelOxygen = templateEntry["baseLevelOxygen"];
165-
dinoBaseLevelFood = templateEntry["baseLevelFood"];
166-
dinoBaseLevelWeight = templateEntry["baseLevelWeight"];
167-
dinoBaseLevelMeleeDamage = templateEntry["baseLevelMeleeDamage"];
168-
dinoBaseLevelMovementSpeed = templateEntry["baseLevelMovementSpeed"];
169-
170-
dinoTamedLevelHealth = templateEntry["tamedLevelHealth"];
171-
dinoTamedLevelStamina = templateEntry["tamedLevelStamina"];
172-
dinoTamedLevelOxygen = templateEntry["tamedLevelOxygen"];
173-
dinoTamedLevelFood = templateEntry["tamedLevelFood"];
174-
dinoTamedLevelWeight = templateEntry["tamedLevelWeight"];
175-
dinoTamedLevelMeleeDamage = templateEntry["tamedLevelMeleeDamage"];
176-
dinoTamedLevelMovementSpeed = templateEntry["tamedLevelMovementSpeed"];
177-
178-
count = templateEntry["count"];
179-
radius = templateEntry["radius"];
178+
saddleArmor = templateEntry.value("saddleArmor", 25.0);
179+
imprint = templateEntry.value("imprint", 0.0);
180+
dinoBaseLevelHealth = templateEntry.value("baseLevelHealth", 0);
181+
dinoBaseLevelStamina = templateEntry.value("baseLevelStamina", 0);
182+
dinoBaseLevelOxygen = templateEntry.value("baseLevelOxygen", 0);
183+
dinoBaseLevelFood = templateEntry.value("baseLevelFood", 0);
184+
dinoBaseLevelWeight = templateEntry.value("baseLevelWeight", 0);
185+
dinoBaseLevelMeleeDamage = templateEntry.value("baseLevelMeleeDamage", 0);
186+
dinoBaseLevelMovementSpeed = templateEntry.value("baseLevelMovementSpeed", 0);
187+
188+
dinoTamedLevelHealth = templateEntry.value("tamedLevelHealth", 0);
189+
dinoTamedLevelStamina = templateEntry.value("tamedLevelStamina", 0);
190+
dinoTamedLevelOxygen = templateEntry.value("tamedLevelOxygen", 0);
191+
dinoTamedLevelFood = templateEntry.value("tamedLevelFood", 0);
192+
dinoTamedLevelWeight = templateEntry.value("tamedLevelWeight", 0);
193+
dinoTamedLevelMeleeDamage = templateEntry.value("tamedLevelMeleeDamage", 0);
194+
dinoTamedLevelMovementSpeed = templateEntry.value("tamedLevelMovementSpeed", 0);
195+
196+
count = templateEntry.value("count", 1);
197+
radius = templateEntry.value("radius", 1000.0);
198+
follow = templateEntry.value("follow", false);
199+
ignoreAllWhistles = templateEntry.value("ignoreAllWhistles", false);
200+
ignoreAllyLook = templateEntry.value("ignoreAllyLook", false);
180201

181202
auto itemsMap = templateEntry.value("items", nlohmann::json::array());
182203
for (auto iter = itemsMap.begin(); iter != itemsMap.end(); ++iter)
183204
{
184205
auto item = iter.value();
185206

186207
std::string blueprint = item["blueprint"];
187-
int quantity = item["quantity"];
188-
int count = item["count"];
208+
int quantity = item.value("quantity", 1);
209+
int count = item.value("count", 1);
189210

190211
GiveItemDefinition giveItemDef;
191212
giveItemDef.blueprint = blueprint;
@@ -204,16 +225,21 @@ void SpawnTemplate(APlayerController* aPlayerController, FString* cmd, bool bWri
204225
bool success = true;
205226
for (int i = 0; i < count; i++)
206227
{
207-
float a = i * 2 * M_PI / count;
228+
float a = i * 2 * M_PI / count; //in radians
208229
float x = radius * std::cos(a);
209230
float y = radius * std::sin(a);
210231

232+
float f = 0.0; // in degrees
233+
if (facing == FacingDirection::Outwards) f = i * 360.0 / count;
234+
else if (facing == FacingDirection::Inwards) f = i * 360.0 / count + 180.0;
235+
211236
bool innerSuccess = SpawnCustomDino(
212237
steamId,
213238
bpPath, bpPathSaddle,
214239
dinoBaseLevelHealth, dinoBaseLevelStamina, dinoBaseLevelOxygen, dinoBaseLevelFood, dinoBaseLevelWeight, dinoBaseLevelMeleeDamage, dinoBaseLevelMovementSpeed,
215240
dinoTamedLevelHealth, dinoTamedLevelStamina, dinoTamedLevelOxygen, dinoTamedLevelFood, dinoTamedLevelWeight, dinoTamedLevelMeleeDamage, dinoTamedLevelMovementSpeed,
216-
saddleArmor, items, x, y);
241+
saddleArmor, imprint, items, x, y, 300,
242+
follow, aggressionLevel, ignoreAllWhistles, ignoreAllyLook, f);
217243

218244
if (!innerSuccess)
219245
{
@@ -362,6 +388,7 @@ void ReloadTestConfig(APlayerController* playerController, FString* cmd, bool sh
362388
LoadConfig();
363389

364390
AShooterPlayerController* aShooterController = static_cast<AShooterPlayerController*>(playerController);
391+
SendDirectMessage(aShooterController, L"Test config reloaded!");
365392
}
366393

367394
void TestFunc(APlayerController* playerController, FString* cmd, bool shouldLog)

ArkGameTestingCommands/GiveCustomItems.cpp

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,9 @@ bool GiveCustomItems(
1616

1717
for (std::list<std::string>::iterator it2 = blueprints.begin(); it2 != blueprints.end(); ++it2)
1818
{
19-
std::wstring itemBlueprint = ConvertToWideStr(*it2);
19+
std::wstring itemName = GetBlueprintNameWideStr(*it2);
2020

21-
//remove "Blueprint'" from start
22-
std::wstring rBp = L"Blueprint'";
23-
size_t fBp = itemBlueprint.find(rBp);
24-
if (fBp == 0) itemBlueprint.replace(fBp, rBp.length(), L"");
25-
26-
//remove ending single quote
27-
std::wstring rQ = L"'";
28-
size_t fQ = itemBlueprint.rfind(rQ);
29-
if (fQ == itemBlueprint.length() - 1) itemBlueprint.replace(fQ, rQ.length(), L"");
30-
31-
//append _C if missing
32-
if (!(itemBlueprint.rfind(L"_C") == itemBlueprint.length() - 2 || itemBlueprint.rfind(L"_c") == itemBlueprint.length() - 2)) itemBlueprint.append(L"_C");
33-
34-
UObject* object = Globals::StaticLoadObject(UObject::StaticClass(), nullptr, itemBlueprint.c_str(), nullptr, 0, 0, true);
21+
UObject* object = Globals::StaticLoadObject(UObject::StaticClass(), nullptr, itemName.c_str(), nullptr, 0, 0, true);
3522
if (object && ((object->GetClassField()->GetClassCastFlagsField() >> 5) & 1))
3623
{
3724
TSubclassOf<UPrimalItem> archetype;

ArkGameTestingCommands/SpawnCustomDino.cpp

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,22 @@ bool SpawnCustomDino(
66
int dinoBaseLevelHealth, int dinoBaseLevelStamina, int dinoBaseLevelOxygen, int dinoBaseLevelFood, int dinoBaseLevelWeight, int dinoBaseLevelMeleeDamage, int dinoBaseLevelMovementSpeed,
77
int dinoTamedLevelHealth, int dinoTamedLevelStamina, int dinoTamedLevelOxygen, int dinoTamedLevelFood, int dinoTamedLevelWeight, int dinoTamedLevelMeleeDamage, int dinoTamedLevelMovementSpeed,
88
float saddleArmor,
9+
float imprint,
910
std::list<GiveItemDefinition> items,
10-
float offsetX, float offsetY, float offsetZ)
11+
float offsetX, float offsetY, float offsetZ,
12+
bool follow,
13+
AggressionLevel aggressionLevel,
14+
bool ignoreAllWhistles,
15+
bool ignoreAllyLook,
16+
float facingModDegrees)
1117
{
18+
if (bpPath.empty()) return false;
19+
1220
AShooterPlayerController* aShooterPC = FindPlayerControllerFromSteamId(steamId);
1321
if (aShooterPC)
1422
{
15-
std::wstring bpPathWStr = ConvertToWideStr(bpPath);
16-
FString bpPathFString(bpPathWStr);
23+
//todo: does FString release the underlying wchar_t*?
24+
FString bpPathFString = GetBlueprintPathFString(bpPath);
1725

1826
//todo: raycast position (?)
1927
//UWorld* world = Ark::GetWorld();
@@ -26,6 +34,13 @@ bool SpawnCustomDino(
2634
{
2735
APrimalDinoCharacter* dino = static_cast<APrimalDinoCharacter*>(actor);
2836

37+
if (facingModDegrees > 0.0)
38+
{
39+
FRotator rot = dino->GetRootComponentField()->GetRelativeRotationField();
40+
rot.Yaw += facingModDegrees;
41+
dino->SetActorRotation(&rot);
42+
}
43+
2944
dino->SetAbsoluteBaseLevelField(1); //temp set to 1 in order to avoid random level assignment
3045

3146
APlayerState* playerState = aShooterPC->GetPlayerStateField();
@@ -53,7 +68,17 @@ bool SpawnCustomDino(
5368

5469
dino->BeginPlay();
5570

56-
dino->SetTamedFollowTargetField(TWeakObjectPtr<AActor>());
71+
//option: follow
72+
if (!follow) dino->SetTamedFollowTargetField(TWeakObjectPtr<AActor>());
73+
74+
//option: aggression level
75+
dino->SetTamedAggressionLevelField(static_cast<int>(aggressionLevel));
76+
77+
//option: ignore all whistles
78+
if (ignoreAllWhistles) dino->SetbIgnoreAllWhistlesField(true);
79+
80+
//option: ignore ally look
81+
if (ignoreAllyLook) dino->SetbIgnoreAllyLookField(true);
5782

5883
UPrimalCharacterStatusComponent* status = dino->GetMyCharacterStatusComponentField();
5984
if (status)
@@ -97,7 +122,11 @@ bool SpawnCustomDino(
97122
+ dinoTamedLevelMeleeDamage
98123
+ dinoTamedLevelMovementSpeed);
99124

100-
dino->GetMyCharacterStatusComponentField()->AddExperience(status->GetExperienceRequiredForPreviousLevelUp(), false, EXPType::XP_GENERIC);
125+
126+
//NOTE: better to set the actual xp because this call gets scaled by configuration settings for different xp types (generic by default is 2x)
127+
//dino->GetMyCharacterStatusComponentField()->AddExperience(status->GetExperienceRequiredForPreviousLevelUp(), false, EXPType::XP_GENERIC);
128+
129+
status->SetExperiencePointsField(status->GetExperienceRequiredForPreviousLevelUp());
101130

102131
char* statsTamed = status->GetNumberOfLevelUpPointsAppliedTamedField();
103132
statsTamed[0] = dinoTamedLevelHealth;
@@ -109,6 +138,8 @@ bool SpawnCustomDino(
109138
statsTamed[9] = dinoTamedLevelMovementSpeed;
110139

111140
//status->SetNumberOfLevelUpPointsAppliedTamedField(stats);
141+
142+
status->SetbInitializedBaseLevelMaxStatusValuesField(true);
112143
}
113144

114145
//add saddle
@@ -131,7 +162,8 @@ bool SpawnCustomDino(
131162

132163
if (!bpPathSaddle.empty())
133164
{
134-
std::wstring bpPathSaddleWStr = ConvertToWideStr(bpPathSaddle);
165+
std::wstring bpPathSaddleWStr = GetBlueprintNameWideStr(bpPathSaddle);
166+
135167
UObject* object = Globals::StaticLoadObject(UObject::StaticClass(), nullptr, bpPathSaddleWStr.c_str(), nullptr, 0, 0, true);
136168

137169
if (object && ((object->GetClassField()->GetClassCastFlagsField() >> 5) & 1))
@@ -154,7 +186,7 @@ bool SpawnCustomDino(
154186
//give items
155187
for (std::list<GiveItemDefinition>::iterator it = items.begin(); it != items.end(); ++it)
156188
{
157-
std::wstring itemBlueprint = ConvertToWideStr(it->blueprint);
189+
std::wstring itemBlueprint = GetBlueprintNameWideStr(it->blueprint);
158190
UObject* object = Globals::StaticLoadObject(UObject::StaticClass(), nullptr, itemBlueprint.c_str(), nullptr, 0, 0, true);
159191
if (object)
160192
{
@@ -184,17 +216,24 @@ bool SpawnCustomDino(
184216
0i64);*/
185217
}
186218

219+
if (imprint > 0.0)
220+
{
221+
long long playerId = aShooterPC->GetLinkedPlayerIDField();
222+
FString* playerName2 = new FString();
223+
aShooterPC->GetPlayerCharacterName(playerName2);
187224

188-
long long playerId = aShooterPC->GetLinkedPlayerIDField();
189-
FString* playerName2 = new FString();
190-
aShooterPC->GetPlayerCharacterName(playerName2);
191-
192-
dino->UpdateImprintingDetails(playerName2, playerId);
193-
//todo: memory leak? playerName2 not deleted
194-
dino->UpdateImprintingQuality(1.0);
225+
dino->UpdateImprintingDetails(playerName2, playerId);
226+
//todo: memory leak? playerName2 not deleted
227+
dino->UpdateImprintingQuality(imprint > 1.0 ? 1.0 : imprint);
228+
}
229+
else
230+
{
231+
dino->UpdateImprintingQuality(0.0);
232+
}
195233

196-
dino->UpdateStatusComponent(0.0);
197-
dino->ForceNetUpdate(false);
234+
//NOTE: had these before for unknown reasons, but appears to not be required anymore (another way to update base/max stats is to call: status->RescaleAllStats();)
235+
//dino->UpdateStatusComponent(0.0);
236+
//dino->ForceNetUpdate(false);
198237

199238
if (status)
200239
{
@@ -207,8 +246,10 @@ bool SpawnCustomDino(
207246
float* maxStatsValues = status->GetMaxStatusValuesField();
208247
float wildRandomScale = dino->GetWildRandomScaleField();
209248
float* currentStatValues = status->GetCurrentStatusValuesField();
210-
currentStatValues[0] = maxStatsValues[0]; // maxStatsValues[0] * wildRandomScale;
211-
currentStatValues[4] = maxStatsValues[4];
249+
currentStatValues[0] = maxStatsValues[0]; //health (calculated as maxStatsValues[0] * wildRandomScale; in server code)
250+
currentStatValues[1] = maxStatsValues[1]; //stamina
251+
currentStatValues[3] = maxStatsValues[3]; //oxygen
252+
currentStatValues[4] = maxStatsValues[4]; //food
212253

213254
/*v5->MaxStatusValues[2] = (float)((float)(*((float *)&v29 + 2) * v5->TheMaxTorporIncreasePerBaseLevel)
214255
* (float)(v5->BaseCharacterLevel - 1))

ArkGameTestingCommands/SpawnCustomDino.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,32 @@
66
#include <list>
77
#include <iostream>
88

9+
enum AggressionLevel
10+
{
11+
Passive = 0,
12+
Neutral = 1,
13+
Aggressive = 2,
14+
AttackMyTarget = 3
15+
};
16+
17+
enum FacingDirection
18+
{
19+
Forward = 0,
20+
Outwards = 1,
21+
Inwards = 2
22+
};
23+
924
bool SpawnCustomDino(
1025
unsigned long long steamId,
1126
std::string bpPath, std::string bpPathSaddle,
1227
int dinoBaseLevelHealth, int dinoBaseLevelStamina, int dinoBaseLevelOxygen, int dinoBaseLevelFood, int dinoBaseLevelWeight, int dinoBaseLevelMeleeDamage, int dinoBaseLevelMovementSpeed,
1328
int dinoTamedLevelHealth, int dinoTamedLevelStamina, int dinoTamedLevelOxygen, int dinoTamedLevelFood, int dinoTamedLevelWeight, int dinoTamedLevelMeleeDamage, int dinoTamedLevelMovementSpeed,
1429
float saddleArmor,
30+
float imprint,
1531
std::list<GiveItemDefinition> items,
16-
float offsetX, float offsetY, float offsetZ = 300.0);
32+
float offsetX, float offsetY, float offsetZ = 300.0,
33+
bool follow = false,
34+
AggressionLevel aggressionLevel = AggressionLevel::Passive,
35+
bool ignoreAllWhistles = false,
36+
bool ignoreAllyLook = false,
37+
float facingModDegrees = 0.0);

0 commit comments

Comments
 (0)