288 lines
No EOL
11 KiB
GDScript
288 lines
No EOL
11 KiB
GDScript
# Class to manage low level communication with khaganat
|
|
#
|
|
# Copyright (C) 2019 AleaJactaEst
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
# https://godotengine.org/qa/20026/to-send-a-udp-packet-godot-3
|
|
|
|
extends Control
|
|
|
|
enum TCONNECTIONSTATE {
|
|
NOTINITIALISED = 0, # nothing happened yet
|
|
NOTCONNECTED = 1, # init() called
|
|
AUTHENTICATE = 2, # connect() called, identified by the login server
|
|
LOGIN = 3, # connecting to the frontend, sending identification
|
|
SYNCHRONIZE = 4, # connection accepted by the frontend, synchronizing
|
|
CONNECTED = 5, # synchronized, connected, ready to work
|
|
PROBE = 6, # connection lost by frontend, probing for response
|
|
STALLED = 7, # server is stalled
|
|
DISCONNECT = 8, # disconnect() called, or timeout, or connection closed by frontend
|
|
QUIT = 9}
|
|
|
|
enum CLFECOMMON {
|
|
SYSTEM_LOGIN_CODE = 0,
|
|
SYSTEM_SYNC_CODE = 1,
|
|
SYSTEM_ACK_SYNC_CODE = 2,
|
|
SYSTEM_PROBE_CODE = 3,
|
|
SYSTEM_ACK_PROBE_CODE = 4,
|
|
SYSTEM_DISCONNECTION_CODE = 5,
|
|
SYSTEM_STALLED_CODE = 6,
|
|
SYSTEM_SERVER_DOWN_CODE = 7,
|
|
SYSTEM_QUIT_CODE = 8,
|
|
SYSTEM_ACK_QUIT_CODE = 9,
|
|
NUMBITSINLONGACK = 512}
|
|
|
|
const NUM_BITS_IN_LONG_ACK = 512
|
|
|
|
var _connection_state
|
|
|
|
var _socketUDP
|
|
|
|
var _user_addr
|
|
var _user_key
|
|
var _user_id
|
|
|
|
var _current_received_number
|
|
var _last_received_number
|
|
var _confirmed_received_number
|
|
|
|
var _last_ack_bit
|
|
var _ack_bit_mask
|
|
var _long_ack_bit_field
|
|
var _last_ack_in_long_ack
|
|
var _latest_sync
|
|
|
|
var _latest_probe_time
|
|
var _latest_probe
|
|
var _latest_probes
|
|
|
|
var _quit_id
|
|
var _update_time
|
|
var _queue_message_system
|
|
|
|
func _ready():
|
|
_current_received_number = 0
|
|
_last_received_number = 0
|
|
_confirmed_received_number = 0
|
|
_last_ack_bit = 0
|
|
_ack_bit_mask = 0
|
|
_connection_state = TCONNECTIONSTATE.NOTINITIALISED
|
|
_socketUDP = PacketPeerUDP.new()
|
|
_queue_message_system = Array()
|
|
_long_ack_bit_field = preload("res://bitset.gdns").new()
|
|
_long_ack_bit_field.resize(512)
|
|
_last_ack_in_long_ack = 0
|
|
_latest_sync = 0
|
|
_latest_probe_time = 0
|
|
_latest_probe = 0
|
|
_latest_probes = Array()
|
|
_update_time = 0
|
|
_quit_id = 0
|
|
|
|
func send_system_login(user_addr, user_key, user_id, lang):
|
|
var msgout = preload("res://bitstream.gdns").new()
|
|
msgout.put_sint32(_current_received_number)
|
|
msgout.put_bool(true)
|
|
msgout.put_uint8(CLFECOMMON.SYSTEM_LOGIN_CODE)
|
|
msgout.put_string_hexa32(user_addr)
|
|
msgout.put_string_hexa32(user_key)
|
|
msgout.put_string_hexa32(user_id)
|
|
msgout.put_string(lang)
|
|
print("[net_low_level:send_system_login] Send System Login :" + msgout.show())
|
|
# To connect you need send 1st message
|
|
var res = _socketUDP.put_packet(msgout.get_data())
|
|
if ( res != OK):
|
|
print("[net_low_level:send_system_login] Error to send system login : " + str(res))
|
|
return
|
|
_connection_state = TCONNECTIONSTATE.CONNECTED
|
|
|
|
func send_system_sync():
|
|
var msgout = preload("res://bitstream.gdns").new()
|
|
msgout.put_sint32(_current_received_number)
|
|
msgout.put_bool(true)
|
|
msgout.put_uint8(CLFECOMMON.SYSTEM_ACK_SYNC_CODE)
|
|
msgout.put_sint32(_last_received_number)
|
|
msgout.put_sint32(_last_ack_in_long_ack)
|
|
_long_ack_bit_field.write_serial(msgout)
|
|
msgout.put_sint32(_latest_sync)
|
|
_queue_message_system.append(msgout)
|
|
|
|
func send_system_ack_probe():
|
|
var msgout = preload("res://bitstream.gdns").new()
|
|
msgout.put_sint32(_current_received_number)
|
|
msgout.put_bool(true)
|
|
msgout.put_uint8(CLFECOMMON.SYSTEM_ACK_PROBE_CODE)
|
|
msgout.put_sint32(_latest_probes.size())
|
|
for data in _latest_probes:
|
|
msgout.put_sint32(data)
|
|
_latest_probes.clear()
|
|
#_queue_message_system.append(msgout)
|
|
var res = _socketUDP.put_packet(msgout.get_data())
|
|
if ( res != OK):
|
|
print("[net_low_level:send_system_quit] Error to send system quit : " + str(res))
|
|
return
|
|
|
|
func send_system_quit():
|
|
var msgout = preload("res://bitstream.gdns").new()
|
|
_quit_id += 1
|
|
msgout.put_sint32(_current_received_number)
|
|
msgout.put_bool(true)
|
|
msgout.put_uint8(CLFECOMMON.SYSTEM_QUIT_CODE)
|
|
msgout.put_sint32(_quit_id)
|
|
#_queue_message_system.append(msgout)
|
|
_connection_state == TCONNECTIONSTATE.QUIT
|
|
var res = _socketUDP.put_packet(msgout.get_data())
|
|
if ( res != OK):
|
|
print("[net_low_level:send_system_quit] Error to send system quit : " + str(res))
|
|
return
|
|
|
|
func send_systemm_disconnect():
|
|
var msgout = preload("res://bitstream.gdns").new()
|
|
msgout.put_sint32(_current_received_number)
|
|
msgout.put_bool(true)
|
|
msgout.put_uint8(CLFECOMMON.SYSTEM_DISCONNECTION_CODE)
|
|
var res = _socketUDP.put_packet(msgout.get_data())
|
|
_connection_state == TCONNECTIONSTATE.QUIT
|
|
if ( res != OK):
|
|
print("[net_low_level:send_systemm_disconnect] Error to send system disconnection : " + str(res))
|
|
return
|
|
|
|
func disconnect_server():
|
|
print("[net_low_level:disconnect_server] Disconnect")
|
|
if _socketUDP:
|
|
send_systemm_disconnect()
|
|
print("[net_low_level:disconnect_server] Send disconnect to server")
|
|
_socketUDP.close()
|
|
|
|
func connect_to_server(user_addr, user_key, user_id):
|
|
var connexion = load("res://assets/Scripts/Config/connexion.gd").connexion.new()
|
|
var khaganat_host = connexion.get_khaganat_host()
|
|
var khaganat_port = connexion.get_khaganat_port()
|
|
var lang = connexion.get_language()
|
|
print("[net_low_level:connect_to_server] prepare:" + str(khaganat_host) + ":" + str(khaganat_port))
|
|
_socketUDP.set_dest_address(khaganat_host, khaganat_port)
|
|
send_system_login(user_addr, user_key, user_id, lang)
|
|
|
|
func decode_system_message(msgin):
|
|
var message = msgin.get_uint8()
|
|
print("[net_low_level:analyze_message_received] Message type:" + str(message) )
|
|
match message:
|
|
CLFECOMMON.SYSTEM_LOGIN_CODE:
|
|
pass
|
|
CLFECOMMON.SYSTEM_SYNC_CODE:
|
|
var synchronize = msgin.get_uint32()
|
|
var stime = msgin.get_sint64()
|
|
_latest_sync = msgin.get_uint32()
|
|
var msg_xml = msgin.get_array_uint8(16)
|
|
var database_xml = msgin.get_array_uint8(16)
|
|
print("[net_low_level:analyze_message_received] synchronize:" + str(synchronize) + " stime:" + str(stime) + " latest_sync:" + str(_latest_sync))
|
|
var num = ""
|
|
for item in msg_xml:
|
|
num += str(item) + "."
|
|
print(num)
|
|
num = ""
|
|
for item in database_xml:
|
|
num += str(item) + "."
|
|
print(num)
|
|
send_system_sync()
|
|
CLFECOMMON.SYSTEM_STALLED_CODE:
|
|
pass
|
|
CLFECOMMON.SYSTEM_PROBE_CODE:
|
|
_latest_probe_time = _update_time
|
|
_latest_probe = msgin.get_sint32()
|
|
_latest_probes.append(_latest_probe)
|
|
send_system_ack_probe()
|
|
CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
|
|
pass
|
|
_:
|
|
print("[net_low_level:analyze_message_received] Message type unknown (" + str(message) + ")")
|
|
|
|
func decode_normal_message(msgin):
|
|
pass
|
|
|
|
func analyze_message_received(msgbytes):
|
|
# khanat-opennel-code/code/ryzom/server/src/frontend_service/fe_receive_sub.cpp:769 void CFeReceiveSub::handleReceivedMsg( CClientHost *clienthost )
|
|
_update_time = OS.get_ticks_msec()
|
|
var msgin = preload("res://bitstream.gdns").new()
|
|
msgin.put_data(msgbytes)
|
|
_current_received_number = msgin.get_sint32()
|
|
var system_mode = msgin.get_bool()
|
|
print("[net_low_level:analyze_message_received] Tick:" + str(_current_received_number) + ", Mode:" + str(system_mode) + ", Size:" + str(msgin.size()))
|
|
if system_mode:
|
|
print("[net_low_level:analyze_message_received] System Mode")
|
|
if _current_received_number > _last_received_number + 1:
|
|
print("[net_low_level:analyze_message_received] lost message : " + str(_last_received_number + 1 - _current_received_number))
|
|
elif _current_received_number == _last_received_number:
|
|
print("[net_low_level:analyze_message_received] Server re-send last message")
|
|
return
|
|
elif _current_received_number < _last_received_number:
|
|
print("[net_low_level:analyze_message_received] Server re-send old message")
|
|
return
|
|
var ackBool = false
|
|
var ackBit = 0
|
|
if not system_mode:
|
|
match _connection_state:
|
|
TCONNECTIONSTATE.CONNECTED:
|
|
ackBool = true
|
|
ackBit = 1
|
|
TCONNECTIONSTATE.SYNCHRONIZE:
|
|
ackBool = true
|
|
ackBit = 1
|
|
_:
|
|
ackBool = false
|
|
if _current_received_number - _last_received_number < 32:
|
|
_ack_bit_mask <<= _current_received_number - _last_received_number
|
|
_ack_bit_mask |= _last_ack_bit << (_current_received_number - _last_received_number - 1)
|
|
elif (_current_received_number - _last_received_number) == 32 and _last_ack_bit != 0:
|
|
_ack_bit_mask = 0x80000000
|
|
else:
|
|
_ack_bit_mask = 0x00000000
|
|
_last_ack_bit = ackBit
|
|
for i in range(_last_received_number + 1, _current_received_number):
|
|
_long_ack_bit_field.clear_bit(i & (NUM_BITS_IN_LONG_ACK -1))
|
|
_long_ack_bit_field.put(_current_received_number & (NUM_BITS_IN_LONG_ACK-1), ackBool)
|
|
if _last_ack_in_long_ack <= (_last_received_number - NUM_BITS_IN_LONG_ACK):
|
|
_last_ack_in_long_ack = _last_received_number - NUM_BITS_IN_LONG_ACK + 1
|
|
_last_received_number = _current_received_number
|
|
|
|
if system_mode:
|
|
decode_system_message(msgin)
|
|
else:
|
|
decode_normal_message(msgin)
|
|
|
|
func _process(delta):
|
|
var max_read = 10
|
|
if _connection_state == TCONNECTIONSTATE.NOTINITIALISED:
|
|
return
|
|
if _connection_state == TCONNECTIONSTATE.NOTCONNECTED:
|
|
return
|
|
if _connection_state == TCONNECTIONSTATE.QUIT:
|
|
return
|
|
if _queue_message_system.size() > 0:
|
|
var msgout = _queue_message_system.pop_front()
|
|
print("[net_low_level:_process] Send data system (" + str(msgout.size()) + ", " + msgout.show() + ")" )
|
|
_socketUDP.put_packet(msgout.get_data())
|
|
|
|
if _latest_probes.size() > 0:
|
|
send_system_ack_probe()
|
|
|
|
while _socketUDP.get_available_packet_count() > 0 and max_read > 0:
|
|
var msgbytes = _socketUDP.get_packet()
|
|
if msgbytes.size() > 0:
|
|
analyze_message_received(msgbytes)
|
|
|
|
func _exit_tree():
|
|
disconnect_server() |