-
Notifications
You must be signed in to change notification settings - Fork 1
/
IAGS2Client.cpp
242 lines (225 loc) · 11.4 KB
/
IAGS2Client.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// AGS2Client
// Client Plugin Interface for AGS
// Copyright © 2015-2016 MonkeyMoto Productions, Inc.
//
// This work is free. You can redistribute it and/or modify it under the
// terms of the Do What The Fuck You Want To Public License, Version 2,
// as published by Sam Hocevar. See the LICENSE file for more details.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif // WIN32_LEAN_AND_MEAN
#elif defined(__linux__) // !_WIN32
#define __stdcall
#endif // _WIN32, __linux__
#include "Cpp11Fix.h"
#include <algorithm>
#include TR1INCLUDE(unordered_map)
#include <string>
#include <sstream>
#include "agsplugin.h"
#include "IAGS2Client.h"
#include "IClientAchievements.h"
#include "IClientLeaderboards.h"
#include "IClientStats.h"
using namespace AGS2Client;
#ifndef AGS2CLIENT_HAS_CPP11 // NOT C++11
float constexpr const IAGS2Client::VERSION = 2.0f;
#endif // C++11
struct IAGS2Client_Statics
{
public:
static std::string PLUGIN_NAME;
static std::string CLIENT_NAME;
static std::string GENERATED_HEADER;
static stdtr1compat::unordered_map<std::string, void*> FUNCTIONS;
};
std::string IAGS2Client_Statics::PLUGIN_NAME;
std::string IAGS2Client_Statics::CLIENT_NAME;
std::string IAGS2Client_Statics::GENERATED_HEADER;
stdtr1compat::unordered_map<std::string, void*> IAGS2Client_Statics::FUNCTIONS;
extern "C" IAGSEngine* GetAGSEngine();
extern "C" bool StripPluginName_IsInvalidChar(char c)
{
return (((c < 48) || (c > 57)) && ((c < 65) || (c > 90)) && (c != 95) && ((c < 97) || (c > 122)));
}
extern "C" char const* IAGS2Client_GetPluginNameStripped() noexcept
{
std::string &pluginName = IAGS2Client_Statics::PLUGIN_NAME;
if (pluginName.empty())
{
std::string buffer(GetClient()->GetAGSPluginName());
buffer.erase(std::remove_if(buffer.begin(), buffer.end(), StripPluginName_IsInvalidChar), buffer.end());
buffer.erase(0, buffer.find_first_not_of("0123456789"));
pluginName = (buffer.empty() ? "AGS2Client" : buffer);
}
return pluginName.c_str();
}
char const* IAGS2Client::GetClientNameForScript() const noexcept
{
std::string &clientName = IAGS2Client_Statics::CLIENT_NAME;
if (clientName.empty())
{
#ifdef AGS2CLIENT_UNIFIED_CLIENT_NAME
clientName = "AGS2Client";
#else // !AGS2CLIENT_UNIFIED_CLIENT_NAME
clientName = IAGS2Client_GetPluginNameStripped();
#endif // AGS2CLIENT_UNIFIED_CLIENT_NAME
}
return clientName.c_str();
}
char const* IAGS2Client::GetAGSScriptHeader() const noexcept
{
std::string &generatedHeader = IAGS2Client_Statics::GENERATED_HEADER;
if (generatedHeader.empty())
{
float version = this->GetVersion();
std::string clientName(this->GetClientNameForScript());
std::ostringstream header;
#ifdef AGS2CLIENT_UNIFIED_CLIENT_NAME
std::string pluginName(IAGS2Client_GetPluginNameStripped());
if (pluginName != clientName) // account for the unlikely event that pluginName has no usable characters and defaults to AGS2Client
{
// include plugin's ACTUAL name version macro (if it is not already included by DISJOINT plugin!)
header << "#ifndef " << pluginName << "_VERSION\r\n"
"#define " << pluginName << "_VERSION " << version << "\r\n"
"#endif // " << pluginName << "_VERSION\r\n";
}
#endif // AGS2CLIENT_UNIFIED_CLIENT_NAME
header <<
"#define " << clientName << "_VERSION " << version << "\r\n"
"\r\n"
"enum " << clientName << "StatType\r\n"
"{\r\n"
" e" << clientName << "StatInt = 0,\r\n"
" e" << clientName << "StatFloat = 1,\r\n"
" e" << clientName << "StatAverageRate = 2\r\n"
"};\r\n"
"\r\n"
"enum " << clientName << "ScoresRequestType\r\n"
"{\r\n"
" e" << clientName << "ScoresRequestGlobal = 0,\r\n"
" e" << clientName << "ScoresRequestAroundUser = 1,\r\n"
" e" << clientName << "ScoresRequestFriends = 2\r\n"
"};\r\n"
"\r\n"
"managed struct " << clientName << "\r\n"
"{\r\n"
" ///" << clientName << ": Returns whether the specified achievement has been achieved\r\n"
" import static int IsAchievementAchieved(const string name);\r\n"
" ///" << clientName << ": Sets an achievement as achieved\r\n"
" import static int SetAchievementAchieved(const string name);\r\n"
" ///" << clientName << ": Resets the specified achievement, so it can be achieved again\r\n"
" import static int ResetAchievement(const string name);\r\n"
" ///" << clientName << ": Sets the value of an INT stat\r\n"
" import static int SetIntStat(const string name, int value);\r\n"
" ///" << clientName << ": Sets the value of a FLOAT stat\r\n"
" import static int SetFloatStat(const string name, float value);\r\n"
" ///" << clientName << ": Updates an average rate stat\r\n"
" import static int UpdateAverageRateStat(const string name, float countThisSession, float sessionLength);\r\n"
" ///" << clientName << ": Returns the value of an INT stat\r\n"
" import static int GetIntStat(const string name);\r\n"
" ///" << clientName << ": Returns the value of a FLOAT stat\r\n"
" import static float GetFloatStat(const string name);\r\n"
" ///" << clientName << ": Returns the value of an average rate stat\r\n"
" import static float GetAverageRateStat(const string name);\r\n"
" ///" << clientName << ": Resets all stats and achievements\r\n"
" import static void ResetStatsAndAchievements();\r\n"
" ///" << clientName << ": Returns whether the client is loaded and the user logged in\r\n"
" readonly import static attribute int Initialized;\r\n"
" ///" << clientName << ": Returns the name of the current leaderboard (call FindLeaderboard first)\r\n"
" readonly import static attribute String CurrentLeaderboardName;\r\n"
" ///" << clientName << ": Requests to load the specified leaderboard. This call is asynchronous and does not return the data immediately, check for results in repeatedly_execute\r\n"
" import static void RequestLeaderboard(const string leaderboardName, " << clientName << "ScoresRequestType, int limit=10);\r\n"
" ///" << clientName << ": Uploads the score to the current leaderboard (call RequestLeaderboard first). Returns false if an error occurs\r\n"
" import static int UploadScore(int score);\r\n"
" ///" << clientName << ": Returns the name associated with a leaderboard rank (call RequestLeaderboard first)\r\n"
" readonly import static attribute String LeaderboardNames[];\r\n"
" ///" << clientName << ": Returns a leader's score from the current leaderboard (call RequestLeaderboard first)\r\n"
" readonly import static attribute int LeaderboardScores[];\r\n"
" ///" << clientName << ": Returns the number of leaders in the current leaderboard (if any) (call RequestLeaderboard first)\r\n"
" readonly import static attribute int LeaderboardCount;\r\n"
" ///" << clientName << ": Returns the username from the client\r\n"
" import static String GetUserName();\r\n"
" ///" << clientName << ": Returns the current game language from the client\r\n"
" import static String GetCurrentGameLanguage();\r\n"
<< this->GetExtraFunctionsForScriptHeader() <<
"};\r\n"
"\r\n";
generatedHeader = header.str();
}
return generatedHeader.c_str();
}
char const* IAGS2Client::GetExtraFunctionsForScriptHeader() const noexcept
{
return "";
}
void IAGS2Client::RegisterScriptFunctions(IAGSEngine *engine) const noexcept
{
stdtr1compat::unordered_map<std::string, void*> &functions = IAGS2Client_Statics::FUNCTIONS; // RegisterScriptFunction does not copy the buffer, we must persist it ourselves
typedef stdtr1compat::unordered_map<std::string, void*>::iterator functions_iterator;
std::string clientName(this->GetClientNameForScript());
functions[clientName + "::IsAchievementAchieved^1"] = reinterpret_cast<void*>(ClientAchievements_IsAchievementAchieved);
functions[clientName + "::SetAchievementAchieved^1"] = reinterpret_cast<void*>(ClientAchievements_SetAchievementAchieved);
functions[clientName + "::ResetAchievement^1"] = reinterpret_cast<void*>(ClientAchievements_ResetAchievement);
functions[clientName + "::GetIntStat^1"] = reinterpret_cast<void*>(ClientStats_GetIntStat);
functions[clientName + "::GetFloatStat^1"] = reinterpret_cast<void*>(ClientStats_GetFloatStat);
functions[clientName + "::GetAverageRateStat^1"] = reinterpret_cast<void*>(ClientStats_GetAverageRateStat);
functions[clientName + "::SetIntStat^2"] = reinterpret_cast<void*>(ClientStats_SetIntStat);
functions[clientName + "::SetFloatStat^2"] = reinterpret_cast<void*>(ClientStats_SetFloatStat);
functions[clientName + "::UpdateAverageRateStat^3"] = reinterpret_cast<void*>(ClientStats_UpdateAverageRateStat);
functions[clientName + "::ResetStatsAndAchievements^0"] = reinterpret_cast<void*>(AGS2Client_ResetStatsAndAchievements);
functions[clientName + "::get_Initialized"] = reinterpret_cast<void*>(AGS2Client_IsInitialized);
functions[clientName + "::get_CurrentLeaderboardName"] = reinterpret_cast<void*>(ClientLeaderboards_GetCurrentLeaderboardName);
functions[clientName + "::RequestLeaderboard^3"] = reinterpret_cast<void*>(ClientLeaderboards_RequestLeaderboard);
functions[clientName + "::UploadScore^1"] = reinterpret_cast<void*>(ClientLeaderboards_UploadScore);
functions[clientName + "::geti_LeaderboardNames"] = reinterpret_cast<void*>(ClientLeaderboards_GetLeaderName);
functions[clientName + "::geti_LeaderboardScores"] = reinterpret_cast<void*>(ClientLeaderboards_GetLeaderScore);
functions[clientName + "::get_LeaderboardCount"] = reinterpret_cast<void*>(ClientLeaderboards_GetLeaderCount);
functions[clientName + "::GetUserName^0"] = reinterpret_cast<void*>(AGS2Client_GetUserName);
functions[clientName + "::GetCurrentGameLanguage^0"] = reinterpret_cast<void*>(AGS2Client_GetCurrentGameLanguage);
for (functions_iterator it = functions.begin(); it != functions.end(); ++it)
{
engine->RegisterScriptFunction(it->first.c_str(), it->second);
}
}
IAGS2Client::~IAGS2Client() noexcept
{
}
namespace AGS2Client
{
int AGS2Client_IsInitialized() noexcept
{
return (GetClient()->IsInitialized() != 0);
}
void AGS2Client_ResetStatsAndAchievements() noexcept
{
GetClient()->ResetStatsAndAchievements();
}
char const* AGS2Client_GetUserName() noexcept
{
char const *userName = GetClient()->GetUserName();
return (userName == nullptr ? nullptr : GetAGSEngine()->CreateScriptString(userName));
}
char const* AGS2Client_GetCurrentGameLanguage()
{
char const *gameLanguage = GetClient()->GetCurrentGameLanguage();
return (gameLanguage == nullptr ? nullptr : GetAGSEngine()->CreateScriptString(gameLanguage));
}
}