Skip to content

Commit 715f873

Browse files
authored
Initial upload
1 parent bf9ddb5 commit 715f873

37 files changed

+1974
-0
lines changed
+360
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,360 @@
1+
extends Node
2+
class_name PraxisAPICall
3+
4+
#This function works in a single call, but the UI tends not to update while this is running, so we
5+
#dont really want to use this one too much. In most cases you will want to use PraxisEndpoints instead
6+
#of this class, but it remains here for now as an alternative.
7+
8+
9+
# Based on the HTTPClient demo in the official docs. Used to make getting data a single function call.
10+
# This simple class can do HTTP requests; it will not block, but it needs to be polled.
11+
12+
#NOTE: this works, but it seems to cause the app to not process anything else while it's running in a scene.
13+
14+
#For a game with a custom plugin, it'll basically want a node that creates an instance of this node,
15+
#and hits call_url() with the correct parameters, then process the result accordingly and return that.
16+
var http
17+
var lastResponseCode #can be checked if this returns null for more info
18+
var lastError #can be checked if this returns null for more info.
19+
20+
static var _isReauthing = false
21+
22+
signal result(data: Array)
23+
24+
func _init():
25+
var err = 0
26+
http = HTTPClient.new() # Create the Client.
27+
28+
var split = PraxisMapper.serverURL.split(":")
29+
if (split.size() == 3): #http:\\url:port
30+
err = http.connect_to_host(split[0] + ":" + split[1], int(split[2])) # Connect to host/port.
31+
elif (split.size() == 2 and !split[0].begins_with("http")): #url:port
32+
err = http.connect_to_host(split[0], int(split[1])) # Connect to host/port.
33+
else: # url
34+
err = http.connect_to_host(PraxisMapper.serverURL)
35+
36+
assert(err == OK) # Make sure connection is OK.
37+
38+
# Wait until resolved and connected.
39+
while http.get_status() == HTTPClient.STATUS_CONNECTING or http.get_status() == HTTPClient.STATUS_RESOLVING:
40+
http.poll()
41+
if not OS.has_feature("web"):
42+
OS.delay_msec(25)
43+
else:
44+
await get_tree().process_frame
45+
46+
print(http.get_status())
47+
assert(http.get_status() == HTTPClient.STATUS_CONNECTED) # Check if the connection was made successfully.
48+
49+
func call_url(endpoint, method = HTTPClient.METHOD_GET, body = ''):
50+
lastError = ''
51+
lastResponseCode = 0
52+
# Some headers
53+
var headers = [
54+
"AuthKey: " + PraxisMapper.authKey,
55+
"PraxisAuthKey: " + PraxisMapper.headerKey,
56+
"User-Agent: Pirulo/1.0 (Godot)",
57+
"Accept: */*"
58+
]
59+
60+
if !endpoint.begins_with("/"):
61+
endpoint = "/" + endpoint
62+
63+
var err = http.request(method, endpoint, headers, body) # Request a page from the site (this one was chunked..)
64+
if (err != OK):
65+
lastError = error_string(err)
66+
return null
67+
68+
while http.get_status() == HTTPClient.STATUS_REQUESTING:
69+
# Keep polling for as long as the request is being processed.
70+
http.poll()
71+
if OS.has_feature("web"):
72+
# Synchronous HTTP requests are not supported on the web,
73+
# so wait for the next main loop iteration.
74+
await get_tree().process_frame
75+
else:
76+
OS.delay_msec(25)
77+
78+
assert(http.get_status() == HTTPClient.STATUS_BODY or http.get_status() == HTTPClient.STATUS_CONNECTED) # Make sure request finished well.
79+
if (http.get_status() != HTTPClient.STATUS_BODY and http.get_status() != HTTPClient.STATUS_CONNECTED):
80+
lastError = "Request Failed: " + http.get_status()
81+
return
82+
83+
var statusCode = http.get_response_code()
84+
lastResponseCode = statusCode
85+
if (statusCode == 419):
86+
#reauth. TODO: better locking.
87+
if (_isReauthing == true):
88+
while _isReauthing == true:
89+
if OS.has_feature("web"):
90+
await get_tree().process_frame
91+
else:
92+
OS.delay_msec(25)
93+
else:
94+
_isReauthing = true
95+
await self.Login(PraxisMapper.username, PraxisMapper.password)
96+
_isReauthing = false
97+
return await call_url(endpoint, method, body)
98+
elif(statusCode != 200 and statusCode != 204):
99+
lastError = str(statusCode)
100+
return "Error: " + str(statusCode)
101+
102+
if http.has_response():
103+
# Getting the HTTP Body
104+
var rb = PackedByteArray() # Array that will hold the data.
105+
while http.get_status() == HTTPClient.STATUS_BODY:
106+
# While there is body left to be read
107+
http.poll()
108+
# Get a chunk.
109+
var chunk = http.read_response_body_chunk()
110+
if chunk.size() == 0:
111+
if not OS.has_feature("web"):
112+
# Got nothing, wait for buffers to fill a bit.
113+
OS.delay_usec(10)
114+
else:
115+
await get_tree().process_frame
116+
else:
117+
rb = rb + chunk # Append to read buffer.
118+
# Done!
119+
120+
result.emit(rb) # an alternate way to get this info, but may not work if this node is shared.
121+
return rb #Let the caller decode this data the way they expect to have it.
122+
123+
return true
124+
125+
#Pre-made calls for stock endpoints
126+
#/Server controller APIs
127+
func GetServerBounds(): # Server's covered area in S|W|N|E order/format
128+
var data = await call_url("/Server/Bounds")
129+
return data.get_string_from_utf8()
130+
131+
func ServerTest(): # always returns 'OK'
132+
var data = await call_url("/Server/Test")
133+
return data.get_string_from_utf8()
134+
135+
func MOTD(): #Message of the Day
136+
var data = await call_url("/Server/MOTD")
137+
return data.get_string_from_utf8()
138+
139+
func RandomPoint(): # A random point somewhere inside server bounds
140+
var data = await call_url("/Server/RandomPoint")
141+
return data.get_string_from_utf8()
142+
143+
func GDPRExport(): #All data available on the user as a string.
144+
var data = await call_url("/Server/GdprExport")
145+
return data.get_string_from_utf8()
146+
147+
func DeleteAccount():
148+
var data = await call_url("/Server/Account", HTTPClient.METHOD_DELETE)
149+
return data.get_string_from_utf8()
150+
151+
func Login(account, password):
152+
var data = await call_url("/Server/Login/" + account + "/" + password)
153+
return data.get_string_from_utf8()
154+
155+
func CreateAccount(account,password):
156+
var data = await call_url("/Server/CreateAccount/" + account + "/" + password, HTTPClient.METHOD_PUT)
157+
return data.get_string_from_utf8() #true or false
158+
159+
func ChangePassword(account, oldPassword, newPassword):
160+
var data = await call_url("/Server/ChangePassword/" + account + "/" + oldPassword + "/" + newPassword, HTTPClient.METHOD_PUT)
161+
return data.get_string_from_utf8()
162+
163+
#Data endpoint API calls. For games that don't have a dedicated plugin or early development testing.
164+
#Sets return true/false, Gets usually return JSON data.
165+
func SetAreaValue(plusCode, key, value, expiresIn = null):
166+
var url = "/Data/Area/" + plusCode + "/" + key
167+
if (expiresIn != null):
168+
url += "/noval/" + str(expiresIn)
169+
170+
var data = await call_url(url, HTTPClient.METHOD_PUT, value)
171+
return data.get_string_from_utf8()
172+
173+
func GetAreaValue(plusCode, key):
174+
var data = await call_url("/Data/Area/" + plusCode + "/" + key)
175+
return data.get_string_from_utf8()
176+
177+
#TODO: Server doesn't currently allow for body values with expiration on Player.
178+
func SetPlayerValue(account, key, value, expiresIn = null):
179+
var url = "/Data/Player/" + account + "/" + key
180+
if (expiresIn != null):
181+
url += "/" + value + "/" + str(expiresIn)
182+
183+
var data = await call_url(url, HTTPClient.METHOD_PUT, value)
184+
return data.get_string_from_utf8()
185+
186+
func GetPlayerValue(account, key):
187+
var data = await call_url("/Data/Player/" + account + "/" + key)
188+
return data.get_string_from_utf8()
189+
190+
#TODO: Server doesn't currently allow for body values with expiration on Place
191+
func SetPlaceValue(place, key, value, expiresIn = null):
192+
var url = "/Data/Place/" + place + "/" + key
193+
if (expiresIn != null):
194+
url += "/" + value + "/" + str(expiresIn)
195+
196+
var data = await call_url(url, HTTPClient.METHOD_PUT, value)
197+
return data.get_string_from_utf8()
198+
199+
func GetPlaceValue(place, key):
200+
var data = await call_url("/Data/Place/" + place + "/" + key)
201+
return data.get_string_from_utf8()
202+
203+
func GetGlobalValue(key):
204+
var data = await call_url("/Data/Global/" + key)
205+
return data.get_string_from_utf8()
206+
207+
func SetGlobalValue(key, value):
208+
var data = await call_url("/Data/Global/" + key, HTTPClient.METHOD_PUT, value)
209+
return data.get_string_from_utf8()
210+
211+
func DeleteGlobalValue(key):
212+
var data = await call_url("/Data/Global/" + key, HTTPClient.METHOD_DELETE)
213+
return data.get_string_from_utf8()
214+
215+
func GetAllPlayerData(player):
216+
var data = await call_url("/Data/Player/All/" + player)
217+
return data.get_string_from_utf8()
218+
219+
func GetAllAreaData(player):
220+
var data = await call_url("/Data/Area/All/" + player)
221+
return data.get_string_from_utf8()
222+
223+
func GetAllPlaceData(place):
224+
var data = await call_url("/Data/Place/All/" + place)
225+
return data.get_string_from_utf8()
226+
227+
#SecureData endpoint API calls.
228+
func SetSecureAreaValue(plusCode, key, value, password, expiresIn = null):
229+
#TODO: server doesnt support value in body and expiration together.
230+
var url = "/SecureData/Area/" + plusCode + "/" + key
231+
if (expiresIn != null):
232+
url += "/" + value + "/" + password + "/"+ str(expiresIn)
233+
else:
234+
url += "/" + password
235+
236+
var data = await call_url(url, HTTPClient.METHOD_PUT, value)
237+
return data.get_string_from_utf8()
238+
239+
func GetSecureAreaValue(plusCode, key, password):
240+
var data = await call_url("/SecureData/Area/" + plusCode + "/" + key + "/" + password)
241+
return data.get_string_from_utf8()
242+
243+
#TODO: Server doesn't currently allow for body values with expiration on Player.
244+
func SetSecurePlayerValue(account, key, value, password, expiresIn = null):
245+
var url = "/SecureData/Player/" + account + "/" + key
246+
if (expiresIn != null):
247+
url += "/" + value + "/" + password + "/"+ str(expiresIn)
248+
else:
249+
url += "/" + password
250+
251+
var data = await call_url(url, HTTPClient.METHOD_PUT, value)
252+
return data.get_string_from_utf8()
253+
254+
func GetSecurePlayerValue(account, key, password):
255+
var data = await call_url("/SecureData/Player/" + account + "/" + key + "/" + password)
256+
return data.get_string_from_utf8()
257+
258+
#TODO: Server doesn't currently allow for body values with expiration on Place
259+
func SetSecurePlaceValue(place, key, value, password, expiresIn = null):
260+
var url = "/SecureData/Place/" + place + "/" + key
261+
if (expiresIn != null):
262+
url += "/" + value + "/" + password + "/"+ str(expiresIn)
263+
else:
264+
url += "/" + password
265+
266+
var data = await call_url(url, HTTPClient.METHOD_PUT, value)
267+
return data.get_string_from_utf8()
268+
269+
func GetSecurePlaceValue(place, key, password):
270+
var data = await call_url("/SecureData/Place/" + place + "/" + key)
271+
return data.get_string_from_utf8()
272+
273+
#These don't return a value.
274+
func IncrementSecurePlaceValue(place, key, changeAmount, password, expiresIn = null):
275+
var url = "/SecureData/Place/Increment/" + place + "/" + key + "/" + password + "/" + changeAmount
276+
if (expiresIn != null):
277+
url += "/"+ str(expiresIn)
278+
279+
var data = await call_url(url, HTTPClient.METHOD_PUT)
280+
return data.get_string_from_utf8()
281+
282+
func IncrementSecurePlayerValue(account, key, changeAmount, password, expiresIn = null):
283+
var url = "/SecureData/Player/Increment/" + account + "/" + key + "/" + password + "/" + changeAmount
284+
if (expiresIn != null):
285+
url += "/"+ str(expiresIn)
286+
287+
var data = await call_url(url, HTTPClient.METHOD_PUT)
288+
return data.get_string_from_utf8()
289+
290+
func IncrementSecureAreaValue(plusCode, key, changeAmount, password, expiresIn = null):
291+
var url = "/SecureData/Area/Increment/" + plusCode+ "/" + key + "/" + password + "/" + changeAmount
292+
if (expiresIn != null):
293+
url += "/"+ str(expiresIn)
294+
295+
var data = await call_url(url, HTTPClient.METHOD_PUT)
296+
return data.get_string_from_utf8()
297+
298+
#MapTile endpoints API calls. Returns a PNG in byte array format.
299+
func DrawMapTile(plusCode, styleSet, onlyLayer): #Normal map tiles. styleSet and onlyLayer are optional.
300+
var url = '/MapTile/Area/' + plusCode
301+
if (styleSet != null):
302+
url += "/" + styleSet
303+
if (onlyLayer != null):
304+
url += "/" + onlyLayer
305+
306+
var data = await call_url(url)
307+
return data
308+
309+
func DrawMapTileAreaData(plusCode, styleSet): #loads drawable area data inside the given area.
310+
var url = '/MapTile/AreaData/' + plusCode
311+
if (styleSet != null):
312+
url += "/" + styleSet
313+
314+
var data = await call_url(url)
315+
return data
316+
317+
func ExpireTiles(place, styleSet): #expires all map tiles in styleSet that contain place.
318+
var url = "/MapTile/Expire/" + place + "/" + styleSet
319+
await call_url(url)
320+
321+
func GetTileGenerationID(plusCode, styleSet): #Gets the current generation ID (creation count) for a tile. -1 is "expired"
322+
var url = "/MapTile/Generatiion/" + plusCode + "/" + styleSet
323+
await call_url(url)
324+
325+
#Demo endpoint API calls, so this can server immediately as a test client.
326+
327+
func DemoSplatterEnter(plusCode): #Grants the player 1 splat point when walking into a Cell10 the first time in 24 hours
328+
var url = "/Splatter/Enter/" + plusCode
329+
var data = await call_url(url)
330+
return data.get_string_from_utf8() #count of current splat points
331+
332+
func DemoSplatterSplat(plusCode, radius): #Spend points to make a splat of radius (integer) size if player has enough points.
333+
var url = "/Splatter/Splat/" + plusCode + "/" + radius
334+
await call_url(url)
335+
#When done, update 'splatter' maptiles.
336+
337+
func DemoSplatterTest(plusCode8): #Creates random splats all over the given Cell8. Return the image of the given Cell8 after.
338+
var url = "/Splatter/Test/" + plusCode8
339+
var data = await call_url(url)
340+
return data
341+
#When done, update 'splatter' maptiles.
342+
343+
func DemoUnroutineEnter(plusCode): #if at a Place, add it to the Visited list.
344+
var url = "/Unroutine/Enter/" + plusCode
345+
await call_url(url)
346+
347+
func DemoUnroutinePickTarget(plusCode):
348+
var url = "/Unroutine/Target/" + plusCode
349+
var data = await call_url(url, HTTPClient.METHOD_PUT)
350+
return data.get_string_from_utf8() #target info JSON
351+
352+
func DemoUnroutineGetCurrentTarget():
353+
var url = "/Unroutine/Target"
354+
var data = await call_url(url)
355+
return data.get_string_from_utf8() #target info JSON
356+
357+
func DemoUnroutineGetAllVisited():
358+
var url = "/Unroutine/Visited"
359+
var data = await call_url(url)
360+
return data.get_string_from_utf8() #all places JSON
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[gd_scene load_steps=2 format=3 uid="uid://ddl6jqncfeef4"]
2+
3+
[ext_resource type="Script" path="res://PraxisMapper/APICalls/PraxisAPICall.gd" id="1_duea4"]
4+
5+
[node name="PraxisAPICall" type="Node"]
6+
process_thread_group = 2
7+
process_thread_group_order = 0
8+
process_thread_messages = 0
9+
script = ExtResource("1_duea4")

0 commit comments

Comments
 (0)