1+ #include " HealthCommand.h"
2+
3+ void HealthChatCommand (AShooterPlayerController* aShooterPlayerController, FString* msg, EChatSendMode::Type mode)
4+ {
5+ auto result = HealthInternal (aShooterPlayerController, ArkLibrary::GetCommand (CommandName_Health_Chat));
6+ if (result.size () == 0 ) return ;
7+
8+ for (auto str : result) ArkApi::GetApiUtils ().SendChatMessage (aShooterPlayerController, L" [system]" , str.c_str ());
9+ }
10+
11+ void HealthConsoleCommand (APlayerController* aPlayerController, FString* msg, bool bWriteToLog)
12+ {
13+ auto aShooterPlayerController = static_cast <AShooterPlayerController*>(aPlayerController);
14+
15+ auto result = HealthInternal (aShooterPlayerController, ArkLibrary::GetCommand (CommandName_Health_Console));
16+ if (result.size () == 0 ) return ;
17+
18+ std::wstringstream ss;
19+ for (auto str : result) ss << ArkApi::Tools::ConvertToWideStr (str) << std::endl;
20+
21+ ArkApi::GetApiUtils ().SendNotification (aShooterPlayerController, { 1 , 0 , 1 , 1 }, 0 .8f , 30 .0f , nullptr , ss.str ().c_str ());
22+ }
23+
24+ std::list<std::string> HealthInternal (AShooterPlayerController* aShooterPlayerController, ArkLibrary::CommandDefinition *cmd)
25+ {
26+ std::list<std::string> result;
27+
28+ UWorld* world = ArkApi::GetApiUtils ().GetWorld ();
29+ if (!world) return result;
30+ if (!aShooterPlayerController) return result;
31+
32+ ACharacter* character = aShooterPlayerController->CharacterField ()();
33+ if (!character || !character->IsA (APrimalCharacter::GetPrivateStaticClass ())) return result;
34+
35+ APrimalCharacter* primalCharacter = static_cast <APrimalCharacter*>(character);
36+
37+ std::map<std::string, std::list<std::tuple<float , float >>> statuses;
38+ FVector* pos = new FVector ();
39+ int teamId = aShooterPlayerController->TargetingTeamField ()();
40+ FVector playerPos = aShooterPlayerController->DefaultActorLocationField ()();
41+
42+ TArray<AActor*>* FoundActors = new TArray<AActor*>();
43+ UGameplayStatics::GetAllActorsOfClass (reinterpret_cast <UObject *>(world), APrimalDinoCharacter::GetPrivateStaticClass (), FoundActors);
44+
45+ for (uint32_t i = 0 ; i < FoundActors->Num (); i++)
46+ {
47+ AActor* actor = (*FoundActors)[i];
48+
49+ APrimalDinoCharacter* dino = static_cast <APrimalDinoCharacter*>(actor);
50+
51+ int dinoTeam = dino->TargetingTeamField ()();
52+
53+ dino->RootComponentField ()()->GetCustomLocation (pos);
54+ if (dinoTeam == teamId && ArkLibrary::IsPointInside2dCircle (*pos, playerPos.X , playerPos.Y , 5000 ))
55+ {
56+ FString className;
57+ dino->DinoNameTagField ()().ToString (&className); // species name
58+ // std::string name = dino->GetTamedNameField().ToString(); //tamed name
59+
60+ UPrimalCharacterStatusComponent* status = dino->MyCharacterStatusComponentField ()();
61+ if (status)
62+ {
63+ float * currentStatValues = status->CurrentStatusValuesField ()();
64+ float * maxStatsValues = status->MaxStatusValuesField ()();
65+
66+ std::string classNameStr = className.ToString ();
67+
68+ if (statuses.find (classNameStr) == statuses.end ())
69+ {
70+ auto list = std::list<std::tuple<float , float >>();
71+ list.push_back (std::make_tuple (currentStatValues[0 ], maxStatsValues[0 ]));
72+ statuses[classNameStr] = list;
73+ }
74+ else
75+ {
76+ statuses[classNameStr].push_back (std::make_tuple (currentStatValues[0 ], maxStatsValues[0 ]));
77+ }
78+ }
79+ }
80+ }
81+ delete FoundActors;
82+ delete pos;
83+
84+ for (std::map<std::string, std::list<std::tuple<float , float >>>::const_iterator it = statuses.begin (), end = statuses.end (); it != end; ++it)
85+ {
86+ std::string name = it->first ;
87+ std::list<float > percentages;
88+ double totalHealth = 0.0 ;
89+ double totalRemaining = 0.0 ;
90+ double totalDiff = 0.0 ;
91+
92+ for (std::list<std::tuple<float , float >>::const_iterator it2 = it->second .begin (), end2 = it->second .end (); it2 != end2; ++it2)
93+ {
94+ float currentHealth = std::get<0 >(*it2);
95+ float maxHealth = std::get<1 >(*it2);
96+ float healthPercentage = currentHealth / maxHealth;
97+ float healthDiff = maxHealth - currentHealth;
98+
99+ totalHealth += maxHealth;
100+ totalRemaining += currentHealth;
101+ totalDiff += healthDiff;
102+
103+ percentages.push_back (healthPercentage);
104+ }
105+
106+ percentages.sort ([](const float & a, const float & b) { return a < b; });
107+
108+ std::stringstream ss;
109+ ss << name << " (" << percentages.size () << " ): " ;
110+
111+ int n = 0 ;
112+ for (std::list<float >::const_iterator it2 = percentages.begin (), end2 = percentages.end (); it2 != end2; ++it2)
113+ {
114+ if (n > 0 ) ss << " , " ;
115+ ss << std::round (*it2 * 100.0 );
116+
117+ n++;
118+ }
119+
120+ result.push_back (ss.str ());
121+ ss.str (std::string ());
122+
123+ // avoid divide-by-zero exception
124+ if (totalHealth > 0.0 )
125+ {
126+ ss << " Remaining: " << std::round ((totalRemaining / totalHealth) * 100.0 ) << " %, Diff: " << std::round (-totalDiff);
127+ }
128+
129+ result.push_back (ss.str ());
130+ }
131+
132+ return result;
133+ }
0 commit comments