OverviewFilesCommitsIssuesDocsReleasesPeers

hypergodot commits / 43e7e90

Restructuring
43e7e90b6ab2e57090297a8b5c71453dbf5b8c82
by mauve <ranger@mauve.moe> · 2022-01-10T19:53:47.000Z

Changed files (17) +275 -380

README.md +3 -1
……@@ -28,11 +28,13 @@ A Godot plugin and example project for loading assets from the [hypercore-protoc
2828 - [x] Refactor chat system to be more general purpose (not just texts)
2929 - [x] Basic demo moving blobs around on a map
3030 - [x] Place usernames in a hyperdrive's json file along with an image for your blob
31 - [ ] Create custom maps from an image and a JSON file
31 - [x] Create custom maps from an image and a JSON file
3232 - [ ] Auto-discover which maps are active
3333- [ ] Enable code to work in Godot Web in Agregore
3434 - [ ] Use new [JavaScriptObject](https://godotengine.org/article/godot-web-progress-report-9) API from Godot 4
3535- [ ] Enable code to work in Godot Web in regular browsers
36- [ ] Update to latest hypercore protocol stuff
37- [ ] Add multi-writer for hyperdrives
3638- [ ] Load gltf scene from hyper
3739- [ ] Load VRM avatar from hyper (social multiplayer) [VRM stuff](https://github.com/V-Sekai/godot-vrm/blob/godot3/addons/vrm/import_vrm.gd)
3840- [ ] Folder sync (From `hyper://` to fs, from fs to `hyper://`)
project.godot +6 -0
……@@ -39,6 +39,11 @@ _global_script_classes=[ {
3939"language": "GDScript",
4040"path": "res://src/HyperRequest/HyperUploader.gd"
4141}, {
42"base": "HyperGossip",
43"class": "ListGossip",
44"language": "GDScript",
45"path": "res://src/multiplayer/ListGossip.gd"
46}, {
4247"base": "Reference",
4348"class": "WAT",
4449"language": "GDScript",
……@@ -56,6 +61,7 @@ _global_script_class_icons={
5661"HyperGossip": "",
5762"HyperRequest": "",
5863"HyperUploader": "",
64"ListGossip": "",
5965"WAT": "",
6066"WATTest": ""
6167}
src/MultiplayerDemo/FlyBalls.tscn +2 -2
……@@ -5,7 +5,7 @@
55[ext_resource path="res://src/MultiplayerDemo/FlyBalls.gd" type="Script" id=3]
66[ext_resource path="res://src/HyperGateway/HyperGateway.gd" type="Script" id=4]
77[ext_resource path="res://src/multiplayer/HyperGossip.gd" type="Script" id=5]
8[ext_resource path="res://src/MultiplayerDemo/LevelInfo.tscn" type="PackedScene" id=6]
8[ext_resource path="res://src/multiplayer/InfoLoader.tscn" type="PackedScene" id=6]
99[ext_resource path="res://src/MultiplayerDemo/background.png" type="Texture" id=7]
1010
1111[node name="FlyBalls" type="Node2D"]
……@@ -26,13 +26,13 @@ script = ExtResource( 2 )
2626
2727[node name="HyperGossip" type="Node" parent="."]
2828script = ExtResource( 5 )
29extension_name = "flyballs-v1"
3029
3130[node name="HyperGateway" type="Node" parent="."]
3231script = ExtResource( 4 )
3332autoStart = false
3433
3534[node name="LevelInfo" parent="." instance=ExtResource( 6 )]
35profile_file = "level.json"
3636autoload_image = true
3737
3838[connection signal="moved" from="Player" to="." method="_on_Player_moved"]
src/MultiplayerDemo/LevelInfo.gd +0 -143
……@@ -1,143 +0,0 @@
1extends Node
2
3var URLParser = preload("res://src/utils/URLParser.gd")
4var parser = URLParser.new()
5
6signal info(title, image)
7signal no_info()
8signal image(path)
9signal updated()
10signal resolved(url)
11signal error(err)
12
13export var url = 'hyper://multiplayer-level/'
14export var cache_folder: String = 'user://hyper-file-cache/'
15export var level_file: String = 'level.json'
16
17export var autoload = false
18export var autoload_image = false
19
20const DEFAULT_TITLE = 'New Level'
21
22var info_cache = null
23var has_loaded = false
24var picture_path = ''
25
26func _ready():
27 var dir = Directory.new()
28 var err = dir.make_dir_recursive(cache_folder)
29 if err != OK:
30 printerr("Unable to create cache directory ", err)
31
32 print("Level info setup")
33 if autoload:
34 load_info()
35
36func get_title():
37 if info_cache == null: return DEFAULT_TITLE
38 if !info_cache.has('title'): return DEFAULT_TITLE
39 return info_cache.title
40
41func set_title(title):
42 update_info({
43 "title": title
44 })
45
46func update_info(updates):
47 var data = {}
48
49 if info_cache != null:
50 for key in info_cache.keys():
51 data[key] = info_cache[key]
52
53 for key in updates.keys():
54 data[key] = info_cache[key]
55
56 var json = JSON.print(data)
57 var info_url = url + level_file
58
59 $updateInfoRequest.request(info_url, [], true, HTTPClient.METHOD_PUT, json)
60
61func load_info():
62 var info_url = url + level_file
63 $loadInfoRequest.request(info_url)
64
65func resolve_url():
66 var url_record = url + '.well-known/hyper'
67 $resolveURLRequest.request(url_record)
68
69func download_image(url: String):
70 print('Loading image: ', url)
71 var file_name = url.get_file()
72 var key = parser.parse(url).host
73 # Save the picture with the profile key prefixed to it
74 picture_path = cache_folder + key + '-' + file_name
75 $loadImageRequest.download_file = picture_path
76 $loadImageRequest.request(url)
77
78func upload_image(path: String):
79 var picture_name = path.get_file()
80 var picture_url = url + picture_name
81
82 $uploader.upload_file(picture_url, path)
83
84func _on_loadInfoRequest_request_completed(_result, response_code, _headers, body):
85 print("Loaded info", _result, " ", response_code)
86 if response_code != 200:
87 printerr('Cannot load existing level info: ', response_code)
88 emit_signal("no_info")
89 return
90
91 var parsed = JSON.parse(body.get_string_from_utf8())
92 if parsed.error != OK:
93 printerr(parsed.error_string)
94 emit_signal("no_info")
95 return
96
97 info_cache = parsed.result
98
99 var title = info_cache.title
100 var image = info_cache.image
101
102 emit_signal("info", title, image)
103
104 if image != null and autoload_image:
105 download_image(image)
106
107func _on_uploader_uploaded(resolved_url, response_code):
108 if response_code != 200:
109 printerr('Unable to upload file ')
110 return
111
112 if !url || (url.length() == 0):
113 printerr("Unable to load Link header for image.")
114 return
115
116 update_info({
117 "image": resolved_url
118 })
119
120 download_image(resolved_url)
121
122func _on_loadImageRequest_request_completed(result, response_code, _headers, body):
123 if result != OK or response_code != 200:
124 printerr('Unable to load image: ', result, ": ", body.get_string_from_utf8())
125 return
126
127 print(result, ' Image got downloaded: ', picture_path)
128
129 emit_signal('image', picture_path)
130
131func _on_updateInfoRequest_request_completed(_result, _response_code, _headers, _body):
132 emit_signal("updated")
133
134func _on_resolveURLRequest_request_completed(result, response_code, _headers, body: PoolByteArray):
135 if result != OK or response_code != 200:
136 printerr('Unable to load final profile URL')
137 return
138
139 var lines = body.get_string_from_utf8()
140 var url = lines.split('\n')[0]
141 if !url.ends_with('/'):
142 url += '/'
143 emit_signal('resolved', url)
src/MultiplayerDemo/LevelInfo.tscn +0 -29
……@@ -1,29 +0,0 @@
1[gd_scene load_steps=4 format=2]
2
3[ext_resource path="res://src/MultiplayerDemo/LevelInfo.gd" type="Script" id=1]
4[ext_resource path="res://src/HyperRequest/HyperRequest.gd" type="Script" id=2]
5[ext_resource path="res://src/HyperRequest/HyperUploader.gd" type="Script" id=3]
6
7[node name="LevelInfo" type="Node"]
8script = ExtResource( 1 )
9
10[node name="loadInfoRequest" type="HTTPRequest" parent="."]
11script = ExtResource( 2 )
12
13[node name="loadImageRequest" type="HTTPRequest" parent="."]
14script = ExtResource( 2 )
15
16[node name="updateInfoRequest" type="HTTPRequest" parent="."]
17script = ExtResource( 2 )
18
19[node name="resolveURLRequest" type="HTTPRequest" parent="."]
20script = ExtResource( 2 )
21
22[node name="uploader" type="Node" parent="."]
23script = ExtResource( 3 )
24
25[connection signal="request_completed" from="loadInfoRequest" to="." method="_on_loadInfoRequest_request_completed"]
26[connection signal="request_completed" from="loadImageRequest" to="." method="_on_loadImageRequest_request_completed"]
27[connection signal="request_completed" from="updateInfoRequest" to="." method="_on_updateInfoRequest_request_completed"]
28[connection signal="request_completed" from="resolveURLRequest" to="." method="_on_resolveURLRequest_request_completed"]
29[connection signal="uploaded" from="uploader" to="." method="_on_uploader_uploaded"]
src/MultiplayerDemo/LoadLevel.gd +8 -5
……@@ -46,6 +46,9 @@ func _on_HyperGateway_started_gateway(_pid):
4646func _on_StartButton_pressed():
4747 print("Starting next step")
4848 show_loader()
49 $LevelInfo.update({
50 "title": get_title()
51 })
4952 $LevelInfo.resolve_url()
5053
5154func _on_LevelInfo_error(err):
……@@ -63,13 +66,13 @@ func _on_LevelInfo_image(path):
6366
6467 $Form/ImageChooser.icon = texture
6568
66func _on_LevelInfo_info(title: String, image: String):
67 print("Loaded level info:", {"title": title, "image": image})
69func _on_LevelInfo_info(info):
70 print("Loaded level info:", info)
6871 $Form/StartButton.disabled = false
69 $Form/TitleInput.text = title
72 $Form/TitleInput.text = info.title
7073
71 if image != null && image.length() != 0:
72 load_image(image)
74 if info.has('image') && info.image.length() != 0:
75 load_image(info.image)
7376 else: hide_loader()
7477
7578func _on_LevelInfo_updated():
src/MultiplayerDemo/LoadLevel.tscn +7 -2
……@@ -2,7 +2,7 @@
22
33[ext_resource path="res://src/MultiplayerDemo/LoadLevel.gd" type="Script" id=1]
44[ext_resource path="res://src/HyperGateway/HyperGateway.gd" type="Script" id=2]
5[ext_resource path="res://src/MultiplayerDemo/LevelInfo.tscn" type="PackedScene" id=3]
5[ext_resource path="res://src/multiplayer/InfoLoader.tscn" type="PackedScene" id=4]
66
77[node name="LoadLevel" type="VBoxContainer"]
88anchor_right = 1.0
……@@ -79,7 +79,12 @@ access = 2
7979current_dir = "/home/mauve/programming/godot/hypergodot"
8080current_path = "/home/mauve/programming/godot/hypergodot/"
8181
82[node name="LevelInfo" parent="." instance=ExtResource( 3 )]
82[node name="LevelInfo" parent="." instance=ExtResource( 4 )]
83url = "hyper://multiplayer-level/"
84profile_file = "level.json"
85defaults = {
86"title": "New Level"
87}
8388
8489[connection signal="pressed" from="Form/ImageChooser" to="." method="_on_ImageChooser_pressed"]
8590[connection signal="pressed" from="Form/StartButton" to="." method="_on_StartButton_pressed"]
src/MultiplayerDemo/LoadProfile.gd +9 -6
……@@ -14,7 +14,7 @@ func _ready():
1414func load_profile():
1515 print("Initial profile load")
1616 $PlayerProfile.url = profile_url
17 $PlayerProfile.load_profile()
17 $PlayerProfile.load_info()
1818
1919func hide_loader():
2020 $Loader.hide()
……@@ -47,6 +47,9 @@ func _on_HyperGateway_started_gateway(_pid):
4747func _on_StartButton_pressed():
4848 print("Starting next step")
4949 show_loader()
50 $PlayerProfile.update_info({
51 "username": get_username()
52 })
5053 $PlayerProfile.resolve_url()
5154
5255func _on_PlayerProfile_error(err):
……@@ -64,13 +67,13 @@ func _on_PlayerProfile_image(path):
6467
6568 $Form/ImageChooser.icon = texture
6669
67func _on_PlayerProfile_info(username: String, image: String):
68 print("Loaded player profile:", {"username": username, "image": image})
70func _on_PlayerProfile_info(info):
71 print("Loaded player profile:", info)
6972 $Form/StartButton.disabled = false
70 $Form/UsernameInput.text = username
73 $Form/UsernameInput.text = info.username
7174
72 if image != null && image.length() != 0:
73 load_image(image)
75 if info.has('image') && info.image.length() != 0:
76 load_image(info.image)
7477 else: hide_loader()
7578
7679func _on_PlayerProfile_updated():
src/MultiplayerDemo/LoadProfile.tscn +5 -4
……@@ -2,7 +2,7 @@
22
33[ext_resource path="res://src/MultiplayerDemo/LoadProfile.gd" type="Script" id=1]
44[ext_resource path="res://src/HyperGateway/HyperGateway.gd" type="Script" id=2]
5[ext_resource path="res://src/MultiplayerDemo/PlayerProfile.tscn" type="PackedScene" id=3]
5[ext_resource path="res://src/multiplayer/InfoLoader.tscn" type="PackedScene" id=3]
66
77[node name="LoadProfile" type="VBoxContainer"]
88anchor_right = 1.0
……@@ -67,6 +67,10 @@ script = ExtResource( 2 )
6767autoStart = false
6868
6969[node name="PlayerProfile" parent="." instance=ExtResource( 3 )]
70url = "hyper://flyballs-profile/"
71defaults = {
72"username": "anonymous"
73}
7074
7175[node name="FileDialog" type="FileDialog" parent="."]
7276margin_top = 536.0
……@@ -87,7 +91,4 @@ current_path = "/home/mauve/programming/godot/hypergodot/"
8791[connection signal="error" from="PlayerProfile" to="." method="_on_PlayerProfile_error"]
8892[connection signal="image" from="PlayerProfile" to="." method="_on_PlayerProfile_image"]
8993[connection signal="info" from="PlayerProfile" to="." method="_on_PlayerProfile_info"]
90[connection signal="no_info" from="PlayerProfile" to="." method="_on_PlayerProfile_no_info"]
91[connection signal="resolved" from="PlayerProfile" to="." method="_on_PlayerProfile_resolved"]
92[connection signal="updated" from="PlayerProfile" to="." method="_on_PlayerProfile_updated"]
9394[connection signal="file_selected" from="FileDialog" to="." method="_on_FileDialog_file_selected"]
src/MultiplayerDemo/MultiplayerDemo.gd +1 -1
……@@ -10,5 +10,5 @@ func _on_LoadProfile_profile_ready(url):
1010 game.spawn_gateway = false
1111 add_child(game)
1212
13func _on_HyperGateway_started_gateway(pid):
13func _on_HyperGateway_started_gateway(_pid):
1414 $LoadProfile.load_profile()
src/MultiplayerDemo/PlayerProfile.gd +0 -144
……@@ -1,144 +0,0 @@
1extends Node
2
3var URLParser = preload("res://src/utils/URLParser.gd")
4var parser = URLParser.new()
5
6signal info(username, image)
7signal no_info()
8signal image(path)
9signal updated()
10signal resolved(url)
11signal error(err)
12
13export var url = 'hyper://blog.mauve.moe/'
14export var cache_folder: String = 'user://hyper-file-cache/'
15export var profile_file: String = 'profile.json'
16
17export var autoload = false
18export var autoload_image = false
19
20const DEFAULT_USERNAME = 'Anonymous'
21
22var info_cache = null
23var has_loaded = false
24var picture_path = ''
25
26func _ready():
27 var dir = Directory.new()
28 var err = dir.make_dir_recursive(cache_folder)
29 if err != OK:
30 printerr("Unable to create cache directory ", err)
31
32 print("Profile setup")
33 if autoload:
34 load_profile()
35
36func get_username():
37 if info_cache == null: return DEFAULT_USERNAME
38 if !info_cache.has('username'): return DEFAULT_USERNAME
39 return info_cache.username
40
41func set_username(username):
42 update_info({
43 "username": username
44 })
45
46func update_info(updates):
47 var data = {}
48
49 if info_cache != null:
50 for key in info_cache.keys():
51 data[key] = info_cache[key]
52
53 for key in updates.keys():
54 data[key] = info_cache[key]
55
56 var json = JSON.print(data)
57 var info_url = url + profile_file
58
59 $updateInfoRequest.request(info_url, [], true, HTTPClient.METHOD_PUT, json)
60
61func load_profile():
62 var info_url = url + profile_file
63 $loadInfoRequest.request(info_url)
64
65func resolve_url():
66 var url_record = url + '.well-known/hyper'
67 $resolveURLRequest.request(url_record)
68
69func download_image(url: String):
70 print('Loading image: ', url)
71 var file_name = url.get_file()
72 var key = parser.parse(url).host
73 # Save the picture with the profile key prefixed to it
74 picture_path = cache_folder + key + '-' + file_name
75 $loadImageRequest.download_file = picture_path
76 $loadImageRequest.request(url)
77
78func upload_image(path: String):
79 var picture_name = path.get_file()
80 var picture_url = url + picture_name
81
82 $uploader.upload_file(picture_url, path)
83
84func _on_loadInfoRequest_request_completed(_result, response_code, _headers, body):
85 print("Loaded info", _result, " ", response_code)
86 if response_code != 200:
87 printerr('Cannot load existing profile info: ', response_code)
88 emit_signal("no_info")
89 return
90
91 var parsed = JSON.parse(body.get_string_from_utf8())
92 if parsed.error != OK:
93 printerr(parsed.error_string)
94 emit_signal("no_info")
95 return
96
97 info_cache = parsed.result
98
99 var username = info_cache.username
100 var image = info_cache.image
101
102 emit_signal("info", username, image)
103
104 if image != null and autoload_image:
105 download_image(image)
106
107func _on_uploader_uploaded(resolved_url, response_code):
108 if response_code != 200:
109 printerr('Unable to upload file ')
110 return
111
112 if !url || (url.length() == 0):
113 printerr("Unable to load Link header for image.")
114 return
115
116 update_info({
117 "username": get_username(),
118 "image": resolved_url
119 })
120
121 download_image(resolved_url)
122
123func _on_loadImageRequest_request_completed(result, response_code, _headers, body):
124 if result != OK or response_code != 200:
125 printerr('Unable to load image: ', result, ": ", body.get_string_from_utf8())
126 return
127
128 print(result, ' Image got downloaded: ', picture_path)
129
130 emit_signal('image', picture_path)
131
132func _on_updateInfoRequest_request_completed(_result, _response_code, _headers, _body):
133 emit_signal("updated")
134
135func _on_resolveURLRequest_request_completed(result, response_code, _headers, body: PoolByteArray):
136 if result != OK or response_code != 200:
137 printerr('Unable to load final profile URL')
138 return
139
140 var lines = body.get_string_from_utf8()
141 var url = lines.split('\n')[0]
142 if !url.ends_with('/'):
143 url += '/'
144 emit_signal('resolved', url)
src/MultiplayerDemo/PlayerProfile.tscn +0 -29
……@@ -1,29 +0,0 @@
1[gd_scene load_steps=4 format=2]
2
3[ext_resource path="res://src/MultiplayerDemo/PlayerProfile.gd" type="Script" id=1]
4[ext_resource path="res://src/HyperRequest/HyperRequest.gd" type="Script" id=2]
5[ext_resource path="res://src/HyperRequest/HyperUploader.gd" type="Script" id=3]
6
7[node name="PlayerProfile" type="Node"]
8script = ExtResource( 1 )
9
10[node name="loadInfoRequest" type="HTTPRequest" parent="."]
11script = ExtResource( 2 )
12
13[node name="loadImageRequest" type="HTTPRequest" parent="."]
14script = ExtResource( 2 )
15
16[node name="updateInfoRequest" type="HTTPRequest" parent="."]
17script = ExtResource( 2 )
18
19[node name="resolveURLRequest" type="HTTPRequest" parent="."]
20script = ExtResource( 2 )
21
22[node name="uploader" type="Node" parent="."]
23script = ExtResource( 3 )
24
25[connection signal="request_completed" from="loadInfoRequest" to="." method="_on_loadInfoRequest_request_completed"]
26[connection signal="request_completed" from="loadImageRequest" to="." method="_on_loadImageRequest_request_completed"]
27[connection signal="request_completed" from="updateInfoRequest" to="." method="_on_updateInfoRequest_request_completed"]
28[connection signal="request_completed" from="resolveURLRequest" to="." method="_on_resolveURLRequest_request_completed"]
29[connection signal="uploaded" from="uploader" to="." method="_on_uploader_uploaded"]
src/MultiplayerDemo/PlayerSprite.gd +13 -12
……@@ -6,7 +6,7 @@ export var has_profile = false
66func load_profile(profile_url):
77 has_profile = true
88 $PlayerProfile.url = profile_url
9 $PlayerProfile.load_profile()
9 $PlayerProfile.load_info()
1010
1111func set_texture(texture):
1212 $Sprite.texture = texture
……@@ -18,28 +18,28 @@ func _on_VisibilityNotifier2D_screen_exited():
1818 position.x = viewport.x / 2
1919 position.y = viewport.y / 2
2020
21func set_radius(radius):
22 _set_sprite_radius(radius)
23 _set_colission_radius(radius)
24 _set_visibility_radius(radius)
21func set_radius(new_radius):
22 _set_sprite_radius(new_radius)
23 _set_colission_radius(new_radius)
24 _set_visibility_radius(new_radius)
2525
26func _set_sprite_radius(radius):
26func _set_sprite_radius(new_radius):
2727 var sprite = $Sprite
2828 var rect = sprite.get_rect()
2929 var xCurrent = rect.size.x
3030 var yCurrent = rect.size.y
3131
32 var xScale = (radius * 2) / xCurrent
33 var yScale = (radius * 2) / yCurrent
32 var xScale = (new_radius * 2) / xCurrent
33 var yScale = (new_radius * 2) / yCurrent
3434
3535 sprite.scale.x = xScale
3636 sprite.scale.y = yScale
3737
38func _set_colission_radius(radius):
39 $CollisionShape2D.shape.radius = radius
38func _set_colission_radius(new_radius):
39 $CollisionShape2D.shape.radius = new_radius
4040
41func _set_visibility_radius(radius):
42 var rect = Rect2(-radius, -radius, radius*2, radius*2)
41func _set_visibility_radius(new_radius):
42 var rect = Rect2(-new_radius, -new_radius, new_radius*2, new_radius*2)
4343 $VisibilityNotifier2D.rect = rect
4444
4545func _on_PlayerProfile_image(path):
……@@ -48,3 +48,4 @@ func _on_PlayerProfile_image(path):
4848 image.load(path)
4949 texture.create_from_image(image)
5050 set_texture(texture)
51
src/MultiplayerDemo/PlayerSprite.tscn +1 -2
……@@ -2,7 +2,7 @@
22
33[ext_resource path="res://src/MultiplayerDemo/icon.png" type="Texture" id=1]
44[ext_resource path="res://src/MultiplayerDemo/PlayerSprite.gd" type="Script" id=2]
5[ext_resource path="res://src/MultiplayerDemo/PlayerProfile.tscn" type="PackedScene" id=3]
5[ext_resource path="res://src/multiplayer/InfoLoader.tscn" type="PackedScene" id=3]
66
77[sub_resource type="ParticlesMaterial" id=1]
88flag_disable_z = true
……@@ -41,7 +41,6 @@ shape = SubResource( 2 )
4141rect = Rect2( -40, -40, 80, 80 )
4242
4343[node name="PlayerProfile" parent="." instance=ExtResource( 3 )]
44autoload_image = true
4544
4645[connection signal="screen_exited" from="VisibilityNotifier2D" to="." method="_on_VisibilityNotifier2D_screen_exited"]
4746[connection signal="image" from="PlayerProfile" to="." method="_on_PlayerProfile_image"]
src/multiplayer/InfoLoader.gd +143 -0
……@@ -0,0 +1,143 @@
1extends Node
2
3var URLParser = preload("res://src/utils/URLParser.gd")
4var parser = URLParser.new()
5
6signal info(info)
7signal no_info()
8signal image(path)
9signal updated()
10signal resolved(url)
11signal error(err)
12
13export var url = 'hyper://blog.mauve.moe/'
14export var cache_folder: String = 'user://hyper-file-cache/'
15export var profile_file: String = 'profile.json'
16
17export var autoload = false
18export var autoload_image = false
19export var defaults = {}
20
21var info_cache = null
22var has_loaded = false
23var picture_path = ''
24
25func _ready():
26 var dir = Directory.new()
27 var err = dir.make_dir_recursive(cache_folder)
28 if err != OK:
29 printerr("Unable to create cache directory ", err)
30
31 print("Profile setup")
32 if autoload:
33 load_info()
34
35func get(field):
36 if info_cache != null and info_cache.has(field):
37 return info_cache[field]
38 if defaults.has(field):
39 return defaults.get(field)
40
41func update_info(updates):
42 var data = {}
43
44 if info_cache != null:
45 for key in info_cache.keys():
46 data[key] = info_cache[key]
47 else:
48 for key in defaults:
49 data[key] = defaults[key]
50
51 for key in updates.keys():
52 data[key] = updates[key]
53
54 var json = JSON.print(data)
55 var info_url = url + profile_file
56
57 $updateInfoRequest.request(info_url, [], true, HTTPClient.METHOD_PUT, json)
58
59 info_cache = data
60
61func load_info():
62 var info_url = url + profile_file
63 $loadInfoRequest.request(info_url)
64
65func resolve_url():
66 var url_record = url + '.well-known/hyper'
67 $resolveURLRequest.request(url_record)
68
69func download_image(image_url: String):
70 print('Loading image: ', image_url)
71 var file_name = image_url.get_file()
72 var key = parser.parse(image_url).host
73 # Save the picture with the profile key prefixed to it
74 picture_path = cache_folder + key + '-' + file_name
75 $loadImageRequest.download_file = picture_path
76 $loadImageRequest.request(image_url)
77
78func upload_image(path: String):
79 var picture_name = path.get_file()
80 var picture_url = url + picture_name
81
82 $uploader.upload_file(picture_url, path)
83
84func _on_loadInfoRequest_request_completed(_result, response_code, _headers, body):
85 print("Loaded info", _result, " ", response_code)
86 if response_code != 200:
87 printerr('Cannot load existing profile info: ', response_code)
88 emit_signal("no_info")
89 return
90
91 var parsed = JSON.parse(body.get_string_from_utf8())
92 if parsed.error != OK:
93 printerr(parsed.error_string)
94 emit_signal("no_info")
95 return
96
97 info_cache = parsed.result
98
99 var image = info_cache.image
100
101 emit_signal("info", info_cache)
102
103 if image != null and autoload_image:
104 download_image(image)
105
106func _on_uploader_uploaded(resolved_url, response_code):
107 if response_code != 200:
108 printerr('Unable to upload file ')
109 return
110
111 if !url || (url.length() == 0):
112 printerr("Unable to load Link header for image.")
113 return
114
115 update_info({
116 "image": resolved_url
117 })
118
119 download_image(resolved_url)
120
121func _on_loadImageRequest_request_completed(result, response_code, _headers, body):
122 if result != OK or response_code != 200:
123 printerr('Unable to load image: ', result, ": ", body.get_string_from_utf8())
124 return
125
126 print(result, ' Image got downloaded: ', picture_path)
127
128 emit_signal('image', picture_path)
129
130func _on_updateInfoRequest_request_completed(_result, _response_code, _headers, _body):
131 emit_signal("updated")
132
133func _on_resolveURLRequest_request_completed(result, response_code, _headers, body: PoolByteArray):
134 if result != OK or response_code != 200:
135 printerr('Unable to load final profile URL')
136 return
137
138 var lines = body.get_string_from_utf8()
139 var resolved_url = lines.split('\n')[0]
140 if !resolved_url.ends_with('/'):
141 resolved_url += '/'
142
143 emit_signal('resolved', resolved_url)
src/multiplayer/InfoLoader.tscn +29 -0
……@@ -0,0 +1,29 @@
1[gd_scene load_steps=4 format=2]
2
3[ext_resource path="res://src/multiplayer/InfoLoader.gd" type="Script" id=1]
4[ext_resource path="res://src/HyperRequest/HyperRequest.gd" type="Script" id=2]
5[ext_resource path="res://src/HyperRequest/HyperUploader.gd" type="Script" id=3]
6
7[node name="InfoLoader" type="Node"]
8script = ExtResource( 1 )
9
10[node name="loadInfoRequest" type="HTTPRequest" parent="."]
11script = ExtResource( 2 )
12
13[node name="loadImageRequest" type="HTTPRequest" parent="."]
14script = ExtResource( 2 )
15
16[node name="updateInfoRequest" type="HTTPRequest" parent="."]
17script = ExtResource( 2 )
18
19[node name="resolveURLRequest" type="HTTPRequest" parent="."]
20script = ExtResource( 2 )
21
22[node name="uploader" type="Node" parent="."]
23script = ExtResource( 3 )
24
25[connection signal="request_completed" from="loadInfoRequest" to="." method="_on_loadInfoRequest_request_completed"]
26[connection signal="request_completed" from="loadImageRequest" to="." method="_on_loadImageRequest_request_completed"]
27[connection signal="request_completed" from="updateInfoRequest" to="." method="_on_updateInfoRequest_request_completed"]
28[connection signal="request_completed" from="resolveURLRequest" to="." method="_on_resolveURLRequest_request_completed"]
29[connection signal="uploaded" from="uploader" to="." method="_on_uploader_uploaded"]
src/multiplayer/ListGossip.gd +48 -0
……@@ -0,0 +1,48 @@
1extends HyperGossip
2
3signal list_items(items)
4
5class_name ListGossip
6
7export var id_key = 'url'
8export var items_event = 'items'
9
10# Enables you to gossip a list of items, useful for game lobbies
11var items = []
12
13func _ready():
14 ._ready()
15 connect("event", self, "_on_event_list_gossip")
16
17func add_item(item):
18 if !item.has(id_key):
19 printerr('Attempted to gossip item without an id key:', id_key, ' ', item)
20 return
21
22 if !has_item(item):
23 items.append(item)
24 broadcast_items()
25
26func has_item(item):
27 for existing in items:
28 if existing[id_key] == item[id_key]:
29 return true
30 return false
31
32func broadcast_items():
33 emit_signal('list_items', items)
34 broadcast_event(items_event, {'items': items})
35
36func _on_event_list_gossip(event, data, _from):
37 if event != items_event: return
38 if !data.has('items'):
39 printerr('Gossip without items list', data)
40 return
41 var hasNew = false
42 for item in data.items:
43 if !has_item(item):
44 hasNew = true
45 items.append(item)
46
47 if hasNew: broadcast_items()
48