Skip to content

Commit f812c67

Browse files
committed
Updated for 2.0
- Added support for admin badges - Added support for server tags
1 parent d82d7eb commit f812c67

24 files changed

Lines changed: 618 additions & 211951 deletions

ArkCrossServerChat/ArkCrossServerChat.cpp

Lines changed: 144 additions & 223 deletions
Large diffs are not rendered by default.

ArkCrossServerChat/ArkCrossServerChat.h

Lines changed: 0 additions & 7 deletions
This file was deleted.

ArkCrossServerChat/ArkCrossServerChat.vcxproj

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<VCProjectVersion>15.0</VCProjectVersion>
2323
<ProjectGuid>{6E3CB8BD-966B-4CAA-8CF6-D8DD3499DC35}</ProjectGuid>
2424
<RootNamespace>ArkCrossServerChat</RootNamespace>
25-
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
25+
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
2626
</PropertyGroup>
2727
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
2828
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@@ -70,8 +70,8 @@
7070
</ImportGroup>
7171
<PropertyGroup Label="UserMacros" />
7272
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
73-
<IncludePath>C:\ArkApi\include;$(IncludePath)</IncludePath>
74-
<LibraryPath>C:\ArkApi\lib;$(LibraryPath)</LibraryPath>
73+
<IncludePath>C:\ArkApi2\include;$(IncludePath)</IncludePath>
74+
<LibraryPath>C:\ArkApi2\lib;$(LibraryPath)</LibraryPath>
7575
</PropertyGroup>
7676
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
7777
<ClCompile>
@@ -107,27 +107,28 @@
107107
<FunctionLevelLinking>true</FunctionLevelLinking>
108108
<IntrinsicFunctions>true</IntrinsicFunctions>
109109
<SDLCheck>true</SDLCheck>
110+
<LanguageStandard>stdcpp17</LanguageStandard>
111+
<PreprocessorDefinitions>_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS;_WINDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
110112
</ClCompile>
111113
<Link>
112114
<EnableCOMDATFolding>true</EnableCOMDATFolding>
113115
<OptimizeReferences>true</OptimizeReferences>
114116
</Link>
115117
</ItemDefinitionGroup>
116118
<ItemGroup>
117-
<ClInclude Include="ArkCrossServerChat.h" />
118-
<ClInclude Include="hdr\sqlite_modern_cpp.h" />
119-
<ClInclude Include="hdr\sqlite_modern_cpp\extensions\boost_json_spirit.h" />
120-
<ClInclude Include="hdr\sqlite_modern_cpp\extensions\boost_uuid.h" />
121-
<ClInclude Include="hdr\sqlite_modern_cpp\extensions\std_time_t.h" />
122-
<ClInclude Include="hdr\sqlite_modern_cpp\utility\function_traits.h" />
123-
<ClInclude Include="json.hpp" />
124-
<ClInclude Include="sqlite3.h" />
125-
<ClInclude Include="Tools.h" />
119+
<ClInclude Include="DatabaseCleanup.h" />
120+
<ClInclude Include="Hooks.h" />
121+
<ClInclude Include="MessageHandlers.h" />
122+
<ClInclude Include="Plugin.h" />
123+
<ClInclude Include="Utils.h" />
126124
</ItemGroup>
127125
<ItemGroup>
128126
<ClCompile Include="ArkCrossServerChat.cpp" />
129-
<ClCompile Include="sqlite3.c" />
130-
<ClCompile Include="Tools.cpp" />
127+
<ClCompile Include="DatabaseCleanup.cpp" />
128+
<ClCompile Include="Hooks.cpp" />
129+
<ClCompile Include="MessageHandlers.cpp" />
130+
<ClCompile Include="Plugin.cpp" />
131+
<ClCompile Include="Utils.cpp" />
131132
</ItemGroup>
132133
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
133134
<ImportGroup Label="ExtensionTargets">

