├── .gitignore
├── CONTRIBUTORS.md
├── LICENSE
├── README.md
├── engine.cfg
├── lib
├── ReadWriteLock.gd
├── shared
│ ├── client.gd
│ ├── constants.gd
│ └── server.gd
├── tcp
│ ├── client.gd
│ └── server.gd
└── udp
│ ├── client.gd
│ └── server.gd
└── preview
├── client_tab.gd
├── client_tab.xscn
├── index.xscn
├── preview.gd
├── res
└── FiraMono-Medium.fnt
├── server_tab.gd
└── server_tab.xscn
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dolphin generates this file, not needed
2 | .directory
3 |
4 | # Some text editors
5 | *~
6 |
7 | # Temporary test-related files
8 | tmp.*
9 |
--------------------------------------------------------------------------------
/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | ## Thanks to:
2 | - Mozilla - for making the Fira font family, which is used in the test sample.
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 KOBUGE-Games
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # godot-networking-module
2 | KOBUGE's Godot networking library
3 |
4 | [docs](https://github.com/KOBUGE-Games/godot-networking-module/wiki)
5 |
6 |
--------------------------------------------------------------------------------
/engine.cfg:
--------------------------------------------------------------------------------
1 | [application]
2 |
3 | name="Multiplayer"
4 | main_scene="res://preview/index.xscn"
5 |
--------------------------------------------------------------------------------
/lib/ReadWriteLock.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Reference
3 |
4 | var write_lock = Mutex.new()
5 | var read_lock = Mutex.new()
6 | var read_count = 0
7 |
8 | func lock_write():
9 | write_lock.lock()
10 |
11 | func unlock_write():
12 | write_lock.unlock()
13 |
14 | func lock_read():
15 | read_lock.lock()
16 | read_count += 1
17 | if read_count == 1:
18 | write_lock.lock()
19 | read_lock.unlock()
20 |
21 | func unlock_read():
22 | read_lock.lock()
23 | read_count -= 1
24 | if read_count == 0:
25 | write_lock.unlock()
26 | read_lock.unlock()
27 |
28 |
29 |
--------------------------------------------------------------------------------
/lib/shared/client.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Reference
3 |
4 | const ReadWriteLock = preload("../ReadWriteLock.gd")
5 | const constants = preload("constants.gd")
6 |
7 | signal connect()
8 | signal disconnect()
9 | signal message(message)
10 |
11 | var connection
12 | var M_connection = Mutex.new()
13 |
14 | var message_queue = []
15 | var _internal_message_queue = []
16 | var M_message_queue = Mutex.new()
17 |
18 | var running
19 | var M_running = Mutex.new()
20 |
21 | var loop_thread = Thread.new()
22 |
23 | func _start_connection(host, port):
24 | pass # Virtual
25 |
26 | func _stop_connection():
27 | pass # Virtual
28 |
29 | func _update_connection():
30 | pass # Virtual
31 |
32 | func _send_messages(messages):
33 | pass # Virtual
34 |
35 | func connect_to(host, port):
36 | M_running.lock()
37 | if not running:
38 | M_connection.lock()
39 |
40 | running = true
41 | _start_connection(host, port)
42 | loop_thread.start(self, "loop")
43 |
44 | M_connection.unlock()
45 |
46 | M_running.unlock()
47 |
48 | func send(message):
49 | M_message_queue.lock()
50 |
51 | message_queue.push_back(message)
52 |
53 | M_message_queue.unlock()
54 |
55 | func _send_internal(message):
56 | _internal_message_queue.push_back(message)
57 |
58 | func stop():
59 | M_running.lock()
60 |
61 | running = false
62 |
63 | M_running.unlock()
64 |
65 | loop_thread.wait_to_finish()
66 |
67 | func loop(data):
68 | while true:
69 | M_connection.lock()
70 |
71 | M_running.lock()
72 | if not running:
73 | M_running.unlock()
74 |
75 | _stop_connection()
76 |
77 | M_connection.unlock()
78 | break;
79 | else:
80 | M_running.unlock()
81 |
82 | _update_connection()
83 |
84 | M_message_queue.lock()
85 |
86 | var _messages = message_queue
87 | message_queue = []
88 |
89 | M_message_queue.unlock()
90 |
91 | _send_messages(_messages)
92 |
93 | _messages = _internal_message_queue
94 | _internal_message_queue = []
95 | _send_messages(_messages)
96 |
97 | M_connection.unlock()
98 | OS.delay_msec(constants.TICK_TIME)
99 |
--------------------------------------------------------------------------------
/lib/shared/constants.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Reference
3 |
4 | const TICK_TIME = 100
5 |
6 | const UDP_COMMAND = "__$COMMAND$__"
7 | const UDP_TIMEOUT = 5*1000
8 | const UDP_SEND_ACK = 500
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/shared/server.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Reference
3 |
4 | const ReadWriteLock = preload("../ReadWriteLock.gd")
5 | const constants = preload("constants.gd")
6 |
7 | class RawMessage:
8 | var target = null
9 | var data = {}
10 |
11 | signal connect(id)
12 | signal disconnect(id)
13 | signal message(id, message)
14 |
15 | var server
16 | var M_server = Mutex.new()
17 |
18 | var running = false
19 | var M_running = Mutex.new()
20 |
21 | var connections = {}
22 | var next_id = 0
23 | var RW_connections = ReadWriteLock.new()
24 |
25 | var message_queue = []
26 | var _internal_message_queue = []
27 | var M_message_queue = Mutex.new()
28 |
29 | var loop_thread = Thread.new()
30 |
31 | func _start_server(port):
32 | pass # Virtual
33 |
34 | func _stop_server():
35 | pass # Virtual
36 |
37 | func _update_connections():
38 | pass # Virtual
39 |
40 | func _send_messages(messages):
41 | pass # Virtual
42 |
43 | func start(port):
44 | M_running.lock()
45 | if not running:
46 | M_server.lock()
47 |
48 | running = true
49 | _start_server(port)
50 | loop_thread.start(self, "loop")
51 |
52 | M_server.unlock()
53 |
54 | M_running.unlock()
55 |
56 | func send_to(id, data):
57 | var message = RawMessage.new()
58 | message.target = id
59 | message.data = data
60 |
61 | M_message_queue.lock()
62 |
63 | message_queue.push_back(message)
64 |
65 | M_message_queue.unlock()
66 |
67 | func send_to_all(data):
68 | var message = RawMessage.new()
69 | message.data = data
70 |
71 | M_message_queue.lock()
72 |
73 | message_queue.push_back(message)
74 |
75 | M_message_queue.unlock()
76 |
77 | func _send_internal(id, data):
78 | var message = RawMessage.new()
79 | message.target = id
80 | message.data = data
81 |
82 | _internal_message_queue.push_back(message)
83 |
84 | func stop():
85 | M_running.lock()
86 |
87 | running = false
88 |
89 | M_running.unlock()
90 |
91 | loop_thread.wait_to_finish()
92 |
93 | func loop(data):
94 | while true:
95 | M_server.lock()
96 |
97 | M_running.lock()
98 | if not running:
99 | M_running.unlock()
100 |
101 | _stop_server()
102 |
103 | M_server.unlock()
104 | break;
105 | else:
106 | M_running.unlock()
107 |
108 | RW_connections.lock_write()
109 |
110 | _update_connections()
111 |
112 | RW_connections.unlock_write()
113 |
114 | RW_connections.lock_read()
115 | M_message_queue.lock()
116 |
117 | var _messages = message_queue
118 | message_queue = []
119 |
120 | M_message_queue.unlock()
121 |
122 | _send_messages(_messages)
123 |
124 | _messages = _internal_message_queue
125 | _internal_message_queue = []
126 | _send_messages(_messages)
127 |
128 | RW_connections.unlock_read()
129 |
130 | M_server.unlock()
131 | OS.delay_msec(constants.TICK_TIME)
132 |
--------------------------------------------------------------------------------
/lib/tcp/client.gd:
--------------------------------------------------------------------------------
1 |
2 | extends "../shared/client.gd"
3 |
4 | const ReadWriteLock = preload("../ReadWriteLock.gd")
5 |
6 | class Connection:
7 | var stream
8 | var packet_peer
9 | var connected = false
10 | static func create(stream):
11 | var new_self = new()
12 | new_self.stream = stream
13 |
14 | new_self.packet_peer = PacketPeerStream.new()
15 | new_self.packet_peer.set_stream_peer(stream)
16 |
17 | return new_self
18 |
19 | func _start_connection(host, port):
20 | var stream = StreamPeerTCP.new()
21 | stream.connect(host, port)
22 |
23 | connection = Connection.create(stream)
24 |
25 | func _stop_connection():
26 | emit_signal("disconnect")
27 | connection.stream.disconnect()
28 | connection = null
29 |
30 | func _update_connection():
31 | var status = connection.stream.get_status()
32 |
33 | if status == StreamPeerTCP.STATUS_CONNECTED and not connection.connected:
34 | connection.connected = true
35 | emit_signal("connect")
36 | if status == StreamPeerTCP.STATUS_ERROR or status == StreamPeerTCP.STATUS_NONE and connection.connected:
37 | connection.connected = false
38 | emit_signal("disconnect")
39 |
40 | while connection.packet_peer.get_available_packet_count():
41 | emit_signal("message", connection.packet_peer.get_var())
42 |
43 | func _send_messages(messages):
44 | for message in messages:
45 | connection.packet_peer.put_var(message)
46 |
47 |
--------------------------------------------------------------------------------
/lib/tcp/server.gd:
--------------------------------------------------------------------------------
1 |
2 | extends "../shared/server.gd"
3 |
4 | class Connection:
5 | var id = -1
6 | var stream
7 | var packet_peer
8 | var connected = false
9 | static func create(id, stream):
10 | var new_self = new()
11 | new_self.id = id
12 | new_self.stream = stream
13 |
14 | new_self.packet_peer = PacketPeerStream.new()
15 | new_self.packet_peer.set_stream_peer(stream)
16 |
17 | return new_self
18 |
19 | func _init():
20 | server = TCP_Server.new()
21 |
22 | func _start_server(port):
23 | server.listen(port)
24 |
25 | func _stop_server():
26 | server.stop()
27 |
28 | func _update_connections():
29 | while server.is_connection_available():
30 | var stream = server.take_connection()
31 | var connection = Connection.create(next_id, stream)
32 |
33 | connections[next_id] = connection
34 | next_id += 1
35 |
36 | for id in connections:
37 | var connection = connections[id]
38 | var status = connection.stream.get_status()
39 |
40 | if status == StreamPeerTCP.STATUS_CONNECTED and not connection.connected:
41 | connection.connected = true
42 | emit_signal("connect", connection.id)
43 | if status == StreamPeerTCP.STATUS_ERROR or status == StreamPeerTCP.STATUS_NONE and connection.connected:
44 | connection.connected = false
45 | emit_signal("disconnect", connection.id)
46 | connections.erase(connection.id)
47 |
48 |
49 | while connection.packet_peer.get_available_packet_count():
50 | emit_signal("message", connection.id, connection.packet_peer.get_var())
51 |
52 | func _send_messages(messages):
53 | for message in messages:
54 | if message.target != null:
55 | if connections.has(message.target):
56 | connections[message.target].packet_peer.put_var(message.data)
57 | else:
58 | for id in connections:
59 | connections[id].packet_peer.put_var(message.data)
60 |
--------------------------------------------------------------------------------
/lib/udp/client.gd:
--------------------------------------------------------------------------------
1 |
2 | extends "../shared/client.gd"
3 |
4 | const ReadWriteLock = preload("../ReadWriteLock.gd")
5 |
6 | class Connection:
7 | var packet_peer
8 |
9 | var last_ack_sent = null
10 | var last_ack_received = null
11 |
12 | static func create(packet_peer):
13 | var new_self = new()
14 |
15 | new_self.packet_peer = packet_peer
16 |
17 | return new_self
18 |
19 | func _start_connection(host, port):
20 | var packet_peer = PacketPeerUDP.new()
21 | packet_peer.set_send_address(host, port)
22 | #_send_internal()
23 |
24 | connection = Connection.create(packet_peer)
25 |
26 | func _stop_connection():
27 | emit_signal("disconnect")
28 | connection.packet_peer.close()
29 | connection = null
30 |
31 | func _update_connection():
32 | var timestamp = OS.get_ticks_msec()
33 | # var status = connection.stream.get_status()
34 | #
35 | # if status == StreamPeerTCP.STATUS_CONNECTED and not connection.connected:
36 | # connection.connected = true
37 | # emit_signal("connect")
38 | # if status == StreamPeerTCP.STATUS_ERROR or status == StreamPeerTCP.STATUS_NONE and connection.connected:
39 | # connection.connected = false
40 | # emit_signal("disconnect")
41 |
42 | while connection.packet_peer.get_available_packet_count():
43 | var message = connection.packet_peer.get_var()
44 | if message.has(constants.UDP_COMMAND):
45 | var command = message[constants.UDP_COMMAND]
46 | if command == "ACK":
47 | if connection.last_ack_received == null:
48 | emit_signal("connect")
49 | connection.last_ack_received = timestamp
50 | else:
51 | emit_signal("message", message)
52 |
53 | if connection.last_ack_sent == null or timestamp - connection.last_ack_sent > constants.UDP_SEND_ACK:
54 | var ack = {}
55 | ack[constants.UDP_COMMAND] = "ACK"
56 | _send_internal(ack)
57 |
58 | connection.last_ack_sent = timestamp
59 |
60 | if connection.last_ack_recetived != null and timestamp - connection.last_ack_recetived > constants.UDP_TIMEOUT:
61 | emit_signal("disconnect")
62 |
63 | func _send_messages(messages):
64 | for message in messages:
65 | connection.packet_peer.put_var(message)
66 |
67 |
--------------------------------------------------------------------------------
/lib/udp/server.gd:
--------------------------------------------------------------------------------
1 |
2 | extends "../shared/server.gd"
3 |
4 | var address_id_map = {}
5 |
6 | class Connection:
7 | var id = -1
8 | var host
9 | var port
10 |
11 | var last_ack_received = null
12 | var last_ack_sent = null
13 |
14 | func _init(_id, _host, _port):
15 | id = _id
16 | host = _host
17 | port = _port
18 |
19 | func _init():
20 | server = PacketPeerUDP.new()
21 |
22 | func _start_server(port):
23 | server.listen(port)
24 |
25 | func _stop_server():
26 | server.close()
27 | address_id_map = {}
28 |
29 | func _update_connections():
30 | var timestamp = OS.get_ticks_msec()
31 | while server.get_available_packet_count():
32 | var host = server.get_packet_ip()
33 | var port = server.get_packet_port()
34 | var address = str(host, ":", port)
35 |
36 | if not address_id_map.has(address) or not connections.has(address_id_map[address]):
37 | print(address)
38 | var connection = Connection.new(next_id, host, port)
39 |
40 | address_id_map[address] = next_id
41 | connections[next_id] = connection
42 |
43 | next_id += 1
44 |
45 | var connection = connections[address_id_map[address]]
46 |
47 | var message = server.get_var()
48 |
49 | if message.has(constants.UDP_COMMAND):
50 | var command = message[constants.UDP_COMMAND]
51 | if command == "ACK":
52 | if connection.last_ack_received == null:
53 | emit_signal("connect", connection.id)
54 | connection.last_ack_received = timestamp
55 | else:
56 | emit_signal("message", connection.id, message)
57 |
58 | for id in connections:
59 | var connection = connections[id]
60 | if connection.last_ack_sent == null or timestamp - connection.last_ack_sent > constants.UDP_SEND_ACK:
61 | var ack = {}
62 | ack[constants.UDP_COMMAND] = "ACK"
63 | _send_internal(id, ack)
64 |
65 | connection.last_ack_sent = timestamp
66 |
67 | if connection.last_ack_received != null and timestamp - connection.last_ack_received > constants.UDP_TIMEOUT:
68 | var ack = {}
69 | ack[constants.UDP_COMMAND] = "ACK"
70 | _send_internal(id, ack)
71 | emit_signal("disconnect", id)
72 | connections.erase(id)
73 |
74 |
75 | func _send_messages(messages):
76 | for message in messages:
77 | if message.target != null:
78 | if connections.has(message.target):
79 | var connection = connections[message.target]
80 | server.set_send_address(connection.host, connection.port)
81 | server.put_var(message.data)
82 | else:
83 | for id in connections:
84 | var connection = connections[id]
85 | server.set_send_address(connection.host, connection.port)
86 | server.put_var(message.data)
87 |
--------------------------------------------------------------------------------
/preview/client_tab.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Control
3 |
4 | var client = preload("res://lib/udp/client.gd").new()
5 |
6 | func _ready():
7 | get_node("Buttons/Send").connect("pressed", self, "send")
8 | get_node("Buttons/Toggle").connect("toggled", self, "toggle")
9 |
10 | get_parent().prepare_results_console(get_node("Result"))
11 |
12 | client.connect("connect", self, "client_connected")
13 | client.connect("message", self, "new_message")
14 | client.connect("disconnect", self, "client_disconnected")
15 |
16 | func toggle(state):
17 | if state:
18 | get_node("Buttons/Toggle").set_text("Stop client")
19 | client.connect_to("127.0.0.1", 8760)
20 | add_result("Client is running!")
21 | else:
22 | get_node("Buttons/Toggle").set_text("Start client")
23 | add_result("Client stopped!")
24 | client.stop()
25 |
26 | func new_message(msg):
27 | add_result(str("Received: ", msg.to_json()))
28 |
29 | if msg.has("chat"):
30 | add_result(str("<", msg.from, "> : ", msg.chat))
31 |
32 | func send():
33 | var possible_messages = [
34 | {"get": "inventory"},
35 | {"action": "attack", "target": "rat-42"},
36 | {"action": "skill", "skill": "FireBall", "target": "snow_troll-3"},
37 | {"chat": "Hello Server!"}
38 | ]
39 | var msg = possible_messages[rand_range(0, possible_messages.size())]
40 | client.send(msg)
41 | add_result(str("Sent message: ", msg.to_json()))
42 |
43 | func client_connected():
44 | add_result("Connected!")
45 |
46 | func client_disconnected():
47 | add_result("Disconnected!")
48 |
49 | func add_result(result):
50 | get_node("Result").set_text(str(get_node("Result").get_text(), "\n", result))
51 |
--------------------------------------------------------------------------------
/preview/client_tab.xscn:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | "conn_count"
8 | 0
9 | "conns"
10 |
11 | "editable_instances"
12 |
13 |
14 | "names"
15 |
16 | "Client"
17 | "anchor/right"
18 | "anchor/bottom"
19 | "margin/left"
20 | "margin/top"
21 | "margin/right"
22 | "margin/bottom"
23 | "focus/ignore_mouse"
24 | "focus/stop_mouse"
25 | "size_flags/horizontal"
26 | "size_flags/vertical"
27 | "script/script"
28 | "__meta__"
29 | "Control"
30 | "Buttons"
31 | "rect/min_size"
32 | "Toggle"
33 | "toggle_mode"
34 | "text"
35 | "flat"
36 | "Button"
37 | "Send"
38 | "Result"
39 | "custom_fonts/font"
40 | "TextEdit"
41 |
42 | "node_count"
43 | 5
44 | "node_paths"
45 |
46 |
47 | "nodes"
48 | -1, -1, 13, 0, -1, 12, 1, 0, 2, 0, 3, 1, 4, 1, 5, 1, 6, 1, 7, 2, 8, 3, 9, 4, 10, 4, 11, 5, 12, 6, 0, 0, 0, 13, 14, -1, 7, 1, 0, 6, 7, 15, 8, 7, 2, 8, 3, 9, 4, 10, 4, 0, 1, 0, 20, 16, -1, 10, 1, 0, 6, 9, 15, 10, 7, 2, 8, 3, 9, 4, 10, 4, 17, 3, 18, 11, 19, 2, 0, 1, 0, 20, 21, -1, 11, 1, 0, 4, 12, 6, 13, 15, 10, 7, 2, 8, 3, 9, 4, 10, 4, 17, 2, 18, 14, 19, 2, 0, 0, 0, 24, 22, -1, 8, 1, 0, 2, 0, 4, 15, 7, 2, 8, 3, 9, 4, 10, 16, 23, 17, 0
49 | "variants"
50 |
51 | 1
52 | 4
53 | False
54 | True
55 | 2
56 |
57 |
58 | "__editor_plugin_screen__"
59 | "2D"
60 | "__editor_plugin_states__"
61 |
62 | "2D"
63 |
64 | "ofs"
65 | -1078.74, -345.453
66 | "snap_grid"
67 | False
68 | "snap_offset"
69 | 0, 0
70 | "snap_pixel"
71 | False
72 | "snap_relative"
73 | False
74 | "snap_rotation"
75 | False
76 | "snap_rotation_offset"
77 | 0
78 | "snap_rotation_step"
79 | 0.261799
80 | "snap_show_grid"
81 | False
82 | "snap_step"
83 | 10, 10
84 | "zoom"
85 | 0.54036
86 |
87 | "3D"
88 |
89 | "ambient_light_color"
90 | 0.15, 0.15, 0.15, 1
91 | "default_light"
92 | True
93 | "default_srgb"
94 | False
95 | "deflight_rot_x"
96 | 0.942478
97 | "deflight_rot_y"
98 | 0.628319
99 | "fov"
100 | 45
101 | "show_grid"
102 | True
103 | "show_origin"
104 | True
105 | "viewport_mode"
106 | 1
107 | "viewports"
108 |
109 |
110 | "distance"
111 | 4
112 | "listener"
113 | True
114 | "pos"
115 | 0, 0, 0
116 | "use_environment"
117 | False
118 | "use_orthogonal"
119 | False
120 | "x_rot"
121 | 0
122 | "y_rot"
123 | 0
124 |
125 |
126 | "distance"
127 | 4
128 | "listener"
129 | False
130 | "pos"
131 | 0, 0, 0
132 | "use_environment"
133 | False
134 | "use_orthogonal"
135 | False
136 | "x_rot"
137 | 0
138 | "y_rot"
139 | 0
140 |
141 |
142 | "distance"
143 | 4
144 | "listener"
145 | False
146 | "pos"
147 | 0, 0, 0
148 | "use_environment"
149 | False
150 | "use_orthogonal"
151 | False
152 | "x_rot"
153 | 0
154 | "y_rot"
155 | 0
156 |
157 |
158 | "distance"
159 | 4
160 | "listener"
161 | False
162 | "pos"
163 | 0, 0, 0
164 | "use_environment"
165 | False
166 | "use_orthogonal"
167 | False
168 | "x_rot"
169 | 0
170 | "y_rot"
171 | 0
172 |
173 |
174 | "zfar"
175 | 500
176 | "znear"
177 | 0.1
178 |
179 | "Anim"
180 |
181 | "visible"
182 | False
183 |
184 |
185 | "__editor_run_settings__"
186 |
187 | "custom_args"
188 | "-l $scene"
189 | "run_mode"
190 | 0
191 |
192 |
193 | 70
194 | 0, 70
195 | 32
196 | 128, 32
197 | "Start client"
198 | 36
199 | 68
200 | "Send message"
201 | 74
202 | 3
203 |
204 |
205 | "version"
206 | 2
207 |
208 |
209 |
210 |
--------------------------------------------------------------------------------
/preview/index.xscn:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | "conn_count"
7 | 0
8 | "conns"
9 |
10 | "editable_instances"
11 |
12 |
13 | "names"
14 |
15 | "Playground"
16 | "anchor/right"
17 | "anchor/bottom"
18 | "focus/ignore_mouse"
19 | "focus/stop_mouse"
20 | "size_flags/horizontal"
21 | "size_flags/vertical"
22 | "__meta__"
23 | "Control"
24 | "Tabs"
25 | "tab_align"
26 | "tabs_visible"
27 | "script/script"
28 | "symbol_color"
29 | "outgoing_color"
30 | "incoming_color"
31 | "TabContainer"
32 | "Add"
33 | "anchor/left"
34 | "margin/left"
35 | "margin/top"
36 | "margin/right"
37 | "margin/bottom"
38 | "toggle_mode"
39 | "click_on_press"
40 | "text"
41 | "flat"
42 | "items"
43 | "MenuButton"
44 |
45 | "node_count"
46 | 3
47 | "node_paths"
48 |
49 |
50 | "nodes"
51 | -1, -1, 8, 0, -1, 7, 1, 0, 2, 0, 3, 1, 4, 2, 5, 3, 6, 3, 7, 4, 0, 0, 0, 16, 9, -1, 12, 1, 0, 2, 0, 3, 1, 4, 2, 5, 3, 6, 3, 10, 0, 11, 2, 12, 5, 13, 6, 14, 7, 15, 8, 0, 0, 0, 28, 17, -1, 15, 18, 0, 1, 0, 19, 9, 20, 10, 21, 10, 22, 11, 3, 1, 4, 2, 5, 3, 6, 3, 23, 1, 24, 2, 25, 12, 26, 1, 27, 13, 0
52 | "variants"
53 |
54 | 1
55 | False
56 | True
57 | 2
58 |
59 | "__editor_plugin_screen__"
60 | "2D"
61 | "__editor_plugin_states__"
62 |
63 | "2D"
64 |
65 | "ofs"
66 | -374.285, -298.683
67 | "snap_grid"
68 | False
69 | "snap_offset"
70 | 0, 0
71 | "snap_pixel"
72 | False
73 | "snap_relative"
74 | False
75 | "snap_rotation"
76 | False
77 | "snap_rotation_offset"
78 | 0
79 | "snap_rotation_step"
80 | 0.261799
81 | "snap_show_grid"
82 | False
83 | "snap_step"
84 | 10, 10
85 | "zoom"
86 | 0.66342
87 |
88 | "3D"
89 |
90 | "ambient_light_color"
91 | 0.15, 0.15, 0.15, 1
92 | "default_light"
93 | True
94 | "default_srgb"
95 | False
96 | "deflight_rot_x"
97 | 0.942478
98 | "deflight_rot_y"
99 | 0.628319
100 | "fov"
101 | 45
102 | "show_grid"
103 | True
104 | "show_origin"
105 | True
106 | "viewport_mode"
107 | 1
108 | "viewports"
109 |
110 |
111 | "distance"
112 | 4
113 | "listener"
114 | True
115 | "pos"
116 | 0, 0, 0
117 | "use_environment"
118 | False
119 | "use_orthogonal"
120 | False
121 | "x_rot"
122 | 0
123 | "y_rot"
124 | 0
125 |
126 |
127 | "distance"
128 | 4
129 | "listener"
130 | False
131 | "pos"
132 | 0, 0, 0
133 | "use_environment"
134 | False
135 | "use_orthogonal"
136 | False
137 | "x_rot"
138 | 0
139 | "y_rot"
140 | 0
141 |
142 |
143 | "distance"
144 | 4
145 | "listener"
146 | False
147 | "pos"
148 | 0, 0, 0
149 | "use_environment"
150 | False
151 | "use_orthogonal"
152 | False
153 | "x_rot"
154 | 0
155 | "y_rot"
156 | 0
157 |
158 |
159 | "distance"
160 | 4
161 | "listener"
162 | False
163 | "pos"
164 | 0, 0, 0
165 | "use_environment"
166 | False
167 | "use_orthogonal"
168 | False
169 | "x_rot"
170 | 0
171 | "y_rot"
172 | 0
173 |
174 |
175 | "zfar"
176 | 2000
177 | "znear"
178 | 0.1
179 |
180 | "Anim"
181 |
182 | "visible"
183 | False
184 |
185 |
186 | "__editor_run_settings__"
187 |
188 | "custom_args"
189 | "-l $scene"
190 | "run_mode"
191 | 0
192 |
193 |
194 |
195 | 255, 255, 255, 1
196 | 0, 1, 1, 1
197 | 255, 0, 255, 1
198 | 24
199 | -1
200 | 21
201 | "+"
202 |
203 |
204 |
205 | "version"
206 | 2
207 |
208 |
209 |
210 |
--------------------------------------------------------------------------------
/preview/preview.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Control
3 |
4 | var tab_count = 0
5 | const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
6 |
7 | export var symbol_color = Color(255,255,255)
8 | export var outgoing_color = Color(255,0,255)
9 | export var incoming_color = Color(0,255,255)
10 |
11 |
12 | func _ready():
13 | var add_menu = get_node("../Add").get_popup()
14 | add_menu.add_item("Add server", 0)
15 | add_menu.add_item("Add client", 1)
16 | add_menu.connect("item_pressed", self, "add_tab")
17 |
18 | add_tab(0)
19 | add_tab(1)
20 |
21 | randomize()
22 | func add_tab(type):
23 | var new_tab
24 | if type == 0:
25 | new_tab = preload("./server_tab.xscn")
26 | elif type == 1:
27 | new_tab = preload("./client_tab.xscn")
28 | new_tab = new_tab.instance()
29 | new_tab.set_name(str(new_tab.get_name(), " ", characters[tab_count]))
30 | tab_count += 1
31 | add_child(new_tab)
32 |
33 | func prepare_results_console(console):
34 | console.set_text(str("----", console.get_parent().get_name(), " log----"))
35 | console.set_readonly(true)
36 | console.set_wrap(true)
37 | console.set_max_chars(20)
38 | console.set_syntax_coloring(true)
39 | console.set_symbol_color(symbol_color)
40 | console.add_keyword_color("Sent", outgoing_color)
41 | console.add_keyword_color("message", outgoing_color)
42 | console.add_keyword_color("response", outgoing_color)
43 | console.add_keyword_color("Received", incoming_color)
--------------------------------------------------------------------------------
/preview/res/FiraMono-Medium.fnt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KOBUGE-Incubator/gdscript-networking-library/6376253159c007438192e40bcb05bcb35f5f9cbf/preview/res/FiraMono-Medium.fnt
--------------------------------------------------------------------------------
/preview/server_tab.gd:
--------------------------------------------------------------------------------
1 |
2 | extends Control
3 |
4 | var server = preload("res://lib/udp/server.gd").new()
5 |
6 | func _ready():
7 | get_node("Buttons/Send/Submit").connect("pressed", self, "send")
8 | get_node("Buttons/Toggle").connect("toggled", self, "toggle")
9 |
10 | get_node("Buttons/Send/Target").add_item("All connected clients", 0)
11 |
12 | get_parent().prepare_results_console(get_node("Result"))
13 |
14 | server.connect("connect", self, "client_connected")
15 | server.connect("message", self, "new_message")
16 | server.connect("disconnect", self, "client_disconnected")
17 |
18 | func toggle(state):
19 | if state:
20 | get_node("Buttons/Toggle").set_text("Stop server")
21 | server.start(8760)
22 | add_result("Server is running!")
23 | else:
24 | get_node("Buttons/Toggle").set_text("Start server")
25 | add_result("Server stopped!")
26 | server.stop()
27 |
28 | func new_message(id, msg):
29 | add_result(str("Received: ", msg.to_json()))
30 |
31 | var response = false
32 |
33 | if msg.has("get") and msg.get == "inventory":
34 | response = {"items": ["Old boots", "Raw fish", "Lenses", "Hat", "Rusty dagger"]}
35 | if msg.has("action") and msg.action == "skill":
36 | response = {"error": "Not enough mana!"}
37 | if msg.has("action") and msg.action == "attack":
38 | response = {"ok": true}
39 | if msg.has("chat"):
40 | add_result(str("<", id, "> : ", msg.chat))
41 | var message = {"chat": msg.chat, "from": id}
42 | server.send_to_all(message)
43 | add_result(str("Sent message: ", message.to_json(), "\n"))
44 |
45 | if response != false:
46 | add_result(str("Sent response: ", response.to_json(), "\n"))
47 | server.send_to(id, response)
48 |
49 | func send():
50 | var possible_messages = [
51 | {"dead": str("rat-", floor(rand_range(0, 42)))},
52 | {"move": str("rat-", floor(rand_range(0, 42))), "amount": [0, 1]},
53 | {"move": str("rat-", floor(rand_range(0, 42))), "amount": [0, -1]},
54 | {"move": str("rat-", floor(rand_range(0, 42))), "amount": [1, 0]},
55 | {"move": str("rat-", floor(rand_range(0, 42))), "amount": [-1, 0]},
56 | {"notification": str("A new level was added to the collection!"), "from": "!level_bot"}
57 | ]
58 | var msg = possible_messages[rand_range(0, possible_messages.size())]
59 |
60 | var target = get_node("Buttons/Send/Target").get_selected_ID()
61 | if target == 0:
62 | server.send_to_all(msg)
63 | else:
64 | server.send_to(target-1, msg)
65 |
66 | add_result(str("Sent message: ", msg.to_json()))
67 |
68 | func client_connected(id):
69 | get_node("Buttons/Send/Target").add_item(str("<",id,">"), id+1)
70 | add_result(str("<", id, "> Connected!"))
71 |
72 | func client_disconnected(id):
73 | add_result(str("<", id, "> Disconnected!"))
74 |
75 | func add_result(result):
76 | get_node("Result").set_text(str(get_node("Result").get_text(), "\n", result))
77 |
--------------------------------------------------------------------------------
/preview/server_tab.xscn:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | "conn_count"
8 | 0
9 | "conns"
10 |
11 | "editable_instances"
12 |
13 |
14 | "names"
15 |
16 | "Server"
17 | "anchor/right"
18 | "anchor/bottom"
19 | "margin/left"
20 | "margin/top"
21 | "margin/right"
22 | "margin/bottom"
23 | "focus/ignore_mouse"
24 | "focus/stop_mouse"
25 | "size_flags/horizontal"
26 | "size_flags/vertical"
27 | "script/script"
28 | "__meta__"
29 | "Control"
30 | "Buttons"
31 | "rect/min_size"
32 | "Toggle"
33 | "toggle_mode"
34 | "text"
35 | "flat"
36 | "Button"
37 | "Send"
38 | "Submit"
39 | "Target"
40 | "anchor/left"
41 | "align"
42 | "selected"
43 | "items"
44 | "OptionButton"
45 | "Result"
46 | "custom_fonts/font"
47 | "TextEdit"
48 |
49 | "node_count"
50 | 7
51 | "node_paths"
52 |
53 |
54 | "nodes"
55 | -1, -1, 13, 0, -1, 12, 1, 0, 2, 0, 3, 1, 4, 1, 5, 1, 6, 1, 7, 2, 8, 3, 9, 4, 10, 4, 11, 5, 12, 6, 0, 0, 0, 13, 14, -1, 7, 1, 0, 6, 7, 15, 8, 7, 2, 8, 3, 9, 4, 10, 4, 0, 1, 0, 20, 16, -1, 10, 1, 0, 6, 9, 15, 10, 7, 2, 8, 3, 9, 4, 10, 4, 17, 3, 18, 11, 19, 2, 0, 1, 0, 13, 21, -1, 8, 1, 0, 4, 12, 6, 13, 15, 10, 7, 2, 8, 3, 9, 4, 10, 4, 0, 3, 0, 20, 22, -1, 11, 1, 14, 2, 0, 5, 15, 15, 10, 7, 2, 8, 3, 9, 4, 10, 4, 17, 2, 18, 16, 19, 2, 0, 3, 0, 28, 23, -1, 13, 24, 14, 1, 0, 2, 0, 3, 17, 7, 2, 8, 3, 9, 4, 10, 4, 17, 2, 19, 2, 25, 18, 26, 19, 27, 20, 0, 0, 0, 31, 29, -1, 8, 1, 0, 2, 0, 4, 21, 7, 2, 8, 3, 9, 4, 10, 14, 30, 22, 0
56 | "variants"
57 |
58 | 1
59 | 4
60 | False
61 | True
62 | 2
63 |
64 |
65 | "__editor_plugin_screen__"
66 | "Script"
67 | "__editor_plugin_states__"
68 |
69 | "2D"
70 |
71 | "ofs"
72 | -279.919, -271.487
73 | "snap_grid"
74 | False
75 | "snap_offset"
76 | 0, 0
77 | "snap_pixel"
78 | False
79 | "snap_relative"
80 | False
81 | "snap_rotation"
82 | False
83 | "snap_rotation_offset"
84 | 0
85 | "snap_rotation_step"
86 | 0.261799
87 | "snap_show_grid"
88 | False
89 | "snap_step"
90 | 10, 10
91 | "zoom"
92 | 0.814506
93 |
94 | "3D"
95 |
96 | "ambient_light_color"
97 | 0.15, 0.15, 0.15, 1
98 | "default_light"
99 | True
100 | "default_srgb"
101 | False
102 | "deflight_rot_x"
103 | 0.942478
104 | "deflight_rot_y"
105 | 0.628319
106 | "fov"
107 | 45
108 | "show_grid"
109 | True
110 | "show_origin"
111 | True
112 | "viewport_mode"
113 | 1
114 | "viewports"
115 |
116 |
117 | "distance"
118 | 4
119 | "listener"
120 | True
121 | "pos"
122 | 0, 0, 0
123 | "use_environment"
124 | False
125 | "use_orthogonal"
126 | False
127 | "x_rot"
128 | 0
129 | "y_rot"
130 | 0
131 |
132 |
133 | "distance"
134 | 4
135 | "listener"
136 | False
137 | "pos"
138 | 0, 0, 0
139 | "use_environment"
140 | False
141 | "use_orthogonal"
142 | False
143 | "x_rot"
144 | 0
145 | "y_rot"
146 | 0
147 |
148 |
149 | "distance"
150 | 4
151 | "listener"
152 | False
153 | "pos"
154 | 0, 0, 0
155 | "use_environment"
156 | False
157 | "use_orthogonal"
158 | False
159 | "x_rot"
160 | 0
161 | "y_rot"
162 | 0
163 |
164 |
165 | "distance"
166 | 4
167 | "listener"
168 | False
169 | "pos"
170 | 0, 0, 0
171 | "use_environment"
172 | False
173 | "use_orthogonal"
174 | False
175 | "x_rot"
176 | 0
177 | "y_rot"
178 | 0
179 |
180 |
181 | "zfar"
182 | 500
183 | "znear"
184 | 0.1
185 |
186 | "Anim"
187 |
188 | "visible"
189 | False
190 |
191 |
192 | "__editor_run_settings__"
193 |
194 | "custom_args"
195 | "-l $scene"
196 | "run_mode"
197 | 0
198 |
199 |
200 | 70
201 | 0, 70
202 | 32
203 | 128, 32
204 | "Start server"
205 | 36
206 | 68
207 | 3
208 | 2
209 | "Send message to:"
210 | -2
211 | 0
212 | -1
213 |
214 |
215 | 74
216 |
217 |
218 | "version"
219 | 2
220 |
221 |
222 |
223 |
--------------------------------------------------------------------------------