-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathgodotsteam_server.cpp
4818 lines (4250 loc) · 264 KB
/
godotsteam_server.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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Turn off MSVC-only warning about strcpy
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:4996)
#pragma warning(disable:4828)
#endif
// Include GodotSteam Server header
#include "godotsteam_server.h"
// Include some system headers
#include "fstream"
#include "vector"
SteamServer *SteamServer::singleton = NULL;
SteamServer::SteamServer():
// Game Server
callbackServerConnectFailure(this, &SteamServer::server_connect_failure),
callbackServerConnected(this, &SteamServer::server_connected),
callbackServerDisconnected(this, &SteamServer::server_disconnected),
callbackClientApproved(this, &SteamServer::client_approved),
callbackClientDenied(this, &SteamServer::client_denied),
callbackClientKicked(this, &SteamServer::client_kick),
callbackPolicyResponse(this, &SteamServer::policy_response),
callbackClientGroupStatus(this, &SteamServer::client_group_status),
callbackAssociateClan(this, &SteamServer::associate_clan),
callbackPlayerCompat(this, &SteamServer::player_compat),
// Game Server Stats
callbackStatsStored(this, &SteamServer::stats_stored),
callbackStatsUnloaded(this, &SteamServer::stats_unloaded),
// HTTP
callbackHTTPRequestCompleted(this, &SteamServer::http_request_completed),
callbackHTTPRequestDataReceived(this, &SteamServer::http_request_data_received),
callbackHTTPRequestHeadersReceived(this, &SteamServer::http_request_headers_received),
// Inventory
callbackInventoryDefinitionUpdate(this, &SteamServer::inventory_definition_update),
callbackInventoryFullUpdate(this, &SteamServer::inventory_full_update),
callbackInventoryResultReady(this, &SteamServer::inventory_result_ready),
// Networking
callbackP2PSessionConnectFail(this, &SteamServer::p2p_session_connect_fail),
callbackP2PSessionRequest(this, &SteamServer::p2p_session_request),
// Networking Messages
callbackNetworkMessagesSessionRequest(this, &SteamServer::network_messages_session_request),
callbackNetworkMessagesSessionFailed(this, &SteamServer::network_messages_session_failed),
// Networking Sockets
callbackNetworkConnectionStatusChanged(this, &SteamServer::network_connection_status_changed),
callbackNetworkAuthenticationStatus(this, &SteamServer::network_authentication_status),
callbackNetworkingFakeIPResult(this, &SteamServer::fake_ip_result),
// Networking Utils
callbackRelayNetworkStatus(this, &SteamServer::relay_network_status),
// Remote Storage
callbackLocalFileChanged(this, &SteamServer::local_file_changed),
// UGC
callbackItemDownloaded(this, &SteamServer::item_downloaded),
callbackItemInstalled(this, &SteamServer::item_installed),
callbackUserSubscribedItemsListChanged(this, &SteamServer::user_subscribed_items_list_changed)
{
is_init_success = false;
singleton = this;
}
///// INTERNAL
// Helper function to turn an array of options into an array of SteamNetworkingConfigValue_t structs
// These arrays contain dictionaries of { NetworkingConfigValue enum : value for config }
const SteamNetworkingConfigValue_t *SteamServer::convert_config_options(Dictionary config_options) {
uint32 options_size = config_options.size();
SteamNetworkingConfigValue_t *option_array = new SteamNetworkingConfigValue_t[options_size];
if (options_size > 0) {
for (uint32 i = 0; i < options_size; i++) {
SteamNetworkingConfigValue_t this_option;
int sent_option = (int)config_options.keys()[i];
// Get the configuration value.
// This is a convoluted way of doing it but can't seem to cast the value as an enum so here we are.
ESteamNetworkingConfigValue this_value = ESteamNetworkingConfigValue((int)sent_option);
Variant::Type value_type = config_options[sent_option].get_type();
if (value_type == Variant::INT) {
if (sent_option == NETWORKING_CONFIG_CONNECTION_USER_DATA) {
this_option.SetInt64(this_value, config_options[sent_option]);
}
else {
this_option.SetInt32(this_value, config_options[sent_option]);
}
}
else if (value_type == Variant::FLOAT) {
this_option.SetFloat(this_value, config_options[sent_option]);
}
else if (value_type == Variant::STRING) {
this_option.SetString(this_value, String(config_options[sent_option]).utf8().get_data());
}
else {
Object *this_pointer;
this_pointer = config_options[sent_option];
this_option.SetPtr(this_value, this_pointer);
}
option_array[i] = this_option;
}
}
return option_array;
}
// Creating a Steam ID for internal use
CSteamID SteamServer::createSteamID(uint64_t steam_id, AccountType account_type) {
CSteamID converted_steam_id;
if (account_type < 0 || account_type >= AccountType(k_EAccountTypeMax)) {
account_type = ACCOUNT_TYPE_INDIVIDUAL;
}
converted_steam_id.Set(steam_id, k_EUniversePublic, EAccountType(account_type));
return converted_steam_id;
}
// Get the Steam singleton, obviously
SteamServer* SteamServer::get_singleton() {
return singleton;
}
// Convert a Steam ID to a Steam Identity
SteamNetworkingIdentity SteamServer::getIdentityFromSteamID(uint64_t steam_id) {
SteamNetworkingIdentity remote_identity;
remote_identity.SetSteamID64(steam_id);
return remote_identity;
}
// Convert a string IP address to an integer
uint32 SteamServer::getIPFromString(String ip_string) {
uint32 ip_address = 0;
SteamNetworkingIPAddr this_address;
this_address.Clear();
if (this_address.ParseString(ip_string.utf8().get_data())) {
ip_address = this_address.GetIPv4();
}
return ip_address;
}
// Convert a Steam IP Address object to an integer
uint32 SteamServer::getIPFromSteamIP(SteamNetworkingIPAddr this_address) {
return this_address.GetIPv4();
}
// Get the Steam ID from an identity struct
uint64_t SteamServer::getSteamIDFromIdentity(SteamNetworkingIdentity this_identity) {
uint64_t this_steam_id = this_identity.GetSteamID64();
return this_steam_id;
}
// Convert an integer to a Steam IP Address
SteamNetworkingIPAddr SteamServer::getSteamIPFromInt(uint32 ip_integer) {
SteamNetworkingIPAddr this_address;
this_address.Clear();
if (ip_integer > 0) {
this_address.SetIPv4(ip_integer, 0);
}
return this_address;
}
// Convert an IP string to a Steam IP Address
SteamNetworkingIPAddr SteamServer::getSteamIPFromString(String ip_string) {
SteamNetworkingIPAddr this_address;
this_address.Clear();
if (this_address.ParseString(ip_string.utf8().get_data())) {
this_address.GetIPv4();
}
return this_address;
}
// Convert an integer IP address to a string
String SteamServer::getStringFromIP(uint32 ip_integer) {
String ip_address = "";
SteamNetworkingIPAddr this_address;
this_address.Clear();
if (ip_integer > 0) {
this_address.SetIPv4(ip_integer, 0);
char this_ip[16];
this_address.ToString(this_ip, 16, false);
ip_address = String(this_ip);
}
return ip_address;
}
// Convert a Steam IP Address to a string
String SteamServer::getStringFromSteamIP(SteamNetworkingIPAddr this_address) {
char this_ip[16];
this_address.ToString(this_ip, 16, false);
return String(this_ip);
}
///// MAIN FUNCTIONS
// Convert a SteamID64 into a SteamID
uint32_t SteamServer::getSteamID32(uint64_t steam_id) {
CSteamID this_steam_id = (uint64)steam_id;
return this_steam_id.GetAccountID();
}
// Gets the server's Steam ID.
uint64_t SteamServer::getServerSteamID() {
return SteamGameServer_GetSteamID();
}
// Is this an anonymous account?
bool SteamServer::isAnonAccount(uint64_t steam_id) {
CSteamID this_steam_id = (uint64)steam_id;
return this_steam_id.BAnonAccount();
}
// Is this an anonymous user account? Used to create an account or reset a password, but do not try to do this.
bool SteamServer::isAnonUserAccount(uint64_t steam_id) {
CSteamID this_steam_id = (uint64)steam_id;
return this_steam_id.BAnonUserAccount();
}
// Is this a chat account ID?
bool SteamServer::isChatAccount(uint64_t steam_id) {
CSteamID this_steam_id = (uint64)steam_id;
return this_steam_id.BChatAccount();
}
// Is this a clan account ID?
bool SteamServer::isClanAccount(uint64_t steam_id) {
CSteamID this_steam_id = (uint64)steam_id;
return this_steam_id.BClanAccount();
}
// Is this a faked up Steam ID for a PSN friend account?
bool SteamServer::isConsoleUserAccount(uint64_t steam_id) {
CSteamID this_steam_id = (uint64)steam_id;
return this_steam_id.BConsoleUserAccount();
}
// Is this an individual user account ID?
bool SteamServer::isIndividualAccount(uint64_t steam_id) {
CSteamID this_steam_id = (uint64)steam_id;
return this_steam_id.BIndividualAccount();
}
// Is this a lobby account ID?
bool SteamServer::isLobby(uint64_t steam_id) {
CSteamID this_steam_id = (uint64)steam_id;
return this_steam_id.IsLobby();
}
// No official notes, but should be checking if the server is secured.
bool SteamServer::isServerSecure() {
return SteamGameServer_BSecure();
}
// Initialize SteamGameServer client and interface objects, and set server properties which may not be changed.
// After calling this function, you should set any additional server parameters, and then logOnAnonymous() or logOn().
bool SteamServer::serverInit(const String &ip, uint16 game_port, uint16 query_port, ServerMode server_mode, const String &version_number) {
if (!SteamGameServer_Init(getIPFromString(ip), game_port, query_port, (EServerMode)server_mode, version_number.utf8().get_data())) {
return false;
}
return true;
}
// Initialize SteamGameServer client and interface objects, and set server properties which may not be changed.
// After calling this function, you should set any additional server parameters, and then logOnAnonymous() or logOn().
// On success STEAM_API_INIT_RESULT_OK is returned. Otherwise, if error_message is non-NULL, it will receive a non-localized message that explains the reason for the failure
Dictionary SteamServer::serverInitEx(const String &ip, uint16 game_port, uint16 query_port, ServerMode server_mode, const String &version_number) {
char error_message[STEAM_MAX_ERROR_MESSAGE] = "Server initialized successfully";
ESteamAPIInitResult initialize_result = k_ESteamAPIInitResult_FailedGeneric;
initialize_result = SteamGameServer_InitEx(getIPFromString(ip), game_port, query_port, (EServerMode)server_mode, version_number.utf8().get_data(), &error_message);
Dictionary server_initialize;
server_initialize["status"] = initialize_result;
server_initialize["verbal"] = error_message;
return server_initialize;
}
// Frees all API-related memory associated with the calling thread. This memory is released automatically by RunCallbacks so single-threaded servers do not need to call this.
void SteamServer::serverReleaseCurrentThreadMemory() {
SteamAPI_ReleaseCurrentThreadMemory();
}
// Shut down the server connection to Steam.
void SteamServer::serverShutdown() {
SteamGameServer_Shutdown();
}
///// GAME SERVER FUNCTIONS
// NOTE: The following, if set, must be set before calling LogOn; they may not be changed after.
//
// Game product identifier; currently used by the master server for version checking purposes.
void SteamServer::setProduct(const String &product) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setProduct");
SteamGameServer()->SetProduct(product.utf8().get_data());
}
// Description of the game; required field and is displayed in the Steam server browser.
void SteamServer::setGameDescription(const String &description) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setGameDescription");
SteamGameServer()->SetGameDescription(description.utf8().get_data());
}
// If your game is a mod, pass the string that identifies it. Default is empty meaning the app is the original game.
void SteamServer::setModDir(const String &mod_directory) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setModDir");
SteamGameServer()->SetModDir(mod_directory.utf8().get_data());
}
// Is this a dedicated server? Default is false.
void SteamServer::setDedicatedServer(bool dedicated) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setDedicatedServer");
SteamGameServer()->SetDedicatedServer(dedicated);
}
// NOTE: The following are login functions.
//
// Begin process to login to a persistent game server account. You need to register for callbacks to determine the result of this operation.
void SteamServer::logOn(const String &token) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: logOn");
SteamGameServer()->LogOn(token.utf8().get_data());
}
// Login to a generic, anonymous account.
void SteamServer::logOnAnonymous() {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: logOnAnonymous");
SteamGameServer()->LogOnAnonymous();
}
// Begin process of logging game server out of Steam.
void SteamServer::logOff() {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: logOff");
SteamGameServer()->LogOff();
}
// Status functions.
bool SteamServer::loggedOn() {
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, false, "[STEAM SERVER] Server class not found when calling: loggedOn");
return SteamGameServer()->BLoggedOn();
}
bool SteamServer::secure() {
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, false, "[STEAM SERVER] Server class not found when calling: secure");
return SteamGameServer()->BSecure();
}
uint64_t SteamServer::getSteamID() {
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, 0, "[STEAM SERVER] Server class not found when calling: getSteamID");
CSteamID serverID = SteamGameServer()->GetSteamID();
return serverID.ConvertToUint64();
}
// Returns true if the master server has requested a restart. Only returns true once per request.
bool SteamServer::wasRestartRequested() {
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, false, "[STEAM SERVER] Server class not found when calling: wasRestartRequested");
return SteamGameServer()->WasRestartRequested();
}
// NOTE: These are server state functions and can be changed at any time.
//
// Max player count that will be reported to server browser and client queries.
void SteamServer::setMaxPlayerCount(int players_max) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setMaxPlayerCount");
SteamGameServer()->SetMaxPlayerCount(players_max);
}
// Number of bots. Default is zero.
void SteamServer::setBotPlayerCount(int bots) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setBotPlayerCount");
SteamGameServer()->SetBotPlayerCount(bots);
}
// Set the naem of the server as it will appear in the server browser.
void SteamServer::setServerName(const String &name) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setServerName");
SteamGameServer()->SetServerName(name.utf8().get_data());
}
// Set name of map to report in server browser.
void SteamServer::setMapName(const String &map) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setMapName");
SteamGameServer()->SetMapName(map.utf8().get_data());
}
// Let people know if your server requires a password.
void SteamServer::setPasswordProtected(bool password_protected) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setPasswordProtected");
SteamGameServer()->SetPasswordProtected(password_protected);
}
// Spectator server. Default is zero, meaning it is now used.
void SteamServer::setSpectatorPort(uint16 port) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setSpectatorPort");
SteamGameServer()->SetSpectatorPort(port);
}
// Name of spectator server. Only used if spectator port is non-zero.
void SteamServer::setSpectatorServerName(const String &name) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setSpectatorServerName");
SteamGameServer()->SetSpectatorServerName(name.utf8().get_data());
}
// Call this to clear the whole list of key/values that are sent in rule queries.
void SteamServer::clearAllKeyValues() {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: clearAllKeyValues");
SteamGameServer()->ClearAllKeyValues();
}
// Call this to add/update a key/value pair.
void SteamServer::setKeyValue(const String &key, const String &value) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setKeyValue");
SteamGameServer()->SetKeyValue(key.utf8().get_data(), value.utf8().get_data());
}
// Set a string defining game tags for this server; optional. Allows users to filter in matchmaking/server browser.
void SteamServer::setGameTags(const String &tags) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setGameTags");
SteamGameServer()->SetGameTags(tags.utf8().get_data());
}
// Set a string defining game data for this server; optional. Allows users to filter in matchmaking/server browser.
void SteamServer::setGameData(const String &data) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setGameData");
SteamGameServer()->SetGameData(data.utf8().get_data());
}
// Region identifier; optional. Default is empty meaning 'world'.
void SteamServer::setRegion(const String ®ion) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setRegion");
SteamGameServer()->SetRegion(region.utf8().get_data());
}
// NOTE: These functions are player list management / authentication.
//
// Retrieve ticket to be sent to the entity who wishes to authenticate you (using BeginAuthSession API).
Dictionary SteamServer::getAuthSessionTicket(uint64_t remote_steam_id) {
Dictionary auth_ticket;
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, auth_ticket, "[STEAM SERVER] Server class not found when calling: getAuthSessionTicket");
uint32_t id = 0;
uint32_t ticket_size = 1024;
PackedByteArray buffer;
buffer.resize(ticket_size);
if (remote_steam_id == 0) {
SteamNetworkingIdentity auth_identity = getIdentityFromSteamID(remote_steam_id);
id = SteamGameServer()->GetAuthSessionTicket(buffer.ptrw(), ticket_size, &ticket_size, &auth_identity);
}
else{
id = SteamGameServer()->GetAuthSessionTicket(buffer.ptrw(), ticket_size, &ticket_size, NULL);
}
// Add this data to the dictionary
auth_ticket["id"] = id;
auth_ticket["buffer"] = buffer;
auth_ticket["size"] = ticket_size;
return auth_ticket;
}
// Authenticate the ticket from the entity Steam ID to be sure it is valid and isn't reused.
uint32 SteamServer::beginAuthSession(PackedByteArray ticket, int ticket_size, uint64_t steam_id) {
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, -1, "[STEAM SERVER] Server class not found when calling: beginAuthSession");
CSteamID auth_steam_id = createSteamID(steam_id);
return SteamGameServer()->BeginAuthSession(ticket.ptr(), ticket_size, auth_steam_id);
}
// Stop tracking started by beginAuthSession; called when no longer playing game with this entity;
void SteamServer::endAuthSession(uint64_t steam_id) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: endAuthSession");
CSteamID auth_steam_id = createSteamID(steam_id);
SteamGameServer()->EndAuthSession(auth_steam_id);
}
// Cancel auth ticket from getAuthSessionTicket; called when no longer playing game with the entity you gave the ticket to.
void SteamServer::cancelAuthTicket(uint32_t auth_ticket) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: cancelAuthTicket");
SteamGameServer()->CancelAuthTicket(auth_ticket);
}
// After receiving a user's authentication data, and passing it to sendUserConnectAndAuthenticate, use to determine if user owns DLC
int SteamServer::userHasLicenceForApp(uint64_t steam_id, uint32 app_id) {
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, 0, "[STEAM SERVER] Server class not found when calling: userHasLicenceForApp");
CSteamID user_id = (uint64)steam_id;
return SteamGameServer()->UserHasLicenseForApp(user_id, (AppId_t)app_id);
}
// Ask if user is in specified group; results returned by GSUserGroupStatus_t.
bool SteamServer::requestUserGroupStatus(uint64_t steam_id, int group_id) {
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, false, "[STEAM SERVER] Server class not found when calling: requestUserGroupStatus");
CSteamID user_id = (uint64)steam_id;
CSteamID clan_id = (uint64)group_id;
return SteamGameServer()->RequestUserGroupStatus(user_id, clan_id);
}
// NOTE: These are in GameSocketShare mode, where instead of ISteamGameServer creating sockets to talk to master server, it lets the game use its socket to forward messages back and forth.
//
// These are used when you've elected to multiplex the game server's UDP socket rather than having the master server updater use its own sockets.
Dictionary SteamServer::handleIncomingPacket(int packet, const String &ip, uint16 port) {
Dictionary result;
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, result, "[STEAM SERVER] Server class not found when calling: handleIncomingPacket");
PackedByteArray data;
data.resize(packet);
if (SteamGameServer()->HandleIncomingPacket(data.ptrw(), packet, getIPFromString(ip), port)) {
result["data"] = data;
}
return result;
}
// AFTER calling HandleIncomingPacket for any packets that came in that frame, call this. This gets a packet that the master server updater needs to send out on UDP. Returns 0 if there are no more packets.
Dictionary SteamServer::getNextOutgoingPacket() {
Dictionary packet;
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, packet, "[STEAM SERVER] Server class not found when calling: getNextOutgoingPacket");
PackedByteArray out;
int max_out = 16 * 1024;
uint32 address;
uint16 port;
// Retrieve the packet information
int length = SteamGameServer()->GetNextOutgoingPacket(&out, max_out, &address, &port);
// Place packet information in dictionary and return it
packet["length"] = length;
packet["out"] = out;
packet["address"] = address;
packet["port"] = port;
return packet;
}
// Gets the public IP of the server according to Steam.
Dictionary SteamServer::getPublicIP() {
Dictionary public_ip;
ERR_FAIL_COND_V_MSG(SteamGameServer() == NULL, public_ip, "[STEAM SERVER] Server class not found when calling: getPublicIP");
SteamIPAddress_t this_public_ip = SteamGameServer()->GetPublicIP();
uint8 *ipv6_address = new uint8[16];
ipv6_address = this_public_ip.m_rgubIPv6;
public_ip["ipv4"] = this_public_ip.m_unIPv4;
public_ip["ipv6"] = ipv6_address;
public_ip["type"] = this_public_ip.m_eType;
return public_ip;
}
// NOTE: These are heartbeat/advertisement functions.
//
// Call this as often as you like to tell the master server updater whether or not you want it to be active (default: off).
void SteamServer::setAdvertiseServerActive(bool active) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: setAdvertiseServerActive");
SteamGameServer()->SetAdvertiseServerActive(active);
}
// Associate this game server with this clan for the purposes of computing player compatibility.
void SteamServer::associateWithClan(uint64_t clan_id) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: associateWithClan");
CSteamID group_id = (uint64)clan_id;
SteamGameServer()->AssociateWithClan(group_id);
}
// Ask if any of the current players dont want to play with this new player - or vice versa.
void SteamServer::computeNewPlayerCompatibility(uint64_t steam_id) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server class not found when calling: computeNewPlayerCompatibility");
CSteamID user_id = (uint64)steam_id;
SteamGameServer()->ComputeNewPlayerCompatibility(user_id);
}
///// GAME SERVER STATS
// Resets the unlock status of an achievement for the specified user.
bool SteamServer::clearUserAchievement(uint64_t steam_id, const String &name) {
ERR_FAIL_COND_V_MSG(SteamGameServerStats() == NULL, false, "[STEAM SERVER] Server Stats class not found when calling: clearUserAchievement");
CSteamID user_id = (uint64)steam_id;
return SteamGameServerStats()->ClearUserAchievement(user_id, name.utf8().get_data());
}
// Gets the unlock status of the Achievement.
Dictionary SteamServer::getUserAchievement(uint64_t steam_id, const String &name) {
Dictionary achieve;
ERR_FAIL_COND_V_MSG(SteamGameServerStats() == NULL, achieve, "[STEAM SERVER] Server Stats class not found when calling: getUserAchievement");
bool achieved = false;
CSteamID user_id = (uint64)steam_id;
bool success = SteamGameServerStats()->GetUserAchievement(user_id, name.utf8().get_data(), &achieved);
if (success) {
achieve["steam_id"] = steam_id;
achieve["retrieved"] = success;
achieve["name"] = name;
achieve["achieved"] = achieved;
}
return achieve;
}
// Gets the current value of the a stat for the specified user.
float SteamServer::getUserStatFloat(uint64_t steam_id, const String &name) {
ERR_FAIL_COND_V_MSG(SteamGameServerStats() == NULL, 0, "[STEAM SERVER] Server Stats class not found when calling: getUserStatFloat");
float stat_value = 0.0;
CSteamID user_id = (uint64)steam_id;
SteamGameServerStats()->GetUserStat(user_id, name.utf8().get_data(), &stat_value);
return stat_value;
}
// Gets the current value of the a stat for the specified user.
uint32_t SteamServer::getUserStatInt(uint64_t steam_id, const String &name) {
ERR_FAIL_COND_V_MSG(SteamGameServerStats() == NULL, 0, "[STEAM SERVER] Server Stats class not found when calling: getUserStatInt");
int32_t stat_value = 0;
CSteamID user_id = (uint64)steam_id;
SteamGameServerStats()->GetUserStat(user_id, name.utf8().get_data(), &stat_value);
return stat_value;
}
// Asynchronously downloads stats and achievements for the specified user from the server.
void SteamServer::requestUserStats(uint64_t steam_id) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server Stats class not found when calling: requestUserStats");
CSteamID user_id = (uint64)steam_id;
SteamAPICall_t api_call = SteamGameServerStats()->RequestUserStats(user_id);
callResultStatReceived.Set(api_call, this, &SteamServer::stats_received);
}
// Unlocks an achievement for the specified user.
bool SteamServer::setUserAchievement(uint64_t steam_id, const String &name) {
ERR_FAIL_COND_V_MSG(SteamGameServerStats() == NULL, false, "[STEAM SERVER] Server Stats class not found when calling: setUserAchievement");
CSteamID user_id = (uint64)steam_id;
return SteamGameServerStats()->SetUserAchievement(user_id, name.utf8().get_data());
}
// Sets / updates the value of a given stat for the specified user.
bool SteamServer::setUserStatFloat(uint64_t steam_id, const String &name, float stat) {
ERR_FAIL_COND_V_MSG(SteamGameServerStats() == NULL, false, "[STEAM SERVER] Server Stats class not found when calling: setUserStatFloat");
CSteamID user_id = (uint64)steam_id;
return SteamGameServerStats()->SetUserStat(user_id, name.utf8().get_data(), stat);
}
// Sets / updates the value of a given stat for the specified user.
bool SteamServer::setUserStatInt(uint64_t steam_id, const String &name, int32 stat) {
ERR_FAIL_COND_V_MSG(SteamGameServerStats() == NULL, false, "[STEAM SERVER] Server Stats class not found when calling: setUserStatInt");
CSteamID user_id = (uint64)steam_id;
return SteamGameServerStats()->SetUserStat(user_id, name.utf8().get_data(), stat);
}
// Send the changed stats and achievements data to the server for permanent storage for the specified user.
void SteamServer::storeUserStats(uint64_t steam_id) {
ERR_FAIL_COND_MSG(SteamGameServer() == NULL, "[STEAM SERVER] Server Stats class not found when calling: storeUserStats");
CSteamID user_id = (uint64)steam_id;
SteamGameServerStats()->StoreUserStats(user_id);
}
// Updates an AVGRATE stat with new values for the specified user.
bool SteamServer::updateUserAvgRateStat(uint64_t steam_id, const String &name, float this_session, double session_length) {
ERR_FAIL_COND_V_MSG(SteamGameServerStats() == NULL, false, "[STEAM SERVER] Server Stats class not found when calling: updateUserAvgRateStat");
CSteamID user_id = (uint64)steam_id;
return SteamGameServerStats()->UpdateUserAvgRateStat(user_id, name.utf8().get_data(), this_session, session_length);
}
///// HTTP
// Creates a cookie container to store cookies during the lifetime of the process. This API is just for during process lifetime, after steam restarts no cookies are persisted and you have no way to access the cookie container across repeat executions of your process.
uint32_t SteamServer::createCookieContainer(bool allow_responses_to_modify) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, 0, "[STEAM SERVER] HTTP class not found when calling: createCookieContainer");
return SteamHTTP()->CreateCookieContainer(allow_responses_to_modify);
}
// Initializes a new HTTP request.
uint32_t SteamServer::createHTTPRequest(HTTPMethod request_method, const String &absolute_url) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, HTTPREQUEST_INVALID_HANDLE, "[STEAM SERVER] HTTP class not found when calling: createCookieContainer");
return SteamHTTP()->CreateHTTPRequest((EHTTPMethod)request_method, absolute_url.utf8().get_data());
}
// Defers a request which has already been sent by moving it at the back of the queue.
bool SteamServer::deferHTTPRequest(uint32 request_handle) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: deferHTTPRequest");
return SteamHTTP()->DeferHTTPRequest(request_handle);
}
// Gets progress on downloading the body for the request.
float SteamServer::getHTTPDownloadProgressPct(uint32 request_handle) {
float percent_one = 0.0;
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, percent_one, "[STEAM SERVER] HTTP class not found when calling: getHTTPDownloadProgressPct");
SteamHTTP()->GetHTTPDownloadProgressPct(request_handle, &percent_one);
return percent_one;
}
// Check if the reason the request failed was because we timed it out (rather than some harder failure).
bool SteamServer::getHTTPRequestWasTimedOut(uint32 request_handle) {
bool was_timed_out = false;
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, was_timed_out, "[STEAM SERVER] HTTP class not found when calling: getHTTPRequestWasTimedOut");
SteamHTTP()->GetHTTPRequestWasTimedOut(request_handle, &was_timed_out);
return was_timed_out;
}
// Gets the body data from an HTTP response.
PackedByteArray SteamServer::getHTTPResponseBodyData(uint32 request_handle, uint32 buffer_size) {
PackedByteArray body_data;
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, body_data, "[STEAM SERVER] HTTP class not found when calling: getHTTPResponseBodyData");
body_data.resize(buffer_size);
SteamHTTP()->GetHTTPResponseBodyData(request_handle, body_data.ptrw(), buffer_size);
return body_data;
}
// Gets the size of the body data from an HTTP response.
uint32 SteamServer::getHTTPResponseBodySize(uint32 request_handle) {
uint32 body_size = 0;
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, body_size, "[STEAM SERVER] HTTP class not found when calling: getHTTPResponseBodySize");
SteamHTTP()->GetHTTPResponseBodySize(request_handle, &body_size);
return body_size;
}
// Checks if a header is present in an HTTP response and returns its size.
uint32 SteamServer::getHTTPResponseHeaderSize(uint32 request_handle, const String &header_name) {
uint32 response_header_size = 0;
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, response_header_size, "[STEAM SERVER] HTTP class not found when calling: getHTTPResponseHeaderSize");
SteamHTTP()->GetHTTPResponseHeaderSize(request_handle, header_name.utf8().get_data(), &response_header_size);
return response_header_size;
}
// Gets a header value from an HTTP response.
PackedByteArray SteamServer::getHTTPResponseHeaderValue(uint32 request_handle, const String &header_name, uint32 buffer_size) {
PackedByteArray header_data;
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, header_data, "[STEAM SERVER] HTTP class not found when calling: getHTTPResponseHeaderValue");
header_data.resize(buffer_size);
SteamHTTP()->GetHTTPResponseHeaderValue(request_handle, header_name.utf8().get_data(), header_data.ptrw(), buffer_size);
return header_data;
}
// Gets the body data from a streaming HTTP response.
PackedByteArray SteamServer::getHTTPStreamingResponseBodyData(uint32 request_handle, uint32 offset, uint32 buffer_size) {
PackedByteArray body_data;
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, body_data, "[STEAM SERVER] HTTP class not found when calling: getHTTPStreamingResponseBodyData");
body_data.resize(buffer_size);
SteamHTTP()->GetHTTPStreamingResponseBodyData(request_handle, offset, body_data.ptrw(), buffer_size);
return body_data;
}
// Prioritizes a request which has already been sent by moving it at the front of the queue.
bool SteamServer::prioritizeHTTPRequest(uint32 request_handle) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: prioritizeHTTPRequest");
return SteamHTTP()->PrioritizeHTTPRequest(request_handle);
}
// Releases a cookie container, freeing the memory allocated within Steam.
bool SteamServer::releaseCookieContainer(uint32 cookie_handle) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: releaseCookieContainer");
return SteamHTTP()->ReleaseCookieContainer(cookie_handle);
}
// Releases an HTTP request handle, freeing the memory allocated within Steam.
bool SteamServer::releaseHTTPRequest(uint32 request_handle) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: releaseHTTPRequest");
return SteamHTTP()->ReleaseHTTPRequest(request_handle);
}
// Sends an HTTP request.
bool SteamServer::sendHTTPRequest(uint32 request_handle) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: sendHTTPRequest");
SteamAPICall_t call_handle;
return SteamHTTP()->SendHTTPRequest(request_handle, &call_handle);
}
// Sends an HTTP request and streams the response back in chunks.
bool SteamServer::sendHTTPRequestAndStreamResponse(uint32 request_handle) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: sendHTTPRequestAndStreamResponse");
SteamAPICall_t call_handle;
return SteamHTTP()->SendHTTPRequestAndStreamResponse(request_handle, &call_handle);
}
// Adds a cookie to the specified cookie container that will be used with future requests.
bool SteamServer::setHTTPCookie(uint32 cookie_handle, const String &host, const String &url, const String &cookie) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: setHTTPCookie");
return SteamHTTP()->SetCookie(cookie_handle, host.utf8().get_data(), url.utf8().get_data(), cookie.utf8().get_data());
}
// Set an absolute timeout in milliseconds for the HTTP request. This is the total time timeout which is different than the network activity timeout which is set with SetHTTPRequestNetworkActivityTimeout which can bump everytime we get more data.
bool SteamServer::setHTTPRequestAbsoluteTimeoutMS(uint32 request_handle, uint32 milliseconds) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: setHTTPRequestAbsoluteTimeoutMS");
return SteamHTTP()->SetHTTPRequestAbsoluteTimeoutMS(request_handle, milliseconds);
}
// Set a context value for the request, which will be returned in the HTTPRequestCompleted_t callback after sending the request. This is just so the caller can easily keep track of which callbacks go with which request data. Must be called before sending the request.
bool SteamServer::setHTTPRequestContextValue(uint32 request_handle, uint64_t context_value) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: setHTTPRequestContextValue");
return SteamHTTP()->SetHTTPRequestContextValue(request_handle, context_value);
}
// Associates a cookie container to use for an HTTP request.
bool SteamServer::setHTTPRequestCookieContainer(uint32 request_handle, uint32 cookie_handle) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: setHTTPRequestCookieContainer");
return SteamHTTP()->SetHTTPRequestCookieContainer(request_handle, cookie_handle);
}
// Set a GET or POST parameter value on the HTTP request. Must be called prior to sending the request.
bool SteamServer::setHTTPRequestGetOrPostParameter(uint32 request_handle, const String &name, const String &value) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: setHTTPRequestGetOrPostParameter");
return SteamHTTP()->SetHTTPRequestGetOrPostParameter(request_handle, name.utf8().get_data(), value.utf8().get_data());
}
// Set a request header value for the HTTP request. Must be called before sending the request.
bool SteamServer::setHTTPRequestHeaderValue(uint32 request_handle, const String &header_name, const String &header_value) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: setHTTPRequestHeaderValue");
return SteamHTTP()->SetHTTPRequestHeaderValue(request_handle, header_name.utf8().get_data(), header_value.utf8().get_data());
}
// Set the timeout in seconds for the HTTP request.
bool SteamServer::setHTTPRequestNetworkActivityTimeout(uint32 request_handle, uint32 timeout_seconds) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: setHTTPRequestNetworkActivityTimeout");
return SteamHTTP()->SetHTTPRequestNetworkActivityTimeout(request_handle, timeout_seconds);
}
// Sets the body for an HTTP Post request.
bool SteamServer::setHTTPRequestRawPostBody(uint32 request_handle, const String &content_type, const String &body) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: setHTTPRequestRawPostBody");
auto body_utf8 = body.utf8();
return SteamHTTP()->SetHTTPRequestRawPostBody(request_handle, content_type.utf8().get_data(), reinterpret_cast<uint8 *>(body_utf8.ptrw()), body_utf8.size());
}
// Sets that the HTTPS request should require verified SSL certificate via machines certificate trust store. This currently only works Windows and macOS.
bool SteamServer::setHTTPRequestRequiresVerifiedCertificate(uint32 request_handle, bool require_verified_certificate) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: setHTTPRequestNetworkActivityTimeout");
return SteamHTTP()->SetHTTPRequestRequiresVerifiedCertificate(request_handle, require_verified_certificate);
}
// Set additional user agent info for a request.
bool SteamServer::setHTTPRequestUserAgentInfo(uint32 request_handle, const String &user_agent_info) {
ERR_FAIL_COND_V_MSG(SteamHTTP() == NULL, false, "[STEAM SERVER] HTTP class not found when calling: setHTTPRequestNetworkActivityTimeout");
return SteamHTTP()->SetHTTPRequestUserAgentInfo(request_handle, user_agent_info.utf8().get_data());
}
///// INVENTORY
///// When dealing with any inventory handles, you should call CheckResultSteamID on the result handle when it completes to verify that a remote player is not pretending to have a different user's inventory.
///// Also, you must call DestroyResult on the provided inventory result when you are done with it.
// Grant a specific one-time promotional item to the current user.
int32 SteamServer::addPromoItem(uint32 item) {
int32 new_inventory_handle = 0;
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, new_inventory_handle, "[STEAM SERVER] Inventory class not found when calling: addPromoItem");
if (SteamInventory()->AddPromoItem(&new_inventory_handle, item)) {
inventory_handle = new_inventory_handle;
}
return new_inventory_handle;
}
// Grant a specific one-time promotional items to the current user.
int32 SteamServer::addPromoItems(PackedInt64Array items) {
int32 new_inventory_handle = 0;
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, new_inventory_handle, "[STEAM SERVER] Inventory class not found when calling: addPromoItems");
int count = items.size();
SteamItemDef_t *new_items = new SteamItemDef_t[items.size()];
for(int i = 0; i < count; i++) {
new_items[i] = items[i];
}
if (SteamInventory()->AddPromoItems(&new_inventory_handle, new_items, count)) {
inventory_handle = new_inventory_handle;
}
delete[] new_items;
return new_inventory_handle;
}
// Checks whether an inventory result handle belongs to the specified Steam ID.
bool SteamServer::checkResultSteamID(uint64_t steam_id_expected, int32 this_inventory_handle) {
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, false, "[STEAM SERVER] Inventory class not found when calling: checkResultSteamID");
CSteamID steam_id = (uint64)steam_id_expected;
if (this_inventory_handle == 0) {
this_inventory_handle = inventory_handle;
}
return SteamInventory()->CheckResultSteamID((SteamInventoryResult_t)this_inventory_handle, steam_id);
}
// Consumes items from a user's inventory. If the quantity of the given item goes to zero, it is permanently removed.
int32 SteamServer::consumeItem(uint64_t item_consume, uint32 quantity) {
int32 new_inventory_handle = 0;
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, new_inventory_handle, "[STEAM SERVER] Inventory class not found when calling: consumeItem");
if (SteamInventory()->ConsumeItem(&new_inventory_handle, (SteamItemInstanceID_t)item_consume, quantity)) {
inventory_handle = new_inventory_handle;
}
return new_inventory_handle;
}
// Deserializes a result set and verifies the signature bytes.
int32 SteamServer::deserializeResult(PackedByteArray buffer) {
int32 new_inventory_handle = 0;
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, 0, "[STEAM SERVER] Inventory class not found when calling: deserializeResult");
if (SteamInventory()->DeserializeResult(&new_inventory_handle, &buffer, buffer.size(), false)) {
inventory_handle = new_inventory_handle;
}
return new_inventory_handle;
}
// Destroys a result handle and frees all associated memory.
void SteamServer::destroyResult(int this_inventory_handle) {
ERR_FAIL_COND_MSG(SteamInventory() == NULL, "[STEAM SERVER] Inventory class not found when calling: destroyResult");
if (this_inventory_handle == 0) {
this_inventory_handle = inventory_handle;
}
SteamInventory()->DestroyResult((SteamInventoryResult_t)this_inventory_handle);
}
//! Grant one item in exchange for a set of other items.
int32 SteamServer::exchangeItems(const PackedInt64Array output_items, const PackedInt32Array output_quantity, const PackedInt64Array input_items, const PackedInt32Array input_quantity) {
int32 new_inventory_handle = 0;
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, new_inventory_handle, "[STEAM SERVER] Inventory class not found when calling: exchangeItems");
uint32 total_output = output_items.size();
SteamItemDef_t *generated_items = new SteamItemDef_t[total_output];
for (uint32 i = 0; i < total_output; i++) {
generated_items[i] = output_items[i];
}
uint32_t *quantity_out = (uint32*) output_quantity.ptr();
uint32_t *quantity_in = (uint32*) input_quantity.ptr();
uint32 array_size = input_items.size();
SteamItemInstanceID_t *input_item_ids = new SteamItemInstanceID_t[array_size];
for (uint32 i = 0; i < array_size; i++) {
input_item_ids[i] = input_items[i];
}
const SteamItemInstanceID_t *these_item_ids = input_item_ids;
if (SteamInventory()->ExchangeItems(&new_inventory_handle, generated_items, quantity_out, total_output, these_item_ids, quantity_in, array_size)) {
inventory_handle = new_inventory_handle;
}
delete[] generated_items;
delete[] input_item_ids;
return new_inventory_handle;
}
// Grants specific items to the current user, for developers only.
int32 SteamServer::generateItems(const PackedInt64Array items, const PackedInt32Array quantity) {
int32 new_inventory_handle = 0;
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, new_inventory_handle, "[STEAM SERVER] Inventory class not found when calling: generateItems");
uint32 total_quantity = items.size();
SteamItemDef_t *generated_items = new SteamItemDef_t[total_quantity];
for (uint32 i = 0; i < total_quantity; i++) {
generated_items[i] = items[i];
}
uint32_t *this_quantity = (uint32*) quantity.ptr();
if (SteamInventory()->GenerateItems(&new_inventory_handle, generated_items, this_quantity, items.size())) {
inventory_handle = new_inventory_handle;
}
delete[] generated_items;
return new_inventory_handle;
}
// Start retrieving all items in the current users inventory.
int32 SteamServer::getAllItems() {
int32 new_inventory_handle = 0;
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, new_inventory_handle, "[STEAM SERVER] Inventory class not found when calling: getAllItems");
if (SteamInventory()->GetAllItems(&new_inventory_handle)) {
inventory_handle = new_inventory_handle;
}
return new_inventory_handle;
}
// Gets a string property from the specified item definition. Gets a property value for a specific item definition.
String SteamServer::getItemDefinitionProperty(uint32 definition, const String &name) {
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, "", "[STEAM SERVER] Inventory class not found when calling: getItemDefinitionProperty");
char buffer[STEAM_BUFFER_SIZE];
uint32 buffer_size = std::size(buffer);
SteamInventory()->GetItemDefinitionProperty(definition, name.utf8().get_data(), buffer, &buffer_size);
String property = String::utf8(buffer, buffer_size);
return property;
}
// After a successful call to RequestPrices, you can call this method to get the pricing for a specific item definition.
Dictionary SteamServer::getItemPrice(uint32 definition) {
Dictionary prices;
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, prices, "[STEAM SERVER] Inventory class not found when calling: getItemPrice");
uint64 price = 0;
uint64 base_price = 0;
SteamInventory()->GetItemPrice(definition, &price, &base_price);
prices["price"] = (uint64_t)price;
prices["base_price"] = (uint64_t)base_price;
return prices;
}
// Gets the state of a subset of the current user's inventory.
int32 SteamServer::getItemsByID(const PackedInt64Array id_array) {
int32 new_inventory_handle = 0;
ERR_FAIL_COND_V_MSG(SteamInventory() == NULL, new_inventory_handle, "[STEAM SERVER] Inventory class not found when calling: getItemsByID");
uint32 array_size = id_array.size();
SteamItemInstanceID_t *item_ids = new SteamItemInstanceID_t[array_size];
for (uint32 i = 0; i < array_size; i++) {
item_ids[i] = id_array[i];
}
const SteamItemInstanceID_t *these_item_ids = item_ids;