Initial commit for testing/fixing a deprecated godot-colyseus addon
This commit is contained in:
BIN
addons/godot_colyseus/demo/blur.png
Normal file
BIN
addons/godot_colyseus/demo/blur.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
34
addons/godot_colyseus/demo/blur.png.import
Normal file
34
addons/godot_colyseus/demo/blur.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bdhx6b3h4tkao"
|
||||
path="res://.godot/imported/blur.png-4563c8475376415b661c69b2b9f1d2d4.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/godot_colyseus/demo/blur.png"
|
||||
dest_files=["res://.godot/imported/blur.png-4563c8475376415b661c69b2b9f1d2d4.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
8
addons/godot_colyseus/demo/char.tscn
Normal file
8
addons/godot_colyseus/demo/char.tscn
Normal file
@@ -0,0 +1,8 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/godot_colyseus/demo/blur.png" type="Texture2D" id=1]
|
||||
|
||||
[node name="char" type="Sprite2D"]
|
||||
position = Vector2( 0, -16 )
|
||||
scale = Vector2( 0.6, 1 )
|
||||
texture = ExtResource( 1 )
|
||||
32
addons/godot_colyseus/demo/chat.gd
Normal file
32
addons/godot_colyseus/demo/chat.gd
Normal file
@@ -0,0 +1,32 @@
|
||||
extends Control
|
||||
|
||||
const colyseus = preload("res://addons/godot_colyseus/lib/colyseus.gd")
|
||||
var room: colyseus.Room
|
||||
|
||||
func _ready():
|
||||
var client = colyseus.Client.new("ws://localhost:2567")
|
||||
var promise = client.join_or_create(colyseus.Schema, "chat")
|
||||
await promise.completed
|
||||
if promise.get_state() == promise.State.Failed:
|
||||
print("Failed")
|
||||
return
|
||||
var room: colyseus.Room = promise.get_data()
|
||||
room.on_message("messages").on(Callable(self, "_on_messages"))
|
||||
$label.text += "Connected"
|
||||
self.room = room
|
||||
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
#func _process(delta):
|
||||
# pass
|
||||
|
||||
func _on_messages(data):
|
||||
$label.text += "\n" + data
|
||||
|
||||
|
||||
func _on_send_pressed():
|
||||
if $input.text.is_empty():
|
||||
return
|
||||
room.send("message", $input.text)
|
||||
$input.text = ""
|
||||
1
addons/godot_colyseus/demo/chat.gd.uid
Normal file
1
addons/godot_colyseus/demo/chat.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cj7jhyoe2eluq
|
||||
48
addons/godot_colyseus/demo/chat.tscn
Normal file
48
addons/godot_colyseus/demo/chat.tscn
Normal file
@@ -0,0 +1,48 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dpxco2ygtk2bx"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/godot_colyseus/demo/chat.gd" id="1"]
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="input" type="TextEdit" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = -1
|
||||
anchor_top = 0.927
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -0.200012
|
||||
offset_right = -110.0
|
||||
|
||||
[node name="send" type="Button" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 3
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -104.0
|
||||
offset_top = -42.0
|
||||
offset_right = 1.0
|
||||
offset_bottom = -4.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 0
|
||||
text = "Send"
|
||||
|
||||
[node name="label" type="Label" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_right = -2.0
|
||||
offset_bottom = -54.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[connection signal="pressed" from="send" to="." method="_on_send_pressed"]
|
||||
27
addons/godot_colyseus/demo/control.tscn
Normal file
27
addons/godot_colyseus/demo/control.tscn
Normal file
@@ -0,0 +1,27 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://cxtq2mh35wwc5"]
|
||||
|
||||
[sub_resource type="GDScript" id="GDScript_uosag"]
|
||||
script/source = "extends Control
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
print(\"test \", await test_await())
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(delta):
|
||||
pass
|
||||
|
||||
func test_await():
|
||||
return 2
|
||||
"
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = SubResource("GDScript_uosag")
|
||||
68
addons/godot_colyseus/demo/main.gd
Normal file
68
addons/godot_colyseus/demo/main.gd
Normal file
@@ -0,0 +1,68 @@
|
||||
extends Node2D
|
||||
|
||||
const colyseus = preload("res://addons/godot_colyseus/lib/colyseus.gd")
|
||||
const Char = preload("./char.tscn")
|
||||
|
||||
class Player extends colyseus.Schema:
|
||||
static func define_fields():
|
||||
return [
|
||||
colyseus.Field.new("x", colyseus.NUMBER),
|
||||
colyseus.Field.new("y", colyseus.NUMBER)
|
||||
]
|
||||
|
||||
var node
|
||||
|
||||
func _to_string():
|
||||
return str("(",self.x,",",self.y,")")
|
||||
|
||||
class RoomState extends colyseus.Schema:
|
||||
static func define_fields():
|
||||
return [
|
||||
colyseus.Field.new("players", colyseus.MAP, Player),
|
||||
]
|
||||
|
||||
var room: colyseus.Room
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
var client = colyseus.Client.new("ws://localhost:2567")
|
||||
var promise = client.join_or_create(RoomState, "state_handler")
|
||||
await promise.completed
|
||||
if promise.get_state() == promise.State.Failed:
|
||||
print("Failed")
|
||||
return
|
||||
var room: colyseus.Room = promise.get_data()
|
||||
var state: RoomState = room.get_state()
|
||||
state.listen('players:add').on(Callable(self, "_on_players_add"))
|
||||
room.on_state_change.on(Callable(self, "_on_state"))
|
||||
room.on_message("hello").on(Callable(self, "_on_message"))
|
||||
self.room = room
|
||||
|
||||
func _on_message(data):
|
||||
print(str("hello:", data))
|
||||
|
||||
func _on_state(state):
|
||||
pass
|
||||
|
||||
func _on_players_add(target, value, key):
|
||||
print("Add:", " key:", key, " ", value)
|
||||
var ch = Char.instantiate()
|
||||
ch.position = Vector2(value.x, value.y)
|
||||
add_child(ch)
|
||||
value.node = ch
|
||||
value.listen(":change").on(Callable(self, "_on_player"))
|
||||
|
||||
func _on_player(target):
|
||||
print("Change ", target)
|
||||
var ch = target.node
|
||||
ch.position = Vector2(target.x, target.y)
|
||||
|
||||
func _physics_process(delta):
|
||||
if Input.is_action_pressed("ui_up"):
|
||||
room.send("move", { y = -1 });
|
||||
elif Input.is_action_pressed("ui_down"):
|
||||
room.send("move", { y = 1 });
|
||||
elif Input.is_action_pressed("ui_left"):
|
||||
room.send("move", { x = -1 });
|
||||
elif Input.is_action_pressed("ui_right"):
|
||||
room.send("move", { x = 1 });
|
||||
1
addons/godot_colyseus/demo/main.gd.uid
Normal file
1
addons/godot_colyseus/demo/main.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ddjkvt52o2ggh
|
||||
6
addons/godot_colyseus/demo/main.tscn
Normal file
6
addons/godot_colyseus/demo/main.tscn
Normal file
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://ceqab8i8yqmjj"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/godot_colyseus/demo/main.gd" id="1"]
|
||||
|
||||
[node name="Node2D" type="Node2D"]
|
||||
script = ExtResource("1")
|
||||
10
addons/godot_colyseus/init.gd
Normal file
10
addons/godot_colyseus/init.gd
Normal file
@@ -0,0 +1,10 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
pass
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
pass
|
||||
1
addons/godot_colyseus/init.gd.uid
Normal file
1
addons/godot_colyseus/init.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b13nsgfmclyf6
|
||||
132
addons/godot_colyseus/lib/client.gd
Normal file
132
addons/godot_colyseus/lib/client.gd
Normal file
@@ -0,0 +1,132 @@
|
||||
extends RefCounted
|
||||
|
||||
const promises = preload("res://addons/godot_colyseus/lib/promises.gd")
|
||||
const Promise = promises.Promise;
|
||||
const RunPromise = promises.RunPromise;
|
||||
const HTTP = preload("res://addons/godot_colyseus/lib/http.gd")
|
||||
const CRoom = preload("res://addons/godot_colyseus/lib/room.gd")
|
||||
const RoomInfo = preload("res://addons/godot_colyseus/lib/room_info.gd")
|
||||
|
||||
var endpoint: String
|
||||
|
||||
func _init(endpoint: String):
|
||||
self.endpoint = endpoint
|
||||
|
||||
func join_or_create(schema_type: GDScript, room_name: String, options: Dictionary = {}) -> Promise:
|
||||
return RunPromise.new(
|
||||
_create_match_make_request,
|
||||
["joinOrCreate", room_name, options, schema_type])
|
||||
|
||||
func create(schema_type: GDScript, room_name: String, options: Dictionary = {}) -> Promise:
|
||||
return RunPromise.new(
|
||||
_create_match_make_request,
|
||||
["create", room_name, options, schema_type])
|
||||
|
||||
func join(schema_type: GDScript, room_name: String, options: Dictionary = {}) -> Promise:
|
||||
return RunPromise.new(
|
||||
_create_match_make_request,
|
||||
["join", room_name, options, schema_type])
|
||||
|
||||
func join_by_id(schema_type: GDScript, room_id: String, options: Dictionary = {}) -> Promise:
|
||||
return RunPromise.new(
|
||||
_create_match_make_request,
|
||||
["joinById", room_id, options, schema_type])
|
||||
|
||||
func reconnect(schema_type: GDScript, reconnection_token: String) -> Promise:
|
||||
var arr = reconnection_token.split(":")
|
||||
if arr.size() == 2:
|
||||
var room_id = arr[0]
|
||||
var token = arr[1]
|
||||
return RunPromise.new(
|
||||
_create_match_make_request,
|
||||
["reconnect", room_id, {"reconnectionToken": token}, schema_type])
|
||||
else:
|
||||
var fail = Promise.new()
|
||||
fail.reject("Invalidate `reconnection_token`")
|
||||
return fail
|
||||
|
||||
func get_available_rooms(room_name:String) -> Promise:
|
||||
var path = "/matchmake/" + room_name
|
||||
return RunPromise.new(
|
||||
_http_get,
|
||||
[path, {"Accept": "application/json"}]
|
||||
).then(_process_rooms)
|
||||
|
||||
func _create_match_make_request(
|
||||
promise: Promise,
|
||||
method: String,
|
||||
room_name: String,
|
||||
options: Dictionary,
|
||||
schema_type: GDScript):
|
||||
var path: String = "/matchmake/" + method + "/" + room_name
|
||||
var server = endpoint
|
||||
if server.begins_with("ws"):
|
||||
server = server.replace("ws", "http")
|
||||
if options == null:
|
||||
options = {}
|
||||
var http = HTTP.new(server)
|
||||
var req = HTTP.RequestInfo.new("POST", path)
|
||||
req.add_header("Accept", "application/json")
|
||||
req.add_header("Content-Type", "application/json")
|
||||
req.body = options
|
||||
var resp = http.fetch(req)
|
||||
|
||||
if resp.get_state() == Promise.State.Waiting:
|
||||
await resp.completed
|
||||
if resp.get_state() == Promise.State.Failed:
|
||||
promise.reject(resp.get_error())
|
||||
return
|
||||
var res: HTTP.Response = resp.get_data()
|
||||
var response = res.json()
|
||||
if response == null:
|
||||
promise.reject("Server unreadable!")
|
||||
return
|
||||
|
||||
if response.get('code') != null:
|
||||
promise.reject(response['error'])
|
||||
return
|
||||
var room = CRoom.new(response["room"]["name"], schema_type)
|
||||
room.room_id = response["room"]["roomId"]
|
||||
room.session_id = response["sessionId"]
|
||||
|
||||
room.connect_remote(_build_endpoint(response["room"], { "sessionId": room.session_id }))
|
||||
|
||||
room.on_join.once(Callable(self, "_room_joined"), [promise, room])
|
||||
room.on_error.once(Callable(self, "_room_error"), [promise, room])
|
||||
|
||||
func _room_joined(promise: Promise, room: CRoom):
|
||||
room.on_error.off(Callable(self, "_room_error"))
|
||||
promise.resolve(room)
|
||||
|
||||
func _room_error(code: int, message: String, promise: Promise, room: CRoom):
|
||||
promise.reject(str("[", code, "]", message))
|
||||
|
||||
func _build_endpoint(room: Dictionary, options: Dictionary = {}):
|
||||
var params = PackedStringArray()
|
||||
for name in options.keys():
|
||||
params.append(name + "=" + options[name])
|
||||
return endpoint + "/" + room["processId"] + "/" + room["roomId"] + "?" + "&".join(params)
|
||||
|
||||
func _http_get(promise: Promise, path: String, headers: Dictionary):
|
||||
var server = endpoint
|
||||
if server.begins_with("ws"):
|
||||
server = server.replace("ws", "http")
|
||||
var http = HTTP.new(server)
|
||||
var req = HTTP.RequestInfo.new("GET", path)
|
||||
for key in headers.keys():
|
||||
req.add_header(key, headers[key])
|
||||
var resp = http.fetch(req)
|
||||
|
||||
if resp.get_state() == Promise.State.Waiting:
|
||||
await resp.completed
|
||||
if resp.get_state() == Promise.State.Failed:
|
||||
promise.reject(resp.get_error())
|
||||
return
|
||||
var res: HTTP.Response = resp.get_data()
|
||||
promise.resolve(res.json())
|
||||
|
||||
func _process_rooms(result, promise: Promise):
|
||||
var list = []
|
||||
for data in result:
|
||||
list.append(RoomInfo.new(data))
|
||||
return list
|
||||
1
addons/godot_colyseus/lib/client.gd.uid
Normal file
1
addons/godot_colyseus/lib/client.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://mutuixu84pvj
|
||||
180
addons/godot_colyseus/lib/collections.gd
Normal file
180
addons/godot_colyseus/lib/collections.gd
Normal file
@@ -0,0 +1,180 @@
|
||||
extends Object
|
||||
|
||||
const EventListener = preload("res://addons/godot_colyseus/lib/listener.gd")
|
||||
const SchemaInterface = preload("res://addons/godot_colyseus/lib/schema_interface.gd")
|
||||
|
||||
class Collection extends SchemaInterface:
|
||||
var sub_type
|
||||
|
||||
func meta_get_subtype(index):
|
||||
return sub_type
|
||||
|
||||
class ArraySchema extends Collection:
|
||||
var items = []
|
||||
|
||||
func clear(decoding: bool = false):
|
||||
items.clear()
|
||||
|
||||
func meta_get(index):
|
||||
if items.size() > index:
|
||||
return items[index]
|
||||
return null
|
||||
|
||||
func meta_get_key(index):
|
||||
return str(index)
|
||||
|
||||
func meta_set(index, key, value):
|
||||
_set_item(index, value)
|
||||
|
||||
func meta_remove(index):
|
||||
assert(items.size() > index)
|
||||
items.remove_at(index)
|
||||
|
||||
func _set_item(index, value):
|
||||
if items.size() > index:
|
||||
items[index] = value
|
||||
else:
|
||||
while items.size() < index - 1:
|
||||
items.append(null)
|
||||
items.append(value)
|
||||
|
||||
func meta_set_self(value):
|
||||
items = value
|
||||
|
||||
func at(index: int):
|
||||
return items[index]
|
||||
|
||||
func size() -> int:
|
||||
return items.size()
|
||||
|
||||
func _to_string():
|
||||
return JSON.stringify(items)
|
||||
|
||||
func to_object():
|
||||
return items
|
||||
|
||||
class MapSchema extends Collection:
|
||||
var _keys = {}
|
||||
var items = {}
|
||||
var _counter = 0
|
||||
|
||||
func clear(decoding: bool = false):
|
||||
items.clear()
|
||||
_keys.clear()
|
||||
_counter = 0
|
||||
|
||||
func meta_get(index):
|
||||
if _keys.has(index):
|
||||
return items[_keys[index]]
|
||||
return null
|
||||
|
||||
func meta_get_key(index):
|
||||
if not _keys.has(index):
|
||||
return index
|
||||
return _keys[index]
|
||||
|
||||
func meta_set(index, key, value):
|
||||
_keys[index] = key
|
||||
items[key] = value
|
||||
|
||||
func meta_remove(index):
|
||||
if not _keys.has(index):
|
||||
return
|
||||
items.erase(_keys[index])
|
||||
_keys.erase(index)
|
||||
|
||||
func at(key: String):
|
||||
return items.get(key)
|
||||
|
||||
func put(key: String, value):
|
||||
_keys[_counter] = key
|
||||
items[key] = value
|
||||
++_counter
|
||||
|
||||
func _to_string():
|
||||
return JSON.stringify(items)
|
||||
|
||||
func to_object():
|
||||
return items
|
||||
|
||||
func keys():
|
||||
var list = []
|
||||
for k in _keys:
|
||||
list.append(_keys[k])
|
||||
return list
|
||||
|
||||
func size():
|
||||
return _keys.size()
|
||||
|
||||
func has(key: String):
|
||||
return items.has(key)
|
||||
|
||||
class SetSchema extends Collection:
|
||||
var _counter = 0
|
||||
var items = {}
|
||||
|
||||
func clear(decoding: bool = false):
|
||||
items.clear()
|
||||
_counter = 0
|
||||
|
||||
func meta_get(index):
|
||||
if items.size() > index:
|
||||
return items[index]
|
||||
return null
|
||||
|
||||
func meta_get_key(index):
|
||||
return str(index)
|
||||
|
||||
func meta_set(index, key, value):
|
||||
_set_item(index, value)
|
||||
|
||||
func meta_remove(index):
|
||||
items.erase(index)
|
||||
|
||||
func _set_item(index, value):
|
||||
if items.size() > index:
|
||||
items[index] = value
|
||||
else:
|
||||
while items.size() < index - 1:
|
||||
items.append(null)
|
||||
items.append(value)
|
||||
|
||||
func _to_string():
|
||||
return JSON.stringify(items)
|
||||
|
||||
func to_object():
|
||||
return items
|
||||
|
||||
class CollectionSchema extends Collection:
|
||||
var items = []
|
||||
|
||||
func clear(decoding: bool = false):
|
||||
items.clear()
|
||||
|
||||
func meta_get(index):
|
||||
if items.size() > index:
|
||||
return items[index]
|
||||
return null
|
||||
|
||||
func meta_get_key(index):
|
||||
return str(index)
|
||||
|
||||
func meta_set(index, key, value):
|
||||
_set_item(index, value)
|
||||
|
||||
func meta_remove(index):
|
||||
items.erase(index)
|
||||
|
||||
func _set_item(index, value):
|
||||
if items.size() > index:
|
||||
items[index] = value
|
||||
else:
|
||||
while items.size() < index - 1:
|
||||
items.append(null)
|
||||
items.append(value)
|
||||
|
||||
func _to_string():
|
||||
return JSON.stringify(items)
|
||||
|
||||
func to_object():
|
||||
return items
|
||||
1
addons/godot_colyseus/lib/collections.gd.uid
Normal file
1
addons/godot_colyseus/lib/collections.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ciu14viqsjpjg
|
||||
32
addons/godot_colyseus/lib/colyseus.gd
Normal file
32
addons/godot_colyseus/lib/colyseus.gd
Normal file
@@ -0,0 +1,32 @@
|
||||
extends Object
|
||||
|
||||
const Client = preload("res://addons/godot_colyseus/lib/client.gd")
|
||||
const Schema = preload("res://addons/godot_colyseus/lib/schema.gd")
|
||||
const Room = preload("res://addons/godot_colyseus/lib/room.gd")
|
||||
const types = preload("res://addons/godot_colyseus/lib/types.gd")
|
||||
const Field = Schema.Field
|
||||
const REF = types.REF
|
||||
const MAP = types.MAP
|
||||
const ARRAY = types.ARRAY
|
||||
const STRING = types.STRING
|
||||
const NUMBER = types.NUMBER
|
||||
const BOOLEAN = types.BOOLEAN
|
||||
const INT8 = types.INT8
|
||||
const UINT8 = types.UINT8
|
||||
const INT16 = types.INT16
|
||||
const UINT16 = types.UINT16
|
||||
const INT32 = types.INT32
|
||||
const UINT32 = types.UINT32
|
||||
const INT64 = types.INT64
|
||||
const UINT64 = types.UINT64
|
||||
const FLOAT32 = types.FLOAT32
|
||||
const FLOAT64 = types.UINT32
|
||||
const collections = preload("res://addons/godot_colyseus/lib/collections.gd")
|
||||
const ArraySchema = collections.ArraySchema
|
||||
const MapSchema = collections.MapSchema
|
||||
const SetSchema = collections.SetSchema
|
||||
const CollectionSchema = collections.CollectionSchema
|
||||
|
||||
const RoomInfo = preload("res://addons/godot_colyseus/lib/room_info.gd")
|
||||
|
||||
const Promise = preload("res://addons/godot_colyseus/lib/promises.gd").Promise
|
||||
1
addons/godot_colyseus/lib/colyseus.gd.uid
Normal file
1
addons/godot_colyseus/lib/colyseus.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dni1bp1qice02
|
||||
68
addons/godot_colyseus/lib/decoder.gd
Normal file
68
addons/godot_colyseus/lib/decoder.gd
Normal file
@@ -0,0 +1,68 @@
|
||||
extends RefCounted
|
||||
|
||||
const MsgPack = preload("res://addons/godot_colyseus/lib/msgpack.gd")
|
||||
|
||||
var reader: StreamPeerBuffer
|
||||
|
||||
func _init(reader: StreamPeerBuffer):
|
||||
reader.big_endian = false
|
||||
self.reader = reader
|
||||
|
||||
func read_utf8() -> String:
|
||||
var prefix = reader.get_u8()
|
||||
var length = -1
|
||||
|
||||
if prefix < 0xc0:
|
||||
length = prefix & 0x1f
|
||||
elif prefix == 0xd9:
|
||||
length = reader.get_u8()
|
||||
elif prefix == 0xda:
|
||||
length = reader.get_u16()
|
||||
elif prefix == 0xdb:
|
||||
length = reader.get_u32()
|
||||
|
||||
return reader.get_utf8_string(length)
|
||||
|
||||
func number():
|
||||
var prefix = reader.get_u8()
|
||||
|
||||
if prefix < 0x80:
|
||||
return prefix
|
||||
elif prefix == 0xca:
|
||||
return reader.get_float()
|
||||
elif prefix == 0xcb:
|
||||
return reader.get_double()
|
||||
elif prefix == 0xcc:
|
||||
return reader.get_u8()
|
||||
elif prefix == 0xcd:
|
||||
return reader.get_u16()
|
||||
elif prefix == 0xce:
|
||||
return reader.get_u32()
|
||||
elif prefix == 0xcf:
|
||||
return reader.get_u64()
|
||||
elif prefix == 0xd0:
|
||||
return reader.get_8()
|
||||
elif prefix == 0xd1:
|
||||
return reader.get_16()
|
||||
elif prefix == 0xd2:
|
||||
return reader.get_32()
|
||||
elif prefix == 0xd3:
|
||||
return reader.get_64()
|
||||
elif prefix > 0xdf:
|
||||
return (0xff - prefix + 1) * -1
|
||||
|
||||
func has_more() -> bool:
|
||||
return reader.get_position() < reader.get_size()
|
||||
|
||||
func current_bit() -> int:
|
||||
return reader.data_array[reader.get_position()]
|
||||
|
||||
func is_number() -> bool:
|
||||
var prefix = current_bit()
|
||||
return prefix < 0x80 || (prefix >= 0xca && prefix <= 0xd3)
|
||||
|
||||
func unpack():
|
||||
var result = MsgPack.decode(reader)
|
||||
if result.error == OK:
|
||||
return result.result
|
||||
return null
|
||||
1
addons/godot_colyseus/lib/decoder.gd.uid
Normal file
1
addons/godot_colyseus/lib/decoder.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://btjicixj57gl5
|
||||
67
addons/godot_colyseus/lib/encoder.gd
Normal file
67
addons/godot_colyseus/lib/encoder.gd
Normal file
@@ -0,0 +1,67 @@
|
||||
extends RefCounted
|
||||
|
||||
const MsgPack = preload("res://addons/godot_colyseus/lib/msgpack.gd")
|
||||
|
||||
var writer: StreamPeerBuffer
|
||||
|
||||
func _init(writer: StreamPeerBuffer):
|
||||
writer.big_endian = false
|
||||
self.writer = writer
|
||||
|
||||
func string(v: String):
|
||||
|
||||
var bytes = v.to_utf8_buffer()
|
||||
var length = bytes.size()
|
||||
|
||||
if length < 0x20:
|
||||
writer.put_u8(length | 0xa0)
|
||||
elif length < 0x100:
|
||||
writer.put_u8(0xd9)
|
||||
writer.put_u8(length)
|
||||
elif length < 0x10000:
|
||||
writer.put_u8(0xda)
|
||||
writer.put_u16(length)
|
||||
elif length < 0x100000000:
|
||||
writer.put_u8(0xdb)
|
||||
writer.put_u32(length)
|
||||
else:
|
||||
assert(false) #,"String too long")
|
||||
|
||||
writer.put_data(bytes)
|
||||
|
||||
func number(v):
|
||||
if v == NAN:
|
||||
return number(0)
|
||||
elif v != abs(v):
|
||||
writer.put_u8(0xcb)
|
||||
writer.put_double(v)
|
||||
elif v >= 0:
|
||||
if v < 0x80:
|
||||
writer.put_u8(v)
|
||||
elif v < 0x100:
|
||||
writer.put_u8(0xcc)
|
||||
writer.put_u8(v)
|
||||
elif v < 0x10000:
|
||||
writer.put_u8(0xcd)
|
||||
writer.put_u16(v)
|
||||
elif v < 0x100000000:
|
||||
writer.put_u8(0xce)
|
||||
writer.put_u32(v)
|
||||
else:
|
||||
writer.put_u8(0xcf)
|
||||
writer.put_u32(v)
|
||||
else:
|
||||
if v >= -0x20:
|
||||
writer.put_u8(0xe0 | (v + 0x20))
|
||||
elif v >= -0x80:
|
||||
writer.put_u8(0xd0)
|
||||
writer.put_8(v)
|
||||
elif v >= -0x8000:
|
||||
writer.put_u8(0xd1)
|
||||
writer.put_16(v)
|
||||
elif v >= -0x80000000:
|
||||
writer.put_u8(0xd2)
|
||||
writer.put_32(v)
|
||||
else:
|
||||
writer.put_u8(0xd3)
|
||||
writer.put_64(v)
|
||||
1
addons/godot_colyseus/lib/encoder.gd.uid
Normal file
1
addons/godot_colyseus/lib/encoder.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://drl5m0b1yqxig
|
||||
23
addons/godot_colyseus/lib/frame_runner.gd
Normal file
23
addons/godot_colyseus/lib/frame_runner.gd
Normal file
@@ -0,0 +1,23 @@
|
||||
extends RefCounted
|
||||
|
||||
var _running = false
|
||||
var fn: Callable
|
||||
var argv: Array
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _init(fn: Callable,argv: Array = []):
|
||||
self.fn = fn
|
||||
self.argv = argv
|
||||
|
||||
func start():
|
||||
if not _running:
|
||||
_running = true
|
||||
var root: SceneTree = Engine.get_main_loop()
|
||||
while true:
|
||||
await root.process_frame
|
||||
if not _running:
|
||||
return
|
||||
fn.callv(argv)
|
||||
|
||||
func stop():
|
||||
_running = false
|
||||
1
addons/godot_colyseus/lib/frame_runner.gd.uid
Normal file
1
addons/godot_colyseus/lib/frame_runner.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b2ng861vtoeih
|
||||
229
addons/godot_colyseus/lib/http.gd
Normal file
229
addons/godot_colyseus/lib/http.gd
Normal file
@@ -0,0 +1,229 @@
|
||||
extends RefCounted
|
||||
|
||||
const promises = preload("res://addons/godot_colyseus/lib/promises.gd")
|
||||
const Promise = promises.Promise
|
||||
const RunPromise = promises.RunPromise
|
||||
|
||||
var _connected = false
|
||||
var _client_promise: promises.Promise
|
||||
|
||||
class RequestInfo:
|
||||
var method: String = "GET"
|
||||
var path: String = "/"
|
||||
var headers: PackedStringArray = []
|
||||
var body
|
||||
|
||||
func _init(method: String = "GET",path: String = "/"):
|
||||
self.method = method
|
||||
self.path = path
|
||||
|
||||
func add_header(key: String, value):
|
||||
headers.append(str(key, ": ", value))
|
||||
return self
|
||||
|
||||
func http_method():
|
||||
match method.to_upper():
|
||||
"GET":
|
||||
return HTTPClient.METHOD_GET
|
||||
"POST":
|
||||
return HTTPClient.METHOD_POST
|
||||
"PUT":
|
||||
return HTTPClient.METHOD_PUT
|
||||
"DELETE":
|
||||
return HTTPClient.METHOD_DELETE
|
||||
"HEAD":
|
||||
return HTTPClient.METHOD_HEAD
|
||||
"OPTIONS":
|
||||
return HTTPClient.METHOD_OPTIONS
|
||||
|
||||
func get_body():
|
||||
if body == null:
|
||||
body = ""
|
||||
if body is Dictionary or body is Array:
|
||||
body = JSON.stringify(body)
|
||||
return body
|
||||
|
||||
class Response:
|
||||
var _response_chunks: Array = []
|
||||
var _body
|
||||
var _has_response = false
|
||||
|
||||
var _status_code: int = 0
|
||||
var _content_length: int = 0
|
||||
var _headers
|
||||
|
||||
func body() -> PackedByteArray:
|
||||
if _body == null:
|
||||
_body = PackedByteArray()
|
||||
for chunk in _response_chunks:
|
||||
_body.append_array(chunk)
|
||||
return _body
|
||||
|
||||
func text() -> String:
|
||||
return body().get_string_from_utf8()
|
||||
|
||||
func json():
|
||||
var test_json_conv = JSON.new()
|
||||
var err = test_json_conv.parse(text())
|
||||
if err == OK:
|
||||
return test_json_conv.get_data()
|
||||
print(str(test_json_conv.get_error_message(), ":", test_json_conv.get_error_line()))
|
||||
return null
|
||||
|
||||
func headers() -> Dictionary:
|
||||
return _headers
|
||||
|
||||
func status_code() -> int:
|
||||
return _status_code
|
||||
|
||||
func content_length() -> int:
|
||||
return _content_length
|
||||
|
||||
func _to_string():
|
||||
var lines = PackedStringArray()
|
||||
lines.append(str("StatusCode: ", status_code()))
|
||||
lines.append(str("ContentLength: ", content_length()))
|
||||
lines.append(str("Headers: "))
|
||||
var header = headers()
|
||||
for key in header.keys():
|
||||
lines.append(str(" ", key, ": ", header[key]))
|
||||
lines.append(str("Body: [", body().size(), "]"))
|
||||
return "\n".join(lines)
|
||||
|
||||
var _old_status
|
||||
|
||||
func _init(server: String):
|
||||
var url = parseUrl(server)
|
||||
_client_promise = promises.RunPromise.new(Callable(self, "_setup"), [url.host, url.port, url.ssl]);
|
||||
|
||||
static func parseUrl(url) -> Dictionary:
|
||||
var regex = RegEx.new()
|
||||
regex.compile("(\\w+):\\/\\/([^\\/:]+)(:(\\d+))?")
|
||||
var result = regex.search(url)
|
||||
var scheme = result.get_string(1)
|
||||
var ssl = scheme == "https"
|
||||
var host = result.get_string(2)
|
||||
var portstr = result.get_string(4)
|
||||
var port = -1
|
||||
if portstr != "":
|
||||
port = int(portstr)
|
||||
return {
|
||||
"host": host,
|
||||
"ssl": ssl,
|
||||
"port": port,
|
||||
}
|
||||
|
||||
var host: String
|
||||
func _setup(promise: promises.Promise, host, port, ssl):
|
||||
var client = HTTPClient.new()
|
||||
self.host = host
|
||||
var error = client.connect_to_host(host, port, TLSOptions.client() if ssl else null)
|
||||
if error != OK:
|
||||
promise.reject(str("ErrorCode: ", error))
|
||||
var root = Engine.get_main_loop()
|
||||
while true:
|
||||
await root.process_frame
|
||||
client.poll()
|
||||
var status = client.get_status()
|
||||
|
||||
match status:
|
||||
HTTPClient.STATUS_CONNECTED:
|
||||
promise.resolve(client)
|
||||
break
|
||||
HTTPClient.STATUS_DISCONNECTED:
|
||||
promise.reject("Disconnected from Host")
|
||||
break
|
||||
HTTPClient.STATUS_CANT_CONNECT:
|
||||
promise.reject("Can't Connect to Host")
|
||||
break
|
||||
|
||||
func _request(promise: Promise, request: RequestInfo):
|
||||
if _client_promise.get_state() == promises.Promise.State.Waiting:
|
||||
await _client_promise.completed
|
||||
if _client_promise.get_state() == Promise.State.Failed:
|
||||
promise.reject(_client_promise.get_error())
|
||||
return
|
||||
var client: HTTPClient = _client_promise.get_data()
|
||||
var body = request.get_body()
|
||||
var error
|
||||
if body is String:
|
||||
error = client.request(request.http_method(), request.path, request.headers, body)
|
||||
elif body is PackedByteArray:
|
||||
error = client.request_raw(request.http_method(), request.path, request.headers, body)
|
||||
else:
|
||||
promise.reject("Unsupport body type")
|
||||
return
|
||||
if error != OK:
|
||||
promise.reject(str("Error code ", error))
|
||||
return
|
||||
var root = Engine.get_main_loop()
|
||||
var response = Response.new()
|
||||
while true:
|
||||
await root.process_frame
|
||||
error = client.poll()
|
||||
var status = client.get_status()
|
||||
match status:
|
||||
HTTPClient.STATUS_DISCONNECTED:
|
||||
if response._has_response:
|
||||
promise.resolve(response)
|
||||
else:
|
||||
promise.reject("Disconnected from Host")
|
||||
return
|
||||
HTTPClient.STATUS_CANT_CONNECT:
|
||||
promise.reject("Can't Connect to Host")
|
||||
return
|
||||
HTTPClient.STATUS_CONNECTION_ERROR:
|
||||
promise.reject("Connection Error")
|
||||
return
|
||||
HTTPClient.STATUS_BODY:
|
||||
if not response._has_response:
|
||||
response._has_response = true
|
||||
response._status_code = client.get_response_code()
|
||||
response._content_length = client.get_response_body_length()
|
||||
response._headers = client.get_response_headers_as_dictionary()
|
||||
var chunk = client.read_response_body_chunk()
|
||||
if chunk.is_empty():
|
||||
continue
|
||||
response._response_chunks.append(chunk)
|
||||
HTTPClient.STATUS_CONNECTED:
|
||||
promise.resolve(response)
|
||||
return
|
||||
pass
|
||||
|
||||
func _resolve(promise: Promise, request: RequestInfo, response: Response):
|
||||
if response.status_code() == 301:
|
||||
var new_request = RequestInfo.new(request.method, request.path)
|
||||
new_request.headers = request.headers
|
||||
new_request.body = request.body
|
||||
|
||||
var path: String = response.headers()["Location"]
|
||||
if path.begins_with("http://") or path.begins_with("https://"):
|
||||
var idx = path.find('/', 8)
|
||||
var host
|
||||
if idx >= 0:
|
||||
host = path.substr(0, idx)
|
||||
path = path.substr(idx)
|
||||
else:
|
||||
host = path
|
||||
path = '/'
|
||||
var url = parseUrl(host)
|
||||
if url.host != self.host:
|
||||
printerr("Cannot connect to new host ", host, self.host)
|
||||
promise.resolve(response)
|
||||
return
|
||||
else:
|
||||
new_request.path = path
|
||||
|
||||
promise.resolve(fetch(new_request))
|
||||
pass
|
||||
else:
|
||||
promise.resolve(response)
|
||||
|
||||
func fetch(request = null) -> Promise:
|
||||
if request == null:
|
||||
request = RequestInfo.new()
|
||||
elif request is String:
|
||||
var path = request
|
||||
request = RequestInfo.new()
|
||||
request.path = path
|
||||
return RunPromise.new(_request, [request])
|
||||
1
addons/godot_colyseus/lib/http.gd.uid
Normal file
1
addons/godot_colyseus/lib/http.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://co8kfm0yu3vui
|
||||
62
addons/godot_colyseus/lib/listener.gd
Normal file
62
addons/godot_colyseus/lib/listener.gd
Normal file
@@ -0,0 +1,62 @@
|
||||
extends RefCounted
|
||||
|
||||
const ps = preload("res://addons/godot_colyseus/lib/promises.gd")
|
||||
|
||||
|
||||
class Callback:
|
||||
var fn: Callable
|
||||
var args
|
||||
var once = false
|
||||
|
||||
func emit(arg: Array):
|
||||
var parmas = []
|
||||
parmas.append_array(arg)
|
||||
parmas.append_array(args)
|
||||
fn.callv(parmas)
|
||||
|
||||
var cbs = []
|
||||
|
||||
func on(fn: Callable, args: Array = []):
|
||||
var cb = Callback.new()
|
||||
cb.fn = fn
|
||||
cb.args = args
|
||||
cbs.append(cb)
|
||||
|
||||
func off(fn: Callable):
|
||||
var willremove = []
|
||||
for cb in cbs:
|
||||
if cb.fn == fn:
|
||||
willremove.append(cb)
|
||||
for cb in willremove:
|
||||
cbs.erase(cb)
|
||||
|
||||
func once(fn: Callable, args: Array = []):
|
||||
var cb = Callback.new()
|
||||
cb.fn = fn
|
||||
cb.args = args
|
||||
cb.once = true
|
||||
cbs.append(cb)
|
||||
|
||||
func wait() -> ps.Promise:
|
||||
var promise = ps.Promise.new()
|
||||
once(Callable(self, "_on_event"), [promise])
|
||||
return promise
|
||||
|
||||
func _on_event(data, promise: ps.Promise):
|
||||
promise.resolve(data)
|
||||
|
||||
func emit(argv: Array = []):
|
||||
var willremove = []
|
||||
var size = cbs.size()
|
||||
for i in range(size):
|
||||
var cb = cbs[i]
|
||||
if !is_instance_valid(cb):
|
||||
cbs.remove_at(i)
|
||||
i -= 1
|
||||
size -= 1
|
||||
continue
|
||||
cb.emit(argv)
|
||||
if cb.once:
|
||||
willremove.append(cb)
|
||||
for cb in willremove:
|
||||
cbs.erase(cb)
|
||||
1
addons/godot_colyseus/lib/listener.gd.uid
Normal file
1
addons/godot_colyseus/lib/listener.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dtgvuxvgbn08y
|
||||
487
addons/godot_colyseus/lib/msgpack.gd
Normal file
487
addons/godot_colyseus/lib/msgpack.gd
Normal file
@@ -0,0 +1,487 @@
|
||||
# Copyright (C) 2019 Tintin Ho
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
#
|
||||
#
|
||||
# godot-msgpack
|
||||
#
|
||||
# This is a MessagePack serializer written in pure GDSciprt. To install this
|
||||
# library in your project simply and copy and paste this file inside your
|
||||
# project (e.g. res://msgpack.gd).
|
||||
#
|
||||
#
|
||||
# class Msgpack
|
||||
# static Dictionary encode(Variant value)
|
||||
# Convert a value (number, string, array and dictionary) into their
|
||||
# counterparts in messagepack. Returns dictionary with three fields:
|
||||
# `result` which is the packed data (a PackedByteArray); `error` which is the
|
||||
# error code; and `error_string` which is a human readable error message
|
||||
#
|
||||
# static Dictionary decode(PackedByteArray bytes)
|
||||
# Convert a packed data (a PackedByteArray) into a value, the reverse of the
|
||||
# encode function. The return value is similar to the one in the encode
|
||||
# method
|
||||
|
||||
static func encode(value, buffer: StreamPeerBuffer):
|
||||
var ctx = {error = OK, error_string = ""}
|
||||
buffer.big_endian = true
|
||||
|
||||
_encode(buffer, value, ctx)
|
||||
if ctx.error == OK:
|
||||
return {
|
||||
result = buffer.data_array,
|
||||
error = OK,
|
||||
error_string = "",
|
||||
}
|
||||
else:
|
||||
return {
|
||||
result = PackedByteArray(),
|
||||
error = ctx.error,
|
||||
error_string = ctx.error_string,
|
||||
}
|
||||
|
||||
static func decode(buffer: StreamPeerBuffer):
|
||||
buffer.big_endian = true
|
||||
|
||||
var ctx = {error = OK, error_string = ""}
|
||||
var value = _decode(buffer, ctx)
|
||||
if ctx.error == OK:
|
||||
if buffer.get_position() == buffer.get_size():
|
||||
return {result = value, error = OK, error_string = ""}
|
||||
else:
|
||||
var msg = "excess buffer %s bytes" % [buffer.get_size() - buffer.get_position()]
|
||||
return {result = null, error = FAILED, error_string = msg}
|
||||
else:
|
||||
return {result = null, error = ctx.error, error_string = ctx.error_string}
|
||||
|
||||
static func _encode(buf, value, ctx):
|
||||
match typeof(value):
|
||||
TYPE_NIL:
|
||||
buf.put_u8(0xc0)
|
||||
|
||||
TYPE_BOOL:
|
||||
if value:
|
||||
buf.put_u8(0xc3)
|
||||
else:
|
||||
buf.put_u8(0xc2)
|
||||
|
||||
TYPE_INT:
|
||||
if -(1 << 5) <= value and value <= (1 << 7) - 1:
|
||||
# fixnum (positive and negative)
|
||||
buf.put_8(value)
|
||||
elif -(1 << 7) <= value and value <= (1 << 7):
|
||||
buf.put_u8(0xd0)
|
||||
buf.put_8(value)
|
||||
elif -(1 << 15) <= value and value <= (1 << 15):
|
||||
buf.put_u8(0xd1)
|
||||
buf.put_16(value)
|
||||
elif -(1 << 31) <= value and value <= (1 << 31):
|
||||
buf.put_u8(0xd2)
|
||||
buf.put_32(value)
|
||||
else:
|
||||
buf.put_u8(0xd3)
|
||||
buf.put_64(value)
|
||||
|
||||
TYPE_FLOAT:
|
||||
buf.put_u8(0xcb)
|
||||
buf.put_double(value)
|
||||
|
||||
TYPE_STRING:
|
||||
var bytes = value.to_utf8_buffer()
|
||||
|
||||
var size = bytes.size()
|
||||
if size <= (1 << 5) - 1:
|
||||
# type fixstr [101XXXXX]
|
||||
buf.put_u8(0xa0 | size)
|
||||
elif size <= (1 << 8) - 1:
|
||||
# type str 8
|
||||
buf.put_u8(0xd9)
|
||||
buf.put_u8(size)
|
||||
elif size <= (1 << 16) - 1:
|
||||
# type str 16
|
||||
buf.put_u8(0xda)
|
||||
buf.put_u16(size)
|
||||
elif size <= (1 << 32) - 1:
|
||||
# type str 32
|
||||
buf.put_u8(0xdb)
|
||||
buf.put_u32(size)
|
||||
else:
|
||||
assert(false)
|
||||
|
||||
buf.put_data(bytes)
|
||||
|
||||
TYPE_PACKED_BYTE_ARRAY:
|
||||
var size = value.size()
|
||||
if size <= (1 << 8) - 1:
|
||||
buf.put_u8(0xc4)
|
||||
buf.put_u8(size)
|
||||
elif size <= (1 << 16) - 1:
|
||||
buf.put_u8(0xc5)
|
||||
buf.put_u16(size)
|
||||
elif size <= (1 << 32) - 1:
|
||||
buf.put_u8(0xc6)
|
||||
buf.put_u32(size)
|
||||
else:
|
||||
assert(false)
|
||||
|
||||
buf.put_data(value)
|
||||
|
||||
TYPE_ARRAY:
|
||||
var size = value.size()
|
||||
if size <= 15:
|
||||
# type fixarray [1001XXXX]
|
||||
buf.put_u8(0x90 | size)
|
||||
elif size <= (1 << 16) - 1:
|
||||
# type array 16
|
||||
buf.put_u8(0xdc)
|
||||
buf.put_u16(size)
|
||||
elif size <= (1 << 32) - 1:
|
||||
# type array 32
|
||||
buf.put_u8(0xdd)
|
||||
buf.put_u32(size)
|
||||
else:
|
||||
assert(false)
|
||||
|
||||
for obj in value:
|
||||
_encode(buf, obj, ctx)
|
||||
if ctx.error != OK:
|
||||
return
|
||||
|
||||
TYPE_DICTIONARY:
|
||||
var size = value.size()
|
||||
if size <= 15:
|
||||
# type fixmap [1000XXXX]
|
||||
buf.put_u8(0x80 | size)
|
||||
elif size <= (1 << 16) - 1:
|
||||
# type map 16
|
||||
buf.put_u8(0xde)
|
||||
buf.put_u16(size)
|
||||
elif size <= (1 << 32) - 1:
|
||||
# type map 32
|
||||
buf.put_u8(0xdf)
|
||||
buf.put_u32(size)
|
||||
else:
|
||||
assert(false)
|
||||
|
||||
for key in value:
|
||||
_encode(buf, key, ctx)
|
||||
if ctx.error != OK:
|
||||
return
|
||||
|
||||
_encode(buf, value[key], ctx)
|
||||
if ctx.error != OK:
|
||||
return
|
||||
_:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "unsupported data type %s" % [typeof(value)]
|
||||
|
||||
static func _decode(buffer, ctx):
|
||||
if buffer.get_position() == buffer.get_size():
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "unexpected end of input"
|
||||
return null
|
||||
|
||||
var head = buffer.get_u8()
|
||||
if head == 0xc0:
|
||||
return null
|
||||
elif head == 0xc2:
|
||||
return false
|
||||
elif head == 0xc3:
|
||||
return true
|
||||
|
||||
# Integers
|
||||
elif head & 0x80 == 0:
|
||||
# positive fixnum
|
||||
return head
|
||||
elif (~head) & 0xe0 == 0:
|
||||
# negative fixnum
|
||||
return head - 256
|
||||
elif head == 0xcc:
|
||||
# uint 8
|
||||
if buffer.get_size() - buffer.get_position() < 1:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for uint8"
|
||||
return null
|
||||
|
||||
return buffer.get_u8()
|
||||
elif head == 0xcd:
|
||||
# uint 16
|
||||
if buffer.get_size() - buffer.get_position() < 2:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for uint16"
|
||||
return null
|
||||
|
||||
return buffer.get_u16()
|
||||
elif head == 0xce:
|
||||
# uint 32
|
||||
if buffer.get_size() - buffer.get_position() < 4:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for uint32"
|
||||
return null
|
||||
|
||||
return buffer.get_u32()
|
||||
elif head == 0xcf:
|
||||
# uint 64
|
||||
if buffer.get_size() - buffer.get_position() < 8:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for uint64"
|
||||
return null
|
||||
|
||||
return buffer.get_u64()
|
||||
elif head == 0xd0:
|
||||
# int 8
|
||||
if buffer.get_size() - buffer.get_position() < 1:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enogh buffer for int8"
|
||||
return null
|
||||
|
||||
return buffer.get_8()
|
||||
elif head == 0xd1:
|
||||
# int 16
|
||||
if buffer.get_size() - buffer.get_position() < 2:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enogh buffer for int16"
|
||||
return null
|
||||
|
||||
return buffer.get_16()
|
||||
elif head == 0xd2:
|
||||
# int 32
|
||||
if buffer.get_size() - buffer.get_position() < 4:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for int32"
|
||||
return null
|
||||
|
||||
return buffer.get_32()
|
||||
elif head == 0xd3:
|
||||
# int 64
|
||||
if buffer.get_size() - buffer.get_position() < 8:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for int64"
|
||||
return null
|
||||
|
||||
return buffer.get_64()
|
||||
|
||||
# Float
|
||||
elif head == 0xca:
|
||||
# float32
|
||||
if buffer.get_size() - buffer.get_position() < 4:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for float32"
|
||||
return null
|
||||
|
||||
return buffer.get_float()
|
||||
elif head == 0xcb:
|
||||
# float64
|
||||
if buffer.get_size() - buffer.get_position() < 4:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for float64"
|
||||
return null
|
||||
|
||||
return buffer.get_double()
|
||||
|
||||
# String
|
||||
elif (~head) & 0xa0 == 0:
|
||||
var size = head & 0x1f
|
||||
if buffer.get_size() - buffer.get_position() < size:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for fixstr required %s bytes" % [size]
|
||||
return null
|
||||
|
||||
return buffer.get_utf8_string(size)
|
||||
elif head == 0xd9:
|
||||
if buffer.get_size() - buffer.get_position() < 1:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for str8 size"
|
||||
return null
|
||||
|
||||
var size = buffer.get_u8()
|
||||
if buffer.get_size() - buffer.get_position() < size:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for str8 data required %s bytes" % [size]
|
||||
return null
|
||||
|
||||
return buffer.get_utf8_string(size)
|
||||
elif head == 0xda:
|
||||
if buffer.get_size() - buffer.get_position() < 2:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for str16 size"
|
||||
return null
|
||||
|
||||
var size = buffer.get_u16()
|
||||
if buffer.get_size() - buffer.get_position() < size:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for str16 data required %s bytes" % [size]
|
||||
return null
|
||||
|
||||
return buffer.get_utf8_string(size)
|
||||
elif head == 0xdb:
|
||||
if buffer.get_size() - buffer.get_position() < 4:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for str32 size"
|
||||
return null
|
||||
|
||||
var size = buffer.get_u32()
|
||||
if buffer.get_size() - buffer.get_position() < size:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for str32 data required %s bytes" % [size]
|
||||
return null
|
||||
|
||||
return buffer.get_utf8_string(size)
|
||||
|
||||
# Binary
|
||||
elif head == 0xc4:
|
||||
if buffer.get_size() - buffer.get_position() < 1:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for bin8 size"
|
||||
return null
|
||||
|
||||
var size = buffer.get_u8()
|
||||
if buffer.get_size() - buffer.get_position() < size:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for bin8 data required %s bytes" % [size]
|
||||
return null
|
||||
|
||||
var res = buffer.get_data(size)
|
||||
assert(res[0] == OK)
|
||||
return res[1]
|
||||
elif head == 0xc5:
|
||||
if buffer.get_size() - buffer.get_position() < 2:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for bin16 size"
|
||||
return null
|
||||
|
||||
var size = buffer.get_u16()
|
||||
if buffer.get_size() - buffer.get_position() < size:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for bin16 data required %s bytes" % [size]
|
||||
return null
|
||||
|
||||
var res = buffer.get_data(size)
|
||||
assert(res[0] == OK)
|
||||
return res[1]
|
||||
elif head == 0xc6:
|
||||
if buffer.get_size() - buffer.get_position() < 4:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for bin32 size"
|
||||
return null
|
||||
|
||||
var size = buffer.get_u32()
|
||||
if buffer.get_size() - buffer.get_position() < size:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for bin32 data required %s bytes" % [size]
|
||||
return null
|
||||
|
||||
var res = buffer.get_data(size)
|
||||
assert(res[0] == OK)
|
||||
return res[1]
|
||||
|
||||
# Array
|
||||
elif head & 0xf0 == 0x90:
|
||||
var size = head & 0x0f
|
||||
var res = []
|
||||
for i in range(size):
|
||||
res.append(_decode(buffer, ctx))
|
||||
if ctx.error != OK:
|
||||
return null
|
||||
return res
|
||||
elif head == 0xdc:
|
||||
if buffer.get_size() - buffer.get_position() < 2:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for array16 size"
|
||||
return null
|
||||
|
||||
var size = buffer.get_u16()
|
||||
var res = []
|
||||
for i in range(size):
|
||||
res.append(_decode(buffer, ctx))
|
||||
if ctx.error != OK:
|
||||
return null
|
||||
return res
|
||||
elif head == 0xdd:
|
||||
if buffer.get_size() - buffer.get_position() < 4:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for array32 size"
|
||||
return null
|
||||
|
||||
var size = buffer.get_u32()
|
||||
var res = []
|
||||
for i in range(size):
|
||||
res.append(_decode(buffer, ctx))
|
||||
if ctx.error != OK:
|
||||
return null
|
||||
return res
|
||||
|
||||
# Map
|
||||
elif head & 0xf0 == 0x80:
|
||||
var size = head & 0x0f
|
||||
var res = {}
|
||||
for i in range(size):
|
||||
var k = _decode(buffer, ctx)
|
||||
if ctx.error != OK:
|
||||
return null
|
||||
|
||||
var v = _decode(buffer, ctx)
|
||||
if ctx.error != OK:
|
||||
return null
|
||||
|
||||
res[k] = v
|
||||
return res
|
||||
elif head == 0xde:
|
||||
if buffer.get_size() - buffer.get_position() < 2:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for map16 size"
|
||||
return null
|
||||
|
||||
var size = buffer.get_u16()
|
||||
var res = {}
|
||||
for i in range(size):
|
||||
var k = _decode(buffer, ctx)
|
||||
if ctx.error != OK:
|
||||
return null
|
||||
|
||||
var v = _decode(buffer, ctx)
|
||||
if ctx.error != OK:
|
||||
return null
|
||||
|
||||
res[k] = v
|
||||
return res
|
||||
elif head == 0xdf:
|
||||
if buffer.get_size() - buffer.get_position() < 4:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "not enough buffer for map32 size"
|
||||
return null
|
||||
|
||||
var size = buffer.get_u32()
|
||||
var res = {}
|
||||
for i in range(size):
|
||||
var k = _decode(buffer, ctx)
|
||||
if ctx.error != OK:
|
||||
return null
|
||||
|
||||
var v = _decode(buffer, ctx)
|
||||
if ctx.error != OK:
|
||||
return null
|
||||
|
||||
res[k] = v
|
||||
return res
|
||||
|
||||
else:
|
||||
ctx.error = FAILED
|
||||
ctx.error_string = "invalid byte tag %02X at pos %s" % [head, buffer.get_position()]
|
||||
return null
|
||||
1
addons/godot_colyseus/lib/msgpack.gd.uid
Normal file
1
addons/godot_colyseus/lib/msgpack.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dlclaop7pocqd
|
||||
9
addons/godot_colyseus/lib/operations.gd
Normal file
9
addons/godot_colyseus/lib/operations.gd
Normal file
@@ -0,0 +1,9 @@
|
||||
extends Node
|
||||
|
||||
const ADD = 128
|
||||
const REPLACE = 0
|
||||
const DELETE = 64
|
||||
const DELETE_AND_ADD = 192
|
||||
const TOUCH = 1
|
||||
const CLEAR = 10
|
||||
const SWITCH_TO_STRUCTURE = 255
|
||||
1
addons/godot_colyseus/lib/operations.gd.uid
Normal file
1
addons/godot_colyseus/lib/operations.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bucnjhgajvk8x
|
||||
107
addons/godot_colyseus/lib/promises.gd
Normal file
107
addons/godot_colyseus/lib/promises.gd
Normal file
@@ -0,0 +1,107 @@
|
||||
extends RefCounted
|
||||
|
||||
class Promise:
|
||||
enum State {
|
||||
Waiting,
|
||||
Success,
|
||||
Failed
|
||||
}
|
||||
var result
|
||||
|
||||
signal completed
|
||||
|
||||
var _state: State = State.Waiting
|
||||
|
||||
func get_state() -> State:
|
||||
return _state
|
||||
|
||||
func resolve(res = null):
|
||||
if res is Promise:
|
||||
await res.completed
|
||||
result = res.result
|
||||
_state = res.get_state()
|
||||
emit_signal("completed")
|
||||
else:
|
||||
result = res
|
||||
_state = State.Success
|
||||
emit_signal("completed")
|
||||
|
||||
func reject(error = null):
|
||||
result = error
|
||||
_state = State.Failed
|
||||
emit_signal("completed")
|
||||
|
||||
var data:get = get_data
|
||||
func get_data():
|
||||
if _state == State.Success:
|
||||
return result
|
||||
return null
|
||||
|
||||
var error:get = get_error
|
||||
func get_error():
|
||||
if _state == State.Failed:
|
||||
return result
|
||||
return null
|
||||
|
||||
var is_failed : bool :
|
||||
get():
|
||||
return _state == State.Failed
|
||||
|
||||
func wait():
|
||||
if _state == State.Waiting:
|
||||
await self.completed
|
||||
return self
|
||||
|
||||
func _to_string():
|
||||
match _state:
|
||||
State.Waiting:
|
||||
return "[Waiting]"
|
||||
State.Success:
|
||||
return str("[Success:",result,"]")
|
||||
State.Failed:
|
||||
return str("[Failed:",result,"]")
|
||||
|
||||
func _next(promise, callback: Callable, argv: Array):
|
||||
await wait()
|
||||
if _state == State.Success:
|
||||
var arr = [get_data(), promise]
|
||||
arr.append_array(argv)
|
||||
var ret = await callback.callv(arr)
|
||||
promise.resolve(ret)
|
||||
|
||||
func then(callback: Callable, argv: Array = []) -> Promise:
|
||||
return RunPromise.new(Callable(self, "_next"), [callback, argv])
|
||||
|
||||
class FramePromise extends Promise:
|
||||
var cb: Callable
|
||||
var argv: Array
|
||||
|
||||
func _init(callback: Callable,argv: Array = []):
|
||||
cb = callback
|
||||
self.argv = argv
|
||||
_run()
|
||||
|
||||
func _run():
|
||||
var root = Engine.get_main_loop()
|
||||
while true:
|
||||
if root is SceneTree:
|
||||
await root.process_frame
|
||||
var arr = [self]
|
||||
arr.append_array(argv)
|
||||
cb.callv(arr)
|
||||
if get_state() != State.Waiting:
|
||||
break
|
||||
|
||||
class RunPromise extends Promise:
|
||||
var cb: Callable
|
||||
var argv: Array
|
||||
|
||||
func _init(callback: Callable,argv: Array = []):
|
||||
cb = callback
|
||||
self.argv = argv
|
||||
_run()
|
||||
|
||||
func _run():
|
||||
var arr = [self]
|
||||
arr.append_array(argv)
|
||||
await cb.callv(arr)
|
||||
1
addons/godot_colyseus/lib/promises.gd.uid
Normal file
1
addons/godot_colyseus/lib/promises.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d4lhtnts1yq1k
|
||||
198
addons/godot_colyseus/lib/room.gd
Normal file
198
addons/godot_colyseus/lib/room.gd
Normal file
@@ -0,0 +1,198 @@
|
||||
extends RefCounted
|
||||
|
||||
const FrameRunner = preload("res://addons/godot_colyseus/lib/frame_runner.gd")
|
||||
const EventListener = preload("res://addons/godot_colyseus/lib/listener.gd")
|
||||
const ser = preload("res://addons/godot_colyseus/lib/serializer.gd")
|
||||
const Decoder = preload("res://addons/godot_colyseus/lib/decoder.gd")
|
||||
const Encoder = preload("res://addons/godot_colyseus/lib/encoder.gd")
|
||||
const MsgPack = preload("res://addons/godot_colyseus/lib/msgpack.gd")
|
||||
const Schema = preload("./schema.gd")
|
||||
|
||||
const CODE_HANDSHAKE = 9
|
||||
const CODE_JOIN_ROOM = 10
|
||||
const CODE_ERROR = 11
|
||||
const CODE_LEAVE_ROOM = 12
|
||||
const CODE_ROOM_DATA = 13
|
||||
const CODE_ROOM_STATE = 14
|
||||
const CODE_ROOM_STATE_PATCH = 15
|
||||
const CODE_ROOM_DATA_SCHEMA = 16
|
||||
|
||||
const ERROR_MATCHMAKE_NO_HANDLER = 4210
|
||||
const ERROR_MATCHMAKE_INVALID_CRITERIA = 4211
|
||||
const ERROR_MATCHMAKE_INVALID_ROOM_ID = 4212
|
||||
const ERROR_MATCHMAKE_UNHANDLED = 4213
|
||||
const ERROR_MATCHMAKE_EXPIRED = 4214
|
||||
|
||||
const ERROR_AUTH_FAILED = 4215
|
||||
const ERROR_APPLICATION_ERROR = 4216
|
||||
|
||||
var room_name: String
|
||||
var room_id: String
|
||||
var session_id: String
|
||||
var serializer: ser.Serializer
|
||||
var ws: WebSocketPeer
|
||||
var frame_runner: FrameRunner
|
||||
var reconnection_token: String
|
||||
|
||||
var schema_type: GDScript
|
||||
|
||||
var _has_joined = false
|
||||
func has_joined() -> bool:
|
||||
return _has_joined
|
||||
|
||||
# [code: int, message: String]
|
||||
var on_error: EventListener = EventListener.new()
|
||||
|
||||
# []
|
||||
var on_leave: EventListener = EventListener.new()
|
||||
|
||||
# []
|
||||
var on_join: EventListener = EventListener.new()
|
||||
|
||||
# [state: Schema]
|
||||
var on_state_change: EventListener = EventListener.new()
|
||||
|
||||
# [data]
|
||||
var _messages = {}
|
||||
func on_message(event: String, new_listener: bool = true) -> EventListener:
|
||||
var listener
|
||||
if not _messages.has(event) or new_listener:
|
||||
listener = EventListener.new()
|
||||
_messages[event] = listener
|
||||
else:
|
||||
listener = _messages[event]
|
||||
return listener
|
||||
|
||||
func _init(room_name: String,schema_type: GDScript):
|
||||
self.room_name = room_name
|
||||
self.schema_type = schema_type
|
||||
ws = WebSocketPeer.new()
|
||||
#ws.connect("connection_established",Callable(self,"_connection_established"))
|
||||
#ws.connect("connection_error",Callable(self,"_connection_error"))
|
||||
#ws.connect("connection_closed",Callable(self,"_connection_closed"))
|
||||
#ws.connect("data_received",Callable(self,"_on_data"))
|
||||
|
||||
frame_runner = FrameRunner.new(_on_frame)
|
||||
|
||||
|
||||
|
||||
func _connection_established(protocol):
|
||||
pass
|
||||
|
||||
func _connection_error():
|
||||
frame_runner.stop()
|
||||
|
||||
func _connection_closed(was_clean: bool):
|
||||
frame_runner.stop()
|
||||
|
||||
func _on_data():
|
||||
var data = ws.get_packet()
|
||||
var reader = StreamPeerBuffer.new()
|
||||
reader.data_array = data
|
||||
|
||||
var decoder = Decoder.new(reader)
|
||||
var code = reader.get_u8()
|
||||
match code:
|
||||
CODE_JOIN_ROOM:
|
||||
|
||||
var token = reader.get_string(reader.get_u8())
|
||||
|
||||
var serializer_id = reader.get_string(reader.get_u8())
|
||||
|
||||
if serializer == null:
|
||||
serializer = ser.getSerializer(serializer_id, schema_type)
|
||||
|
||||
if decoder.has_more():
|
||||
if serializer:
|
||||
serializer.handshake(decoder)
|
||||
else:
|
||||
on_error.emit([1, "Can not find serializer"])
|
||||
return
|
||||
|
||||
self.reconnection_token = str(room_id, ":", token)
|
||||
_has_joined = true
|
||||
on_join.emit()
|
||||
send_raw([CODE_JOIN_ROOM])
|
||||
CODE_ERROR:
|
||||
var message = decoder.read_utf8()
|
||||
on_error.emit([0, message])
|
||||
CODE_LEAVE_ROOM:
|
||||
leave()
|
||||
CODE_ROOM_DATA:
|
||||
var type
|
||||
if decoder.is_number():
|
||||
type = str('i', decoder.number())
|
||||
else:
|
||||
type = decoder.read_utf8()
|
||||
|
||||
var listener = on_message(type, false)
|
||||
if listener != null:
|
||||
var ret = decoder.unpack()
|
||||
if ret == null:
|
||||
ret = {}
|
||||
listener.emit([ret])
|
||||
|
||||
CODE_ROOM_STATE:
|
||||
serializer.set_state(decoder)
|
||||
on_state_change.emit([serializer.get_state()])
|
||||
CODE_ROOM_STATE_PATCH:
|
||||
serializer.patch(decoder)
|
||||
on_state_change.emit([serializer.get_state()])
|
||||
CODE_ROOM_DATA_SCHEMA:
|
||||
print("Receive message CODE_ROOM_DATA_SCHEMA")
|
||||
|
||||
func connect_remote(url: String):
|
||||
var _url = url
|
||||
if url.begins_with("http:"):
|
||||
_url = url.replace("http:", "ws:")
|
||||
elif url.begins_with("https:"):
|
||||
_url = url.replace("https:", "wss:")
|
||||
#_url = _url.replace("/colyseus", "")
|
||||
ws.connect_to_url(_url)
|
||||
frame_runner.start()
|
||||
|
||||
func _on_frame():
|
||||
ws.poll()
|
||||
var state = ws.get_ready_state()
|
||||
match state:
|
||||
WebSocketPeer.STATE_OPEN:
|
||||
while ws.get_available_packet_count() > 0:
|
||||
_on_data()
|
||||
WebSocketPeer.STATE_CLOSED:
|
||||
var code = ws.get_close_code()
|
||||
var reason = ws.get_close_reason()
|
||||
_connection_closed(true)
|
||||
if _has_joined:
|
||||
leave()
|
||||
|
||||
func send_raw(bytes: PackedByteArray):
|
||||
ws.send(bytes)
|
||||
|
||||
func send(type: String, message = null):
|
||||
var buffer = StreamPeerBuffer.new()
|
||||
buffer.put_u8(CODE_ROOM_DATA)
|
||||
var encoder = Encoder.new(buffer)
|
||||
|
||||
if typeof(type) == TYPE_STRING:
|
||||
encoder.string(type)
|
||||
else:
|
||||
encoder.number(type)
|
||||
|
||||
if message != null:
|
||||
var result = MsgPack.encode(message, buffer)
|
||||
assert(result.error == OK)
|
||||
|
||||
send_raw(buffer.data_array)
|
||||
|
||||
func leave(consented = true):
|
||||
_has_joined = false
|
||||
if not room_id.is_empty():
|
||||
if consented:
|
||||
send_raw([CODE_LEAVE_ROOM])
|
||||
else:
|
||||
ws.disconnect_from_host()
|
||||
on_leave.emit()
|
||||
|
||||
var state : Schema : get = get_state
|
||||
func get_state() -> Schema:
|
||||
return serializer.get_state()
|
||||
1
addons/godot_colyseus/lib/room.gd.uid
Normal file
1
addons/godot_colyseus/lib/room.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://jpi6ohybugst
|
||||
18
addons/godot_colyseus/lib/room_info.gd
Normal file
18
addons/godot_colyseus/lib/room_info.gd
Normal file
@@ -0,0 +1,18 @@
|
||||
extends RefCounted
|
||||
|
||||
var clients: int
|
||||
var created_at: String
|
||||
var max_clients: int
|
||||
var name: String
|
||||
var process_id: String
|
||||
var room_id: String
|
||||
|
||||
func _init(dic):
|
||||
clients = dic.get('clients')
|
||||
created_at = dic.get('createdAt')
|
||||
var num = dic.get('maxClients')
|
||||
if num != null:
|
||||
max_clients = num
|
||||
name = dic.get('name')
|
||||
process_id = dic.get('processId')
|
||||
room_id = dic.get('roomId')
|
||||
1
addons/godot_colyseus/lib/room_info.gd.uid
Normal file
1
addons/godot_colyseus/lib/room_info.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b8wn1vytiodw3
|
||||
308
addons/godot_colyseus/lib/schema.gd
Normal file
308
addons/godot_colyseus/lib/schema.gd
Normal file
@@ -0,0 +1,308 @@
|
||||
extends "./schema_interface.gd"
|
||||
|
||||
const col = preload("res://addons/godot_colyseus/lib/collections.gd")
|
||||
const OP = preload("res://addons/godot_colyseus/lib/operations.gd")
|
||||
const TypeInfo = preload("res://addons/godot_colyseus/lib/type_info.gd")
|
||||
|
||||
const END_OF_STRUCTURE = 0xc1
|
||||
const NIL = 0xc0
|
||||
const INDEX_CHANGE = 0xd4
|
||||
|
||||
const Decoder = preload("res://addons/godot_colyseus/lib/decoder.gd")
|
||||
const EventListener = preload("res://addons/godot_colyseus/lib/listener.gd")
|
||||
const SchemaInterface = preload("res://addons/godot_colyseus/lib/schema_interface.gd")
|
||||
|
||||
class Field:
|
||||
const Types = preload("res://addons/godot_colyseus/lib/types.gd")
|
||||
var index: int
|
||||
var name: String
|
||||
var value
|
||||
var current_type: TypeInfo
|
||||
|
||||
func _init(name: String,type: String,schema_type = null):
|
||||
current_type = TypeInfo.new(type)
|
||||
if schema_type is String:
|
||||
current_type.sub_type = TypeInfo.new(schema_type)
|
||||
elif schema_type is GDScript:
|
||||
if type == Types.REF:
|
||||
current_type.sub_type = schema_type
|
||||
else:
|
||||
current_type.sub_type = TypeInfo.new(Types.REF, schema_type)
|
||||
elif schema_type is TypeInfo:
|
||||
current_type.sub_type = schema_type
|
||||
self.name = name
|
||||
|
||||
func _to_string():
|
||||
if current_type:
|
||||
return current_type.to_string()
|
||||
else:
|
||||
return 'null'
|
||||
|
||||
var _fields: Array = []
|
||||
var _field_index = {}
|
||||
|
||||
var _refs = {}
|
||||
|
||||
var _change_listeners = {}
|
||||
|
||||
func _get_property_list():
|
||||
var result = []
|
||||
for field in _fields:
|
||||
result.append({
|
||||
name = field.name,
|
||||
type = Types.to_gd_type(field.current_type.type),
|
||||
usage = PROPERTY_USAGE_DEFAULT
|
||||
})
|
||||
return result
|
||||
|
||||
func _get(property):
|
||||
if _field_index.has(property):
|
||||
var value = _field_index[property].value
|
||||
if value is SchemaInterface:
|
||||
pass
|
||||
return value
|
||||
return null
|
||||
|
||||
func _set(property, value):
|
||||
if _field_index.has(property):
|
||||
var field = _field_index[property]
|
||||
var old = field.value
|
||||
if old is SchemaInterface:
|
||||
pass
|
||||
field.value = value
|
||||
return true
|
||||
return false
|
||||
|
||||
# [event: String, target, key_or_index]
|
||||
# path format {path}:{action}
|
||||
# {action} is one of:
|
||||
# add Create sub object, paramaters [current, new_value, key]
|
||||
# remove Delete sub object, paramaters [current, old_value, key]
|
||||
# replace Replace sub object, paramaters [current, new_value, key]
|
||||
# delete Current object is deleted, paramaters [current]
|
||||
# create Current object is created, paramaters [current]
|
||||
# change Current object's attributes has changed, paramaters [current]
|
||||
# clear Current Array or Map has cleared, paramaters [current]
|
||||
func listen(path: String) -> EventListener:
|
||||
if not _change_listeners.has(path):
|
||||
_change_listeners[path] = EventListener.new()
|
||||
return _change_listeners[path]
|
||||
|
||||
static func define_fields() -> Array:
|
||||
return []
|
||||
|
||||
func _init():
|
||||
_fields = self.get_script().define_fields()
|
||||
var counter = 0
|
||||
for field in _fields:
|
||||
field.index = counter
|
||||
_setup_field(field)
|
||||
counter += 1
|
||||
|
||||
func _setup_field(field: Field):
|
||||
_field_index[field.name] = field
|
||||
var type = field.current_type
|
||||
match type.type:
|
||||
Types.MAP:
|
||||
assert(type.sub_type != null) #,"Schema type is requested")
|
||||
Types.ARRAY:
|
||||
assert(type.sub_type != null) #,"Schema type is requested")
|
||||
field.value = col.Collection.new()
|
||||
Types.SET:
|
||||
assert(type.sub_type != null) #,"Schema type is requested")
|
||||
Types.COLLECTION:
|
||||
assert(type.sub_type != null) #,"Schema type is requested")
|
||||
Types.REF:
|
||||
assert(type.sub_type != null) #,"Schema type is requested")
|
||||
Types.NUMBER, Types.FLOAT32, Types.FLOAT64:
|
||||
field.value = 0.0
|
||||
Types.INT8, Types.UINT8, Types.INT16, Types.UINT16, Types.INT32, Types.UINT32, Types.INT64, Types.UINT64:
|
||||
field.value = 0
|
||||
Types.STRING:
|
||||
field.value = ""
|
||||
|
||||
func get_fields():
|
||||
return _fields
|
||||
|
||||
func decode(decoder: Decoder) -> int:
|
||||
|
||||
var ref_id = 0
|
||||
var ref: Ref = Ref.new(self, TypeInfo.new(Types.REF))
|
||||
_refs[ref_id] = ref
|
||||
var changes = []
|
||||
var changed_objects = {}
|
||||
|
||||
while decoder.has_more():
|
||||
var byte = decoder.reader.get_u8()
|
||||
|
||||
if byte == OP.SWITCH_TO_STRUCTURE:
|
||||
ref_id = decoder.number()
|
||||
|
||||
var next_ref = _refs[ref_id]
|
||||
|
||||
assert(next_ref != null) #,str('"refId" not found:', ref_id))
|
||||
|
||||
ref = next_ref
|
||||
|
||||
continue
|
||||
|
||||
var is_schema = ref.type_info.type == Types.REF
|
||||
|
||||
var operation = byte
|
||||
if is_schema:
|
||||
operation = (byte >> 6) << 6
|
||||
|
||||
|
||||
if operation == OP.CLEAR:
|
||||
ref.value.clear(true)
|
||||
if ref.value is SchemaInterface:
|
||||
changes.append({
|
||||
target = ref.value,
|
||||
event = "clear",
|
||||
argv = []
|
||||
})
|
||||
continue
|
||||
|
||||
var field_index = byte % _re_replace(operation)
|
||||
if not is_schema:
|
||||
field_index = decoder.number()
|
||||
|
||||
var ref_value = ref.value
|
||||
if ref_value is SchemaInterface:
|
||||
var old = ref_value.meta_get(field_index)
|
||||
var new
|
||||
var key = field_index
|
||||
if ref.type_info.type != Types.MAP:
|
||||
key = ref_value.meta_get_key(field_index)
|
||||
|
||||
if operation == OP.DELETE:
|
||||
if ref.type_info.type == Types.MAP:
|
||||
key = ref_value.meta_get_key(field_index)
|
||||
ref_value.meta_remove(field_index)
|
||||
else:
|
||||
if ref.type_info.type == Types.MAP:
|
||||
key = decoder.read_utf8()
|
||||
var type: TypeInfo = ref_value.meta_get_subtype(field_index)
|
||||
if type.is_schema_type():
|
||||
var new_ref_id = decoder.number()
|
||||
if _refs.has(new_ref_id):
|
||||
new = _refs[new_ref_id].value
|
||||
else:
|
||||
if operation != OP.REPLACE:
|
||||
new = type.create()
|
||||
new.id = new_ref_id
|
||||
_refs[new_ref_id] = Ref.new(new, type)
|
||||
else:
|
||||
new = type.decode(decoder)
|
||||
|
||||
if old != new:
|
||||
if old == null:
|
||||
changes.append({
|
||||
target = ref_value,
|
||||
event = "add",
|
||||
argv = [new, key]
|
||||
})
|
||||
elif new == null:
|
||||
changes.append({
|
||||
target = ref_value,
|
||||
event = "remove",
|
||||
argv = [old, key]
|
||||
})
|
||||
else:
|
||||
changes.append({
|
||||
target = ref_value,
|
||||
event = "replace",
|
||||
argv = [new, key]
|
||||
})
|
||||
|
||||
if old != null:
|
||||
if old is SchemaInterface && old.id != null:
|
||||
changes.append({
|
||||
target = old,
|
||||
event = "delete",
|
||||
argv = []
|
||||
})
|
||||
_refs.erase(old.id)
|
||||
|
||||
if new != null:
|
||||
ref_value.meta_set(field_index, key, new)
|
||||
if new is SchemaInterface:
|
||||
changes.append({
|
||||
target = new,
|
||||
event = "create",
|
||||
argv = []
|
||||
})
|
||||
new.set_parent(ref_value, field_index)
|
||||
elif old != null:
|
||||
ref_value.meta_remove(field_index)
|
||||
|
||||
changed_objects[ref_value] = true
|
||||
|
||||
for change in changes:
|
||||
var target = change.target
|
||||
target.trigger(change.event, change.argv)
|
||||
|
||||
for target in changed_objects.keys():
|
||||
target.trigger("change", [])
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
func _re_replace(operation):
|
||||
if operation == OP.REPLACE:
|
||||
return 255
|
||||
return operation
|
||||
|
||||
func clear(decoding: bool = false):
|
||||
pass
|
||||
|
||||
func meta_get(index):
|
||||
assert(_fields.size() > index)
|
||||
var field : Field = _fields[index]
|
||||
return field.value
|
||||
|
||||
func meta_get_key(index):
|
||||
assert(_fields.size() > index)
|
||||
var field : Field = _fields[index]
|
||||
return field.name
|
||||
|
||||
func meta_get_subtype(index):
|
||||
assert(_fields.size() > index)
|
||||
var field : Field = _fields[index]
|
||||
return field.current_type
|
||||
|
||||
func meta_set(index, key, value):
|
||||
assert(_fields.size() > index)
|
||||
var field : Field = _fields[index]
|
||||
field.value = value
|
||||
|
||||
func meta_remove(index):
|
||||
assert(_fields.size() > index)
|
||||
var field : Field = _fields[index]
|
||||
var old = field.value
|
||||
field.value = null
|
||||
return old
|
||||
|
||||
func _to_string():
|
||||
var obj = to_object()
|
||||
return JSON.stringify(obj)
|
||||
|
||||
func trigger(event: String, argv: Array = [], path: PackedStringArray = PackedStringArray(), target: Object = self):
|
||||
var path_copy = PackedStringArray(path)
|
||||
path_copy.reverse()
|
||||
var path_str = '/'.join(path_copy) + ":" + event
|
||||
if _change_listeners.has(path_str):
|
||||
var ls: EventListener = _change_listeners[path_str]
|
||||
argv.insert(0, target)
|
||||
ls.emit(argv)
|
||||
else:
|
||||
super.trigger(event, argv, path, target)
|
||||
|
||||
func to_object():
|
||||
var dic = {}
|
||||
for field in _fields:
|
||||
if field.value is SchemaInterface:
|
||||
dic[field.name] = field.value.to_object()
|
||||
else:
|
||||
dic[field.name] = field.value
|
||||
return dic
|
||||
1
addons/godot_colyseus/lib/schema.gd.uid
Normal file
1
addons/godot_colyseus/lib/schema.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://vujiy070i53c
|
||||
54
addons/godot_colyseus/lib/schema_interface.gd
Normal file
54
addons/godot_colyseus/lib/schema_interface.gd
Normal file
@@ -0,0 +1,54 @@
|
||||
extends RefCounted
|
||||
|
||||
const Types = preload("res://addons/godot_colyseus/lib/types.gd")
|
||||
|
||||
class Ref:
|
||||
var value
|
||||
var type_info
|
||||
|
||||
func _init(value,type_info):
|
||||
self.value = value
|
||||
self.type_info = type_info
|
||||
|
||||
var id
|
||||
var parent
|
||||
var parent_index: int
|
||||
var parent_key
|
||||
|
||||
func clear(decoding: bool = false):
|
||||
assert(false)
|
||||
|
||||
func meta_get(index):
|
||||
assert(false)
|
||||
|
||||
func meta_get_key(index) -> String:
|
||||
assert(false)
|
||||
return ""
|
||||
|
||||
func meta_get_subtype(index):
|
||||
assert(false)
|
||||
|
||||
func meta_set(index, key, value):
|
||||
assert(false)
|
||||
return null
|
||||
|
||||
func meta_remove(index):
|
||||
assert(false)
|
||||
|
||||
func set_parent(np, pindex):
|
||||
if parent == np and parent_index == pindex:
|
||||
return
|
||||
if parent != null:
|
||||
parent.meta_remove(parent_index)
|
||||
parent = np
|
||||
parent_index = pindex
|
||||
parent_key = parent.meta_get_key(parent_index)
|
||||
|
||||
func trigger(event: String, argv: Array = [], path: PackedStringArray = PackedStringArray(), target: Object = self):
|
||||
if parent == null:
|
||||
return
|
||||
path.append(parent_key)
|
||||
parent.trigger(event, argv, path, target)
|
||||
|
||||
func to_object():
|
||||
return "<null>"
|
||||
1
addons/godot_colyseus/lib/schema_interface.gd.uid
Normal file
1
addons/godot_colyseus/lib/schema_interface.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://7hqsu5vttoy2
|
||||
113
addons/godot_colyseus/lib/serializer.gd
Normal file
113
addons/godot_colyseus/lib/serializer.gd
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
extends RefCounted
|
||||
|
||||
const Schema = preload("res://addons/godot_colyseus/lib/schema.gd")
|
||||
const Decoder = preload("res://addons/godot_colyseus/lib/decoder.gd")
|
||||
const Types = preload("res://addons/godot_colyseus/lib/types.gd")
|
||||
|
||||
class Serializer:
|
||||
|
||||
func set_state(decoder):
|
||||
pass
|
||||
|
||||
func get_state():
|
||||
pass
|
||||
|
||||
func patch(decoder):
|
||||
pass
|
||||
|
||||
func teardown():
|
||||
pass
|
||||
|
||||
func handshake(decoder):
|
||||
pass
|
||||
|
||||
|
||||
class NoneSerializer extends Serializer:
|
||||
pass
|
||||
|
||||
class ReflectionField extends Schema:
|
||||
|
||||
static func define_fields():
|
||||
return [
|
||||
Schema.Field.new("name", Schema.Types.STRING),
|
||||
Schema.Field.new("type", Schema.Types.STRING),
|
||||
Schema.Field.new("referenced_type", Schema.Types.NUMBER),
|
||||
]
|
||||
|
||||
func test(field, reflection: Reflection) -> bool:
|
||||
if self.type != field.current_type.to_string() or self.name != field.name:
|
||||
var str1 = str(field.name, '-', self.name)
|
||||
var str2 = str(field.current_type, '-', self.type)
|
||||
printerr("Field not match ", str1, " : ", str2)
|
||||
return false
|
||||
if self.type == Schema.Types.REF:
|
||||
var type = reflection.types.at(self.referenced_type)
|
||||
return type.test(field.schema_type, reflection)
|
||||
return true
|
||||
|
||||
class ReflectionType extends Schema:
|
||||
|
||||
static func define_fields():
|
||||
return [
|
||||
Schema.Field.new("id", Schema.Types.NUMBER),
|
||||
Schema.Field.new("extendsId", Schema.Types.NUMBER),
|
||||
Schema.Field.new("fields", Schema.Types.ARRAY, ReflectionField),
|
||||
]
|
||||
|
||||
func test(schema_type, reflection: Reflection) -> bool:
|
||||
if not schema_type is GDScript:
|
||||
printerr("Type schema_type not match ", self.id)
|
||||
return false
|
||||
var fields = schema_type.define_fields()
|
||||
var length = fields.size()
|
||||
if length != self.fields.size():
|
||||
printerr("Type fields count not match ", self.id)
|
||||
return false
|
||||
for i in range(length):
|
||||
var field = self.fields.at(i)
|
||||
if not field.test(fields[i], reflection):
|
||||
return false
|
||||
return true
|
||||
|
||||
class Reflection extends Schema:
|
||||
|
||||
static func define_fields():
|
||||
return [
|
||||
Schema.Field.new("types", Schema.Types.ARRAY, ReflectionType),
|
||||
Schema.Field.new("root_type", Schema.Types.NUMBER),
|
||||
]
|
||||
|
||||
func test(schema_type: GDScript) -> bool:
|
||||
return self.types.at(self.root_type).test(schema_type, self)
|
||||
|
||||
class SchemaSerializer extends Serializer:
|
||||
var state
|
||||
var schema_type: GDScript
|
||||
|
||||
func _init(schema_type):
|
||||
self.schema_type = schema_type
|
||||
self.state = schema_type.new()
|
||||
|
||||
func handshake(decoder):
|
||||
var reflection = Reflection.new()
|
||||
reflection.decode(decoder)
|
||||
assert(reflection.test(schema_type),"Can not detect schema type")
|
||||
|
||||
func set_state(decoder):
|
||||
state.decode(decoder)
|
||||
|
||||
func get_state():
|
||||
return state
|
||||
|
||||
func patch(decoder):
|
||||
state.decode(decoder)
|
||||
|
||||
|
||||
static func getSerializer(id: String, schema_type: GDScript = null) -> Serializer:
|
||||
match id:
|
||||
"schema":
|
||||
return SchemaSerializer.new(schema_type)
|
||||
"none":
|
||||
return NoneSerializer.new()
|
||||
return null
|
||||
1
addons/godot_colyseus/lib/serializer.gd.uid
Normal file
1
addons/godot_colyseus/lib/serializer.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dsp61m3okjbm
|
||||
97
addons/godot_colyseus/lib/type_info.gd
Normal file
97
addons/godot_colyseus/lib/type_info.gd
Normal file
@@ -0,0 +1,97 @@
|
||||
extends Object
|
||||
|
||||
const Decoder = preload("res://addons/godot_colyseus/lib/decoder.gd")
|
||||
const types = preload("res://addons/godot_colyseus/lib/types.gd")
|
||||
const collections = preload("res://addons/godot_colyseus/lib/collections.gd")
|
||||
|
||||
var type: String
|
||||
var sub_type
|
||||
|
||||
func _init(type: String,sub_type = null):
|
||||
self.type = type
|
||||
self.sub_type = sub_type
|
||||
|
||||
func is_schema_type():
|
||||
return type == types.REF or type == types.MAP or type == types.ARRAY or type == types.COLLECTION or type == types.SET
|
||||
|
||||
func _to_string():
|
||||
var ret = type
|
||||
if sub_type and sub_type.type != types.REF:
|
||||
ret = str(ret, ':', sub_type.type)
|
||||
return ret
|
||||
|
||||
func create():
|
||||
match type:
|
||||
types.REF:
|
||||
return sub_type.new()
|
||||
types.MAP:
|
||||
var obj = collections.MapSchema.new()
|
||||
obj.sub_type = sub_type
|
||||
return obj
|
||||
types.ARRAY:
|
||||
var obj = collections.ArraySchema.new()
|
||||
obj.sub_type = sub_type
|
||||
return obj
|
||||
types.SET:
|
||||
var obj = collections.SetSchema.new()
|
||||
obj.sub_type = sub_type
|
||||
return obj
|
||||
types.COLLECTION:
|
||||
var obj = collections.CollectionSchema.new()
|
||||
obj.sub_type = sub_type
|
||||
return obj
|
||||
|
||||
func decode(decoder: Decoder):
|
||||
match type:
|
||||
types.REF:
|
||||
var obj = sub_type.new()
|
||||
obj.id = decoder.number()
|
||||
return obj
|
||||
types.MAP:
|
||||
var obj = collections.MapSchema.new()
|
||||
obj.id = decoder.number()
|
||||
obj.sub_type = sub_type
|
||||
return obj
|
||||
types.ARRAY:
|
||||
var obj = collections.ArraySchema.new()
|
||||
obj.id = decoder.number()
|
||||
obj.sub_type = sub_type
|
||||
return obj
|
||||
types.SET:
|
||||
var obj = collections.SetSchema.new()
|
||||
obj.id = decoder.number()
|
||||
obj.sub_type = sub_type
|
||||
return obj
|
||||
types.COLLECTION:
|
||||
var obj = collections.CollectionSchema.new()
|
||||
obj.id = decoder.number()
|
||||
obj.sub_type = sub_type
|
||||
return obj
|
||||
types.STRING:
|
||||
return decoder.read_utf8()
|
||||
types.NUMBER:
|
||||
return decoder.number()
|
||||
types.BOOLEAN:
|
||||
return decoder.reader.get_u8() > 0
|
||||
types.INT8:
|
||||
return decoder.reader.get_8()
|
||||
types.UINT8:
|
||||
return decoder.reader.get_u8()
|
||||
types.INT16:
|
||||
return decoder.reader.get_16()
|
||||
types.UINT16:
|
||||
return decoder.reader.get_u16()
|
||||
types.INT32:
|
||||
return decoder.reader.get_32()
|
||||
types.UINT32:
|
||||
return decoder.reader.get_u32()
|
||||
types.INT64:
|
||||
return decoder.reader.get_64()
|
||||
types.UINT64:
|
||||
return decoder.reader.get_u64()
|
||||
types.FLOAT32:
|
||||
return decoder.reader.get_float()
|
||||
types.FLOAT64:
|
||||
return decoder.reader.get_double()
|
||||
_:
|
||||
assert(true) #,str("Unkown support type:", type))
|
||||
1
addons/godot_colyseus/lib/type_info.gd.uid
Normal file
1
addons/godot_colyseus/lib/type_info.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bga0qc00bmx6a
|
||||
42
addons/godot_colyseus/lib/types.gd
Normal file
42
addons/godot_colyseus/lib/types.gd
Normal file
@@ -0,0 +1,42 @@
|
||||
extends Object
|
||||
|
||||
const REF = "ref"
|
||||
const MAP = "map"
|
||||
const ARRAY = "array"
|
||||
const SET = "set"
|
||||
const COLLECTION = "collection"
|
||||
const STRING = "string"
|
||||
const NUMBER = "number"
|
||||
const BOOLEAN = "boolean"
|
||||
const INT8 = "int8"
|
||||
const UINT8 = "uint8"
|
||||
const INT16 = "int16"
|
||||
const UINT16 = "uint16"
|
||||
const INT32 = "int32"
|
||||
const UINT32 = "uint32"
|
||||
const INT64 = "int64"
|
||||
const UINT64 = "uint64"
|
||||
const FLOAT32 = "float32"
|
||||
const FLOAT64 = "float64"
|
||||
|
||||
static func to_gd_type(type: String) -> int:
|
||||
match type:
|
||||
REF:
|
||||
return TYPE_OBJECT
|
||||
MAP:
|
||||
return TYPE_OBJECT
|
||||
ARRAY:
|
||||
return TYPE_OBJECT
|
||||
SET:
|
||||
return TYPE_OBJECT
|
||||
COLLECTION:
|
||||
return TYPE_OBJECT
|
||||
STRING:
|
||||
return TYPE_STRING
|
||||
NUMBER, FLOAT32, FLOAT64:
|
||||
return TYPE_FLOAT
|
||||
BOOLEAN:
|
||||
return TYPE_BOOL
|
||||
INT8, UINT8, INT16, UINT16, INT32, UINT32, INT64, UINT64:
|
||||
return TYPE_INT
|
||||
return TYPE_NIL
|
||||
1
addons/godot_colyseus/lib/types.gd.uid
Normal file
1
addons/godot_colyseus/lib/types.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cgnlylx00jd6k
|
||||
7
addons/godot_colyseus/plugin.cfg
Normal file
7
addons/godot_colyseus/plugin.cfg
Normal file
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="godot-colyseus"
|
||||
description=""
|
||||
author="gsioteam"
|
||||
version="0.1.0"
|
||||
script="init.gd"
|
||||
Reference in New Issue
Block a user