ArkCrossServerChat/ArkCrossServerChat.vcxproj.filters

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,39 @@
1515
</Filter>
1616
</ItemGroup>
1717
<ItemGroup>
18-
<ClInclude Include="hdr\sqlite_modern_cpp\extensions\boost_json_spirit.h">
18+
<ClInclude Include="Utils.h">
1919
<Filter>Header Files</Filter>
2020
</ClInclude>
21-
<ClInclude Include="hdr\sqlite_modern_cpp\extensions\boost_uuid.h">
21+
<ClInclude Include="DatabaseCleanup.h">
2222
<Filter>Header Files</Filter>
2323
</ClInclude>
24-
<ClInclude Include="hdr\sqlite_modern_cpp\extensions\std_time_t.h">
24+
<ClInclude Include="Hooks.h">
2525
<Filter>Header Files</Filter>
2626
</ClInclude>
27-
<ClInclude Include="hdr\sqlite_modern_cpp\utility\function_traits.h">
27+
<ClInclude Include="MessageHandlers.h">
2828
<Filter>Header Files</Filter>
2929
</ClInclude>
30-
<ClInclude Include="hdr\sqlite_modern_cpp.h">
31-
<Filter>Header Files</Filter>
32-
</ClInclude>
33-
<ClInclude Include="ArkCrossServerChat.h">
34-
<Filter>Header Files</Filter>
35-
</ClInclude>
36-
<ClInclude Include="json.hpp">
37-
<Filter>Header Files</Filter>
38-
</ClInclude>
39-
<ClInclude Include="sqlite3.h">
40-
<Filter>Header Files</Filter>
41-
</ClInclude>
42-
<ClInclude Include="Tools.h">
30+
<ClInclude Include="Plugin.h">
4331
<Filter>Header Files</Filter>
4432
</ClInclude>
4533
</ItemGroup>
4634
<ItemGroup>
4735
<ClCompile Include="ArkCrossServerChat.cpp">
4836
<Filter>Source Files</Filter>
4937
</ClCompile>
50-
<ClCompile Include="sqlite3.c">
38+
<ClCompile Include="Utils.cpp">
39+
<Filter>Source Files</Filter>
40+
</ClCompile>
41+
<ClCompile Include="DatabaseCleanup.cpp">
42+
<Filter>Source Files</Filter>
43+
</ClCompile>
44+
<ClCompile Include="Hooks.cpp">
45+
<Filter>Source Files</Filter>
46+
</ClCompile>
47+
<ClCompile Include="MessageHandlers.cpp">
5148
<Filter>Source Files</Filter>
5249
</ClCompile>
53-
<ClCompile Include="Tools.cpp">
50+
<ClCompile Include="Plugin.cpp">
5451
<Filter>Source Files</Filter>
5552
</ClCompile>
5653
</ItemGroup>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "DatabaseCleanup.h"
2+
3+
void CleanupTimer()
4+
{
5+
auto& plugin = Plugin::Get();
6+
7+
auto now = std::chrono::system_clock::now();
8+
auto diff = std::chrono::duration_cast<std::chrono::seconds>(plugin.NextCleanupTime - now);
9+
10+
if (diff.count() <= 0)
11+
{
12+
plugin.NextCleanupTime = now + std::chrono::seconds(3600);
13+
14+
try
15+
{
16+
*plugin.db << u"DELETE FROM Messages "
17+
"WHERE At <= ?;" << (std::chrono::system_clock::now() - std::chrono::seconds(3600 * 24 * 7)).time_since_epoch().count();
18+
}
19+
catch (sqlite::sqlite_exception& e)
20+
{
21+
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, e.what());
22+
}
23+
}
24+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#pragma once
2+
#include "Plugin.h"
3+
4+
void CleanupTimer();

ArkCrossServerChat/Hooks.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#include "Hooks.h"
2+
3+
// intercept player chat messages
4+
bool ChatMessageCallback(AShooterPlayerController* _AShooterPlayerController, FString* Message, EChatSendMode::Type Mode, bool spam_check, bool command_executed)
5+
{
6+
if (spam_check || command_executed) return false;
7+
8+
auto& plugin = Plugin::Get();
9+
auto playerControllerEx = reinterpret_cast<ArkExtensions::AShooterPlayerController*>(_AShooterPlayerController);
10+
11+
// process the message and relay
12+
long double lastChatMessageTime = 0;
13+
std::wstring msg;
14+
if (_AShooterPlayerController && Message && Mode == EChatSendMode::Type::GlobalChat)
15+
{
16+
lastChatMessageTime = _AShooterPlayerController->LastChatMessageTimeField()();
17+
msg = std::wstring(ArkApi::Tools::ConvertToWideStr(Message->ToString()));
18+
19+
auto steamId = static_cast<int64>(ArkApi::GetApiUtils().GetSteamIdFromController(_AShooterPlayerController));
20+
auto playerName = GetPlayerName(_AShooterPlayerController);
21+
auto characterName = GetPlayerCharacterName(_AShooterPlayerController);
22+
auto tribeName = GetTribeName(_AShooterPlayerController);
23+
24+
auto icon = playerControllerEx->bIsAdminField()()
25+
&& !_AShooterPlayerController->bSuppressAdminIconField()()
26+
? ChatIcon::Admin
27+
: ChatIcon::None;
28+
29+
//todo: maybe support other badges in the future (but when are they used?)
30+
//auto badgeGroups = uPrimalGameData->BadgeGroupsNameTagField()();
31+
//if (badgeGroups.Num() > icon) icon = reinterpret_cast<DWORD64>(badgeGroups[icon]);
32+
33+
try
34+
{
35+
*plugin.db << u"INSERT INTO Messages (At,ServerKey,ServerTag,SteamId,PlayerName,CharacterName,TribeName,Message,Type,Icon) "
36+
"VALUES (?,?,?,?,?,?,?,?,?,?);"
37+
<< std::chrono::system_clock::now().time_since_epoch().count()
38+
<< plugin.serverKey
39+
<< plugin.serverTag
40+
<< steamId
41+
<< playerName
42+
<< ToUTF16(characterName)
43+
<< tribeName
44+
<< ToUTF16(msg)
45+
<< (int)Mode
46+
<< (int)icon;
47+
48+
//notify other servers
49+
PulseEvent(plugin.handle_mre_cluster);
50+
}
51+
catch (sqlite::sqlite_exception& e)
52+
{
53+
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, e.what());
54+
}
55+
56+
return true;
57+
}
58+
59+
return false;
60+
}
61+
62+
// intercept rcon chat messages
63+
void Hook_UShooterCheatManager_ServerChat(UShooterCheatManager* _UShooterCheatManager, FString* MessageText)
64+
{
65+
auto& plugin = Plugin::Get();
66+
if (MessageText)
67+
{
68+
try
69+
{
70+
std::string serverKey = plugin.serverKey;
71+
*plugin.db << u"INSERT INTO Messages (At,ServerKey,Message,Type,Rcon) VALUES (?,?,?,?,?);"
72+
<< std::chrono::system_clock::now().time_since_epoch().count()
73+
<< serverKey
74+
<< ToUTF16(**MessageText)
75+
<< -1 << 1;
76+
77+
//notify other servers
78+
PulseEvent(plugin.handle_mre_cluster);
79+
}
80+
catch (sqlite::sqlite_exception& e)
81+
{
82+
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, e.what());
83+
}
84+
}
85+
86+
UShooterCheatManager_ServerChat_original(_UShooterCheatManager, MessageText);
87+
}

ArkCrossServerChat/Hooks.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#pragma once
2+
#include "Plugin.h"
3+
4+
DECLARE_HOOK_INLINE(UShooterCheatManager_ServerChat, void, UShooterCheatManager*, FString*);
5+
6+
bool ChatMessageCallback(AShooterPlayerController* _AShooterPlayerController, FString* Message, EChatSendMode::Type Mode, bool spam_check, bool command_executed);
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#include "MessageHandlers.h"
2+
3+
DWORD WINAPI WaitForNewMessagesThreadProc(LPVOID lpParam)
4+
{
5+
UNREFERENCED_PARAMETER(lpParam);
6+
7+
auto &plugin = Plugin::Get();
8+
HANDLE events[] = { plugin.handle_mre_cluster, plugin.handle_mre_thread };
9+
10+
bool exit = false;
11+
while (!exit)
12+
{
13+
auto dwWaitResult = WaitForMultipleObjects(2, events, FALSE, INFINITE);
14+
switch (dwWaitResult)
15+
{
16+
case WAIT_OBJECT_0 + 0:
17+
if (ArkApi::GetApiUtils().GetWorld())
18+
{
19+
OnNewMessagesFromDatabase();
20+
}
21+
break;
22+
case WAIT_OBJECT_0 + 1:
23+
exit = true;
24+
break;
25+
case WAIT_TIMEOUT:
26+
default:
27+
Sleep(1000); //todo: ?
28+
}
29+
}
30+
31+
CloseHandle(plugin.handle_mre_cluster);
32+
CloseHandle(plugin.handle_mre_thread);
33+
34+
return 0;
35+
}
36+
37+
// when the database has been updated with new messages
38+
void OnNewMessagesFromDatabase()
39+
{
40+
auto &plugin = Plugin::Get();
41+
try
42+
{
43+
*plugin.db << "SELECT Id,At,ServerKey,ServerTag,SteamId,PlayerName,CharacterName,TribeName,Message,Type,Rcon,Icon "
44+
"FROM Messages "
45+
"WHERE Id > ? "
46+
"ORDER BY Id ASC;" << plugin.lastRowId >>
47+
[&](long long id,
48+
long long at,
49+
std::string serverKey,
50+
std::string serverTag,
51+
long long steamId,
52+
std::string playerName,
53+
std::u16string characterName,
54+
std::string tribeName,
55+
std::u16string message,
56+
int type,
57+
int rcon,
58+
int icon)
59+
{
60+
HandleMessageFromDatabase(id, at, serverKey, serverTag, steamId, playerName, characterName, tribeName, message, type, rcon, icon);
61+
plugin.lastRowId = id;
62+
};
63+
}
64+
catch (sqlite::sqlite_exception& e)
65+
{
66+
Log::GetLog()->error("({} {}) Unexpected DB error {}", __FILE__, __FUNCTION__, e.what());
67+
}
68+
}
69+
70+
void HandleMessageFromDatabase(
71+
long long id,
72+
long long at,
73+
std::string serverKey,
74+
std::string serverTag,
75+
long long steamId,
76+
std::string playerName,
77+
std::u16string characterName,
78+
std::string tribeName,
79+
std::u16string message,
80+
int type,
81+
int rcon,
82+
int icon)
83+
{
84+
auto &plugin = Plugin::Get();
85+
//send chat message to users
86+
if (rcon == 0)
87+
{
88+
auto chatIcon = static_cast<ChatIcon>(icon);
89+
UTexture2D *iconTexture = nullptr;
90+
91+
auto isLocal = serverKey.compare(plugin.serverKey) == 0;
92+
93+
// get chat icon
94+
if (chatIcon == ChatIcon::Admin)
95+
{
96+
auto engine = Globals::GEngine()();
97+
auto primalglobals = engine->GameSingletonField()();
98+
auto gamedata = primalglobals->PrimalGameDataOverrideField()();
99+
if (!gamedata) gamedata = primalglobals->PrimalGameDataField()();
100+
101+
auto texture = gamedata->NameTagServerAdminField()();
102+
if (texture) iconTexture = gamedata->NameTagServerAdminField()();
103+
}
104+
105+
auto name = FString(FromUTF16(characterName).c_str());
106+
if (!isLocal || !plugin.hideServerTagOnLocal)
107+
{
108+
// format name with server tag
109+
auto name_with_tag = FString(ArkApi::Tools::ConvertToWideStr(plugin.namePattern).c_str());
110+
name_with_tag.ReplaceInline(L"{Name}", *name);
111+
name_with_tag.ReplaceInline(L"{ServerTag}", ArkApi::Tools::ConvertToWideStr(serverTag).c_str());
112+
name = name_with_tag;
113+
}
114+
115+
// get the sender id (to support own name showing in gray for the player)
116+
unsigned int linkedPlayerDataID;
117+
if (serverKey.compare(plugin.serverKey) == 0)
118+
{
119+
auto player_controller = ArkApi::GetApiUtils().FindPlayerFromSteamId(steamId);
120+
if (player_controller)
121+
{
122+
auto player_character = player_controller->GetPlayerCharacter();
123+
if (player_character) linkedPlayerDataID = player_character->LinkedPlayerDataIDField()();
124+
}
125+
}
126+
127+
SendChatMessageToAll(
128+
linkedPlayerDataID,
129+
name,
130+
FromUTF8(playerName).c_str(),
131+
FromUTF8(tribeName).c_str(),
132+
FromUTF16(message).c_str(),
133+
iconTexture);
134+
}
135+
else
136+
{
137+
SendRconChatMessageToAll(FromUTF16(message));
138+
}
139+
}

0 commit comments

Comments
 (0)