Skip to content

Commit 6808f9d

Browse files
committed
server commerce functionality
1 parent 99b2844 commit 6808f9d

File tree

8 files changed

+427
-46
lines changed

8 files changed

+427
-46
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#pragma once
2+
3+
#include <ScriptEngine.h>
4+
5+
#include <ClientRegistry.h>
6+
#include <ResourceManager.h>
7+
#include <ServerInstanceBaseRef.h>
8+
9+
template<typename TFn>
10+
inline auto MakeClientFunction(TFn fn, uintptr_t defaultValue = 0)
11+
{
12+
return [=](fx::ScriptContext & context)
13+
{
14+
// get the current resource manager
15+
auto resourceManager = fx::ResourceManager::GetCurrent();
16+
17+
// get the owning server instance
18+
auto instance = resourceManager->GetComponent<fx::ServerInstanceBaseRef>()->Get();
19+
20+
// get the server's client registry
21+
auto clientRegistry = instance->GetComponent<fx::ClientRegistry>();
22+
23+
// parse the client ID
24+
const char* id = context.CheckArgument<const char*>(0);
25+
26+
if (!id)
27+
{
28+
context.SetResult(defaultValue);
29+
return;
30+
}
31+
32+
uint32_t netId = atoi(id);
33+
34+
auto client = clientRegistry->GetClientByNetID(netId);
35+
36+
if (!client)
37+
{
38+
context.SetResult(defaultValue);
39+
return;
40+
}
41+
42+
context.SetResult(fn(context, client));
43+
};
44+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
class ServerLicensingComponent : public fwRefCountable
4+
{
5+
public:
6+
ServerLicensingComponent(const std::string& key)
7+
{
8+
m_key = key;
9+
}
10+
11+
inline std::string GetLicenseKey()
12+
{
13+
return m_key;
14+
}
15+
16+
private:
17+
std::string m_key;
18+
};
19+
20+
DECLARE_INSTANCE_TYPE(ServerLicensingComponent);
21+
22+
#define LICENSING_EP "https://keymaster.fivem.net/"

code/components/citizen-server-impl/src/PlayerScriptFunctions.cpp

+12-46
Original file line numberDiff line numberDiff line change
@@ -11,60 +11,26 @@
1111

1212
#include <se/Security.h>
1313

14+
#include <MakeClientFunction.h>
15+
1416
static InitFunction initFunction([]()
1517
{
16-
auto makeClientFunction = [](auto fn, uintptr_t defaultValue = 0)
17-
{
18-
return [=](fx::ScriptContext& context)
19-
{
20-
// get the current resource manager
21-
auto resourceManager = fx::ResourceManager::GetCurrent();
22-
23-
// get the owning server instance
24-
auto instance = resourceManager->GetComponent<fx::ServerInstanceBaseRef>()->Get();
25-
26-
// get the server's client registry
27-
auto clientRegistry = instance->GetComponent<fx::ClientRegistry>();
28-
29-
// parse the client ID
30-
const char* id = context.CheckArgument<const char*>(0);
31-
32-
if (!id)
33-
{
34-
context.SetResult(defaultValue);
35-
return;
36-
}
37-
38-
uint32_t netId = atoi(id);
39-
40-
auto client = clientRegistry->GetClientByNetID(netId);
41-
42-
if (!client)
43-
{
44-
context.SetResult(defaultValue);
45-
return;
46-
}
47-
48-
context.SetResult(fn(context, client));
49-
};
50-
};
51-
52-
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_NAME", makeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
18+
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_NAME", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
5319
{
5420
return client->GetName().c_str();
5521
}));
5622

57-
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_GUID", makeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
23+
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_GUID", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
5824
{
5925
return client->GetGuid().c_str();
6026
}));
6127

62-
fx::ScriptEngine::RegisterNativeHandler("GET_NUM_PLAYER_IDENTIFIERS", makeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
28+
fx::ScriptEngine::RegisterNativeHandler("GET_NUM_PLAYER_IDENTIFIERS", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
6329
{
6430
return client->GetIdentifiers().size();
6531
}));
6632

67-
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_IDENTIFIER", makeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
33+
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_IDENTIFIER", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
6834
{
6935
int idx = context.GetArgument<int>(1);
7036

@@ -76,15 +42,15 @@ static InitFunction initFunction([]()
7642
return client->GetIdentifiers()[idx].c_str();
7743
}));
7844

79-
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_ENDPOINT", makeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
45+
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_ENDPOINT", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
8046
{
8147
static thread_local std::string str;
8248
str = client->GetTcpEndPoint();
8349

8450
return str.c_str();
8551
}));
8652

87-
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_PING", makeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
53+
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_PING", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
8854
{
8955
auto peer = gscomms_get_peer(client->GetPeer());
9056

@@ -96,12 +62,12 @@ static InitFunction initFunction([]()
9662
return int(peer->GetPing());
9763
}));
9864

99-
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_LAST_MSG", makeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
65+
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_LAST_MSG", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
10066
{
10167
return (msec() - client->GetLastSeen()).count();
10268
}, 0x7fffffff));
10369

104-
fx::ScriptEngine::RegisterNativeHandler("DROP_PLAYER", makeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
70+
fx::ScriptEngine::RegisterNativeHandler("DROP_PLAYER", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
10571
{
10672
// get the current resource manager
10773
auto resourceManager = fx::ResourceManager::GetCurrent();
@@ -117,7 +83,7 @@ static InitFunction initFunction([]()
11783
return true;
11884
}));
11985

120-
fx::ScriptEngine::RegisterNativeHandler("IS_PLAYER_ACE_ALLOWED", makeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
86+
fx::ScriptEngine::RegisterNativeHandler("IS_PLAYER_ACE_ALLOWED", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client)
12187
{
12288
const char* object = context.CheckArgument<const char*>(1);
12389

@@ -210,7 +176,7 @@ static InitFunction initFunction([]()
210176
}
211177
});
212178

213-
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_PED", makeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client) -> uint32_t
179+
fx::ScriptEngine::RegisterNativeHandler("GET_PLAYER_PED", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client) -> uint32_t
214180
{
215181
try
216182
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
#include <StdInc.h>
2+
3+
#include <MakeClientFunction.h>
4+
5+
#include <ServerInstanceBase.h>
6+
#include <ServerInstanceBaseRef.h>
7+
8+
#include <ResourceManager.h>
9+
#include <ScriptEngine.h>
10+
11+
#include <HttpClient.h>
12+
13+
#include <ServerLicensingComponent.h>
14+
15+
#include <json.hpp>
16+
17+
#include <optional>
18+
19+
inline std::string GetLicenseKey()
20+
{
21+
auto resourceManager = fx::ResourceManager::GetCurrent();
22+
auto instance = resourceManager->GetComponent<fx::ServerInstanceBaseRef>()->Get();
23+
auto licensing = instance->GetComponent<ServerLicensingComponent>();
24+
25+
return licensing->GetLicenseKey();
26+
}
27+
28+
class CommerceComponent : public fwRefCountable
29+
{
30+
public:
31+
CommerceComponent(fx::Client* client)
32+
: m_commerceDataLoaded(false), m_client(client)
33+
{
34+
35+
}
36+
37+
inline bool HasCommerceDataLoaded()
38+
{
39+
return m_commerceDataLoaded;
40+
}
41+
42+
void LoadCommerceData();
43+
44+
std::optional<int> GetUserId();
45+
46+
void SetSkus(std::set<int>&& list);
47+
48+
bool OwnsSku(int sku);
49+
50+
void RequestSkuPurchase(int sku);
51+
52+
private:
53+
fx::Client* m_client;
54+
55+
bool m_commerceDataLoaded;
56+
57+
std::set<int> m_ownedSkus;
58+
};
59+
60+
static HttpClient* httpClient = new HttpClient(L"FXServer/Licensing");
61+
62+
void CommerceComponent::LoadCommerceData()
63+
{
64+
auto userId = GetUserId();
65+
66+
if (m_commerceDataLoaded || !userId)
67+
{
68+
return;
69+
}
70+
71+
fwRefContainer<CommerceComponent> thisRef(this);
72+
73+
httpClient->DoGetRequest(fmt::sprintf(LICENSING_EP "api/entitlements/%d/%s", *userId, GetLicenseKey()), [thisRef](bool success, const char* data, size_t length)
74+
{
75+
if (success)
76+
{
77+
try
78+
{
79+
auto json = nlohmann::json::parse(std::string(data, length));
80+
std::set<int> skuIds;
81+
82+
for (auto& entry : json["entitlements"])
83+
{
84+
skuIds.insert(entry.value<int>("sku_id", 0));
85+
}
86+
87+
thisRef->SetSkus(std::move(skuIds));
88+
}
89+
catch (const std::exception& e)
90+
{
91+
92+
}
93+
}
94+
});
95+
}
96+
97+
void CommerceComponent::SetSkus(std::set<int>&& list)
98+
{
99+
m_ownedSkus = std::move(list);
100+
m_commerceDataLoaded = true;
101+
}
102+
103+
bool CommerceComponent::OwnsSku(int sku)
104+
{
105+
return m_ownedSkus.find(sku) != m_ownedSkus.end();
106+
}
107+
108+
void CommerceComponent::RequestSkuPurchase(int sku)
109+
{
110+
auto userId = GetUserId();
111+
112+
if (!userId)
113+
{
114+
return;
115+
}
116+
117+
fwRefContainer<CommerceComponent> thisRef(this);
118+
auto clientRef = m_client->shared_from_this();
119+
120+
httpClient->DoGetRequest(fmt::sprintf(LICENSING_EP "api/paymentRequest/%d/%d/%s", *userId, sku, GetLicenseKey()), [thisRef, clientRef](bool success, const char* data, size_t length)
121+
{
122+
if (success)
123+
{
124+
// build the target event
125+
net::Buffer outBuffer;
126+
outBuffer.Write(HashRageString("msgPaymentRequest"));
127+
128+
// payload
129+
outBuffer.Write(data, length);
130+
131+
// send along
132+
clientRef->SendPacket(0, outBuffer, NetPacketType_Reliable);
133+
}
134+
});
135+
}
136+
137+
std::optional<int> CommerceComponent::GetUserId()
138+
{
139+
const auto& identifiers = m_client->GetIdentifiers();
140+
141+
for (const auto& identifier : identifiers)
142+
{
143+
if (identifier.find("fivem:") == 0)
144+
{
145+
int userId = atoi(identifier.substr(6).c_str());
146+
147+
if (userId != 0)
148+
{
149+
return userId;
150+
}
151+
}
152+
}
153+
154+
return {};
155+
}
156+
157+
DECLARE_INSTANCE_TYPE(CommerceComponent);
158+
159+
static InitFunction initFunction([]()
160+
{
161+
fx::ScriptEngine::RegisterNativeHandler("CAN_PLAYER_START_COMMERCE_SESSION", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client) -> uint32_t
162+
{
163+
return client->GetComponent<CommerceComponent>()->GetUserId() ? true : false;
164+
}));
165+
166+
fx::ServerInstanceBase::OnServerCreate.Connect([](fx::ServerInstanceBase* instance)
167+
{
168+
auto clientRegistry = instance->GetComponent<fx::ClientRegistry>();
169+
170+
clientRegistry->OnClientCreated.Connect([=](fx::Client* client)
171+
{
172+
client->SetComponent(new CommerceComponent(client));
173+
});
174+
});
175+
176+
fx::ScriptEngine::RegisterNativeHandler("LOAD_PLAYER_COMMERCE_DATA", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client) -> uint32_t
177+
{
178+
auto commerceData = client->GetComponent<CommerceComponent>();
179+
180+
commerceData->LoadCommerceData();
181+
182+
return commerceData->HasCommerceDataLoaded();
183+
}));
184+
185+
fx::ScriptEngine::RegisterNativeHandler("IS_PLAYER_COMMERCE_INFO_LOADED", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client) -> uint32_t
186+
{
187+
auto commerceData = client->GetComponent<CommerceComponent>();
188+
189+
return commerceData->HasCommerceDataLoaded();
190+
}));
191+
192+
fx::ScriptEngine::RegisterNativeHandler("DOES_PLAYER_OWN_SKU", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client) -> uint32_t
193+
{
194+
auto commerceData = client->GetComponent<CommerceComponent>();
195+
196+
return commerceData->OwnsSku(context.GetArgument<int>(1));
197+
}));
198+
199+
fx::ScriptEngine::RegisterNativeHandler("REQUEST_PLAYER_COMMERCE_SESSION", MakeClientFunction([](fx::ScriptContext& context, const std::shared_ptr<fx::Client>& client) -> bool
200+
{
201+
auto commerceData = client->GetComponent<CommerceComponent>();
202+
commerceData->RequestSkuPurchase(context.GetArgument<int>(1));
203+
204+
return true;
205+
}));
206+
});

0 commit comments

Comments
 (0)