diff --git a/README.md b/README.md index d03a004..8d51262 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,15 @@ scons -C godot-cpp platform=linux generate_bindings=yes custom_api_file=godot_he ### Build on 64bits ``` -scons -C gdnative platform=linux bits=64 +scons -C gdnative platform=linux bits=64 target=debug +scons -C gdnative platform=linux bits=64 target=release ``` ### Build on 32bits ``` -scons -C gdnative platform=linux bits=32 +scons -C gdnative platform=linux bits=32 target=debug +scons -C gdnative platform=linux bits=64 target=release ``` ## Package client khaganat diff --git a/addons/ui_window/ui_window.gd b/addons/ui_window/ui_window.gd index f89168b..ed0845d 100644 --- a/addons/ui_window/ui_window.gd +++ b/addons/ui_window/ui_window.gd @@ -111,7 +111,6 @@ func _enter_tree(): background.self_modulate = background_color self.add_window_part( background ) - print("[ui_window:3]") # background.set_owner( self ) ### ### diff --git a/assets/Scripts/Definition/msg.gd b/assets/Scripts/Definition/msg.gd index 2bce062..4940478 100644 --- a/assets/Scripts/Definition/msg.gd +++ b/assets/Scripts/Definition/msg.gd @@ -10,12 +10,16 @@ var _msg_data = {} func open_message_xml(): var file = File.new() + # Calculate MD5SUM file.open("res://assets/Definition/msg.xml", File.READ) var content = file.get_as_text() _msg_md5sum = content.md5_text() file.close() + print("[res://assets/Scripts/Definition/msg.gd:open_message_xml] checksum for msg.xml:" + _msg_md5sum) + var NetworkConnexion = preload("res://networkconnexion.gdns").new() + NetworkConnexion.define_checksum_msg_xml(content.md5_buffer()) + # Load XML data _msg_xml.open("res://assets/Definition/msg.xml") - print("[msg:open_message_xml] " + _msg_md5sum) func is_correct_md5(value): return (_msg_md5sum == value) @@ -26,6 +30,8 @@ func read_all_node(): var ret = _msg_xml.read() var branch = "" var leaf = "" + var ibranch = 0 + var ileaf = 0 while ret == OK: #print("Node: Name:" + _msg_xml.get_node_name() + ", Type:" + str(_msg_xml.get_node_type()) + ", Data:" + str(_msg_xml.get_node_data()) + ", attribut count:" + str(_msg_xml.get_attribute_count()) ) #i = 0 @@ -44,7 +50,9 @@ func read_all_node(): if i < _msg_xml.get_attribute_count(): branch = _msg_xml.get_attribute_value(i) #print(branch + " " + str(_msg_xml.get_node_type())) - _msg_data[branch] = [] + _msg_data[branch] = {"leaf": {}, "pos": ibranch} + ibranch += 1 + ileaf = 0 "leaf": i = 0 while i < _msg_xml.get_attribute_count() and _msg_xml.get_attribute_name(i) != "name": @@ -52,21 +60,35 @@ func read_all_node(): if i < _msg_xml.get_attribute_count(): leaf = _msg_xml.get_attribute_value(i) #print(branch + ":" + leaf + str(_msg_xml.get_node_type())) - _msg_data[branch].append(leaf) + _msg_data[branch]["leaf"][leaf] = ileaf + ileaf += 1 ret = _msg_xml.read() - print("Branch:" + str(_msg_data.size())) - for key in _msg_data: - print(" " + key + ":" + str(_msg_data[key].size())) - for leaf in _msg_data[key]: - print(" " + key + ":" + leaf) + if ProjectSettings.get_setting("khaganat/debug_mode"): + #print("Branch:" + str(_msg_data.size())) + var sizebranch = _msg_data.size() + for key in _msg_data: + var sizeleaf = _msg_data[key]["leaf"].size() + print(" " + key + " -> " + str(_msg_data[key]["pos"]) + "/" + str(sizebranch)) + for leaf in _msg_data[key]["leaf"]: + var opt = str(_msg_data[key]["pos"]) + "/" + str(sizebranch) + " : " + str(_msg_data[key]["leaf"][leaf]) + "/" + str(sizeleaf) + print(" " + key + ":" + leaf + " -> " + opt) # Called when the node enters the scene tree for the first time. func _ready(): open_message_xml() read_all_node() - print("[msg] ready") + print("[res://assets/Scripts/Definition/msg.gd] ready") + # Called every frame. 'delta' is the elapsed time since the previous frame. #func _process(delta): # pass + + +func read_msg(msgin): + pass + + +func write_msg(value): + pass \ No newline at end of file diff --git a/assets/Scripts/Network/net_low_level.gd b/assets/Scripts/Network/net_low_level.gd index 6a36314..a2a4e93 100644 --- a/assets/Scripts/Network/net_low_level.gd +++ b/assets/Scripts/Network/net_low_level.gd @@ -20,292 +20,32 @@ 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 - -var _khaganat_host = "localhost" -var _khaganat_port = "47851" - onready var BitStream = preload("res://bitstream.gdns") onready var BitSet = preload("res://bitset.gdns") +onready var NetworkConnexion = preload("res://networkconnexion.gdns") + +var _networkconnexion 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 = BitSet.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 + _networkconnexion = NetworkConnexion.new() -func send_system_login(user_addr, user_key, user_id, lang): - var msgout = BitStream.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 = BitStream.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 = BitStream.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_login(host, port, user_addr, user_key, user_id, lang): + _networkconnexion.send_system_login(host, port, user_addr, user_key, user_id, lang) func send_system_quit(): - # TODO - check why we send quit_id - var msgout = BitStream.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 + _networkconnexion.send_system_quit() func send_systemm_disconnect(): - var msgout = BitStream.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 + _networkconnexion.send_systemm_disconnect() func disconnect_server(): - print("[net_low_level:disconnect_server] Disconnect") - if typeof(_socketUDP) != TYPE_NIL: - send_systemm_disconnect() - print("[net_low_level:disconnect_server] Send disconnect to server") - _socketUDP.close() - _socketUDP = null + _networkconnexion.disconnect_server() -func set_khaganat_server(host, port): - _khaganat_host = host - _khaganat_port = port - -func connect_to_server(user_addr, user_key, user_id): - var connexion = load("res://assets/Scripts/Config/connexion.gd").connexion.new() - var lang = connexion.get_language() - print("[net_low_level:connect_to_server] prepare:" + str(_khaganat_host) + ":" + str(_khaganat_port)) - if typeof(_socketUDP) == TYPE_NIL: - _socketUDP = PacketPeerUDP.new() - _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 hexa = preload("res://assets/Scripts/Tools/hexa.gd").new() - 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) - print(hexa.ArrayIntToStringHexa(msg_xml)) - num = "" - for item in database_xml: - num += str(item) + "." - print(num) - print(hexa.ArrayIntToStringHexa(database_xml)) - if not msg.is_correct_md5(hexa.ArrayIntToStringHexa(msg_xml)): - print("[net_low_level:analyze_message_received] Wrong MD5 for msg.xml") - # TODO - we need quit with message error and go to login - return - 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 = BitStream.new() - msgin.put_data(msgbytes) - _current_received_number = msgin.get_sint32() - var system_mode = msgin.get_bool() - if ProjectSettings.get_setting("khaganat/debug_mode"): - 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 connect_to_server(host, port, user_addr, user_key, user_id, lang): + send_system_login(host, port, user_addr, user_key, user_id, lang) func _process(delta): - if typeof(_socketUDP) == TYPE_NIL: - return - 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() - if ProjectSettings.get_setting("khaganat/debug_mode"): - 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) + _networkconnexion.process(delta) func _exit_tree(): print("[net_low_level] End") diff --git a/gdnative/src/bitstream.cpp b/gdnative/src/bitstream.cpp index 9aca249..18b401f 100644 --- a/gdnative/src/bitstream.cpp +++ b/gdnative/src/bitstream.cpp @@ -50,6 +50,7 @@ void BitStream::_register_methods() register_method("show", &BitStream::show); register_method("show_detail", &BitStream::show_detail); + register_method("show_counter", &BitStream::show_counter); register_method("get_data", &BitStream::get_data); register_method("put_data", &BitStream::put_data); @@ -67,10 +68,15 @@ void BitStream::_register_methods() register_method("get_array_uint8", &BitStream::get_array_uint8); } +void BitStream::clear() +{ + this->_pos = 0; + this->_read = 0; +} + BitStream::BitStream() { - this->_pos = 0; - this->_read = 0; + clear(); } BitStream::~BitStream() @@ -313,6 +319,13 @@ String BitStream::show_detail() return "[size:" + strsize + ", pos:" + strpos + "]" + ret ; } +String BitStream::show_counter() +{ + String ret = "[" + String::num_int64(this->_read) + " / " + String::num_int64(this->_pos) + "]"; + + return ret; +} + PoolByteArray BitStream::get_data() { return this->_data; @@ -441,4 +454,4 @@ PoolByteArray BitStream::get_array_uint8(uint32_t length) --length; } return ret; -} \ No newline at end of file +} diff --git a/gdnative/src/bitstream.h b/gdnative/src/bitstream.h index 21036c7..25de312 100644 --- a/gdnative/src/bitstream.h +++ b/gdnative/src/bitstream.h @@ -34,6 +34,8 @@ private: public: static void _register_methods(); + void clear(); + BitStream(); ~BitStream(); @@ -61,6 +63,7 @@ public: String show(); String show_detail(); + String show_counter(); PoolByteArray get_data(); void put_data(PoolByteArray value); diff --git a/gdnative/src/clfecommon.h b/gdnative/src/clfecommon.h new file mode 100644 index 0000000..c36a1ae --- /dev/null +++ b/gdnative/src/clfecommon.h @@ -0,0 +1,42 @@ +/* + Header CLFECOMMON : message send by server + + 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 . + +*/ + +#ifndef CLFECOMMON_H +#define CLFECOMMON_H + +namespace godot { + +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 +}; + +} + +#endif // CLFECOMMON_H diff --git a/gdnative/src/crypt.h b/gdnative/src/crypt.h index eeef197..34d091b 100644 --- a/gdnative/src/crypt.h +++ b/gdnative/src/crypt.h @@ -6,8 +6,8 @@ namespace godot { -class Crypt : public Reference { - GODOT_CLASS(Crypt, Reference) +class Crypt : public Object { + GODOT_CLASS(Crypt, Object) public: static void _register_methods(); diff --git a/gdnative/src/gdlibrary.cpp b/gdnative/src/gdlibrary.cpp index 352fda1..0b05f8c 100644 --- a/gdnative/src/gdlibrary.cpp +++ b/gdnative/src/gdlibrary.cpp @@ -21,22 +21,25 @@ #include "bitstream.h" #include "bitset.h" #include "crypt.h" +#include "network_connection.h" /** GDNative Initialize **/ extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) { - godot::Godot::gdnative_init(o); + godot::Godot::gdnative_init(o); } /** GDNative Terminate **/ extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) { - godot::Godot::gdnative_terminate(o); + terminate_network_connection(); + godot::Godot::gdnative_terminate(o); } /** NativeScript Initialize **/ extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) { - godot::Godot::nativescript_init(handle); + godot::Godot::nativescript_init(handle); - godot::register_class(); - godot::register_class(); - godot::register_class(); + godot::register_class(); + godot::register_class(); + godot::register_class(); + godot::register_class(); } diff --git a/gdnative/src/network_connection.cpp b/gdnative/src/network_connection.cpp new file mode 100644 index 0000000..8decd60 --- /dev/null +++ b/gdnative/src/network_connection.cpp @@ -0,0 +1,93 @@ +/* + Library to present all functions of NetworkConnectionCore (network) + + 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 . + + */ + + +#include +#include "network_connection.h" +#include "bitstream.h" +#include "network_connection_core.h" + +using namespace godot; + +NetworkConnectionCore *NetworkConnectionCore::singleton = NULL; + +void NetworkConnection::_register_methods() +{ + register_method("define_checksum_msg_xml", &NetworkConnection::define_checksum_msg_xml); + register_method("define_socket_udp", &NetworkConnection::define_socket_udp); + register_method("send_system_login", &NetworkConnection::send_system_login); + register_method("send_system_disconnect", &NetworkConnection::send_system_disconnect); + register_method("send_system_quit", &NetworkConnection::send_system_quit); + register_method("disconnect_server", &NetworkConnection::disconnect_server); + register_method("process", &NetworkConnection::process); + register_method("get_state", &NetworkConnection::get_state); +} + +NetworkConnection::NetworkConnection() +{ +} + +NetworkConnection::~NetworkConnection() +{ +} + +int NetworkConnection::get_state() +{ + return NetworkConnectionCore::get_singleton()->get_state(); +} + +void NetworkConnection::define_checksum_msg_xml(Array checksum_msg_xml) +{ + NetworkConnectionCore::get_singleton()->define_checksum_msg_xml(checksum_msg_xml); +} +void NetworkConnection::define_socket_udp(PacketPeerUDP * socketUDP) +{ + NetworkConnectionCore::get_singleton()->define_socket_udp(socketUDP); +} + +void NetworkConnection::send_system_login(String host, int64_t port, String user_addr, String user_key, String user_id, String lang) +{ + NetworkConnectionCore::get_singleton()->send_system_login(host, port, user_addr, user_key, user_id, lang); +} + +void NetworkConnection::send_system_disconnect() +{ + NetworkConnectionCore::get_singleton()->send_system_disconnect(); +} + + void NetworkConnection::send_system_quit() + { + NetworkConnectionCore::get_singleton()->send_system_quit(); + } + +void NetworkConnection::disconnect_server() +{ + NetworkConnectionCore::get_singleton()->disconnect_server(); +} + +void NetworkConnection::process(int delta) +{ + NetworkConnectionCore::get_singleton()->process(delta); +} + +void terminate_network_connection() +{ + NetworkConnectionCore::get_singleton()->terminate_connexion(); +} diff --git a/gdnative/src/network_connection.h b/gdnative/src/network_connection.h new file mode 100644 index 0000000..eb52c6b --- /dev/null +++ b/gdnative/src/network_connection.h @@ -0,0 +1,62 @@ +/* + Header NetworkConnection + + 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 . + +*/ + +#ifndef NETWORK_CONNECTION_H +#define NETWORK_CONNECTION_H + +#include +#include +#include +#include "bitstream.h" +#include "clfecommon.h" +#include "store_message.h" +#include "network_connection_core.h" + +namespace godot { + +class NetworkConnection : public Object { + GODOT_CLASS(NetworkConnection, Object) +private: + static void _bind_methods(); +public: + NetworkConnection(); + ~NetworkConnection(); + + static void _register_methods(); + + /* _init must exist as it is called by Godot */ + void _init() {}; + + void define_checksum_msg_xml(Array checksum_msg_xml); + void define_socket_udp(PacketPeerUDP * socketUDP); // Not necessary, but you can define network directly on GdScript + void send_system_login(String host, int64_t port, String user_addr, String user_key, String user_id, String lang); + void send_system_disconnect(); + void send_system_quit(); + void disconnect_server(); + void process(int delta); + int get_state(); +}; + +} + +void terminate_network_connection(); + + +#endif // NETWORK_CONNECTION_H diff --git a/gdnative/src/network_connection_core.cpp b/gdnative/src/network_connection_core.cpp new file mode 100644 index 0000000..bd2540d --- /dev/null +++ b/gdnative/src/network_connection_core.cpp @@ -0,0 +1,482 @@ +/* + Library to manage network + + 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 . + + */ + +#define DEBUG_ENABLED + +#include +#include +#include + +#include "tools.h" +#include "bitset.h" +#include "bitstream.h" +#include "network_connection_core.h" +#include "state.h" + +using namespace godot; + +NetworkConnectionCore *NetworkConnectionCore::get_singleton() +{ + if ( NetworkConnectionCore::singleton == NULL ) + NetworkConnectionCore::singleton = new NetworkConnectionCore(); + return NetworkConnectionCore::singleton; +} + +NetworkConnectionCore::NetworkConnectionCore() +{ + this->_socketUDP = NULL; + this->_state = STATE::NotInitialised ; +} + +NetworkConnectionCore::~NetworkConnectionCore() +{ + NetworkConnectionCore::singleton = NULL; + this->_state = STATE::NotInitialised ; +} + +int NetworkConnectionCore::get_state() +{ + return this->_state; +} + +void NetworkConnectionCore::define_checksum_msg_xml(Array & checksum_msg_xml) +{ + DEBUG_PRINT("Received msg.xml checksum"); + this->_checksum_msg_xml = checksum_msg_xml; + DEBUG_PRINT("Received msg.xml checksum " + itos(checksum_msg_xml.size())); + DEBUG_PRINT("Received msg.xml checksum " + itos(this->_checksum_msg_xml.size())); +} + +void NetworkConnectionCore::define_socket_udp(PacketPeerUDP * socketUDP) +{ + // Use if you define PacketPeerUDP on other script + if ( this->_socketUDP == NULL) + this->_socketUDP = socketUDP; +} + +void NetworkConnectionCore::autodefine_socket_udp() +{ + // Create socket udp if not defined (If you don't use define_socket_udp) + if ( this->_socketUDP == NULL) + { + PacketPeerUDP::___init_method_bindings(); + this->_socketUDP = PacketPeerUDP::_new(); + if ( this->_socketUDP == NULL) + throw "Failed to open network"; + } +} + +void NetworkConnectionCore::send_system_login(String host, int64_t port, String user_addr, String user_key, String user_id, String lang) +{ + // Configure socket UDP + this->autodefine_socket_udp(); + if ( this->_state != STATE::NotInitialised ) + { + DEBUG_PRINT("Close old network socket"); + this->_socketUDP->close(); + } + + INFO_PRINT("Connect to " + host + ":" + itos(port)); + this->_socketUDP->set_dest_address(host, port); + // Open connection and send ID + + BitStream msgout; + 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); + godot::Error ret; + ret = this->_socketUDP->put_packet(msgout.get_data()); + if ( ret != Error::OK) + { + this->_socketUDP->close(); + switch(ret) + { + case Error::ERR_CANT_CONNECT: + ERR_PRINT("network connexion - Can't connect"); + default: + ERR_PRINT("network connexion - Unknown error"); + } + return; + } + INFO_PRINT("Connected to khganat"); + this->_state = STATE::Connected; + // Initialize counter + this->_current_received_number = 0; + this->_last_received_number = 0; + this->_quit_id = 0; + this->_long_ack_bit_field.resize(NUM_BITS_IN_LONG_ACK); + this->_latest_probes.clear(); + this->_ack_bit_mask = 0; + this->_last_ack_bit = 0; + this->_last_ack_in_long_ack = 0; +} + +void NetworkConnectionCore::send_system_quit() +{ + // TODO - check why we send quit_id + if ( this->_state != STATE::Connected && this->_state != STATE::ForceSynchronize ) + return; + DEBUG_PRINT("send quit to server"); + BitStream msgout; + msgout.put_sint32(this->_current_received_number); + msgout.put_bool(true); + msgout.put_uint8(CLFECOMMON::SYSTEM_QUIT_CODE); + msgout.put_sint32(this->_quit_id); + + if ( this->_socketUDP->put_packet(msgout.get_data()) != Error::OK ) + { + ERR_PRINT("Error to send disconnect"); + } + this->_state = STATE::Quit; +} + +void NetworkConnectionCore::send_system_disconnect() +{ + if ( this->_state != STATE::Connected && this->_state != STATE::ForceSynchronize ) + return; + DEBUG_PRINT("send disconnect to server"); + BitStream msgout; + msgout.put_sint32(this->_current_received_number); + msgout.put_bool(true); + msgout.put_uint8(CLFECOMMON::SYSTEM_DISCONNECTION_CODE); + + if ( this->_socketUDP->put_packet(msgout.get_data()) != Error::OK ) + { + ERR_PRINT("Error to send disconnect"); + } + this->_socketUDP->close(); + this->_state = STATE::Disconnect; +} + +void NetworkConnectionCore::send_system_ack_probe() +{ + // khanat-opennel-code/code/ryzom/server/src/frontend_service/fe_receive_sub.cpp:1121 void CFeReceiveSub::handleReceivedMsg( CClientHost *clienthost ) + if (this->_state != STATE::Connected && this->_state != STATE::ForceSynchronize) + return; + int max = this->_latest_probes.size(); + if (max == 0 ) + return; + if (this->_state == STATE::ForceSynchronize && max < 5) + return; + DEBUG_PRINT("send system ACK PROBE to server"); + BitStream msgout; + msgout.put_sint32(this->_current_received_number); + msgout.put_bool(true); + msgout.put_uint8(CLFECOMMON::SYSTEM_ACK_PROBE_CODE); + msgout.put_sint32(max); + for(int i=0; i < max ; ++i ) + { + //DEBUG_PRINT("i:" + itos(i)); + int data = this->_latest_probes[i]; + //DEBUG_PRINT("data:" + itos(data)); + msgout.put_sint32(data); + //DEBUG_PRINT("updated"); + } + if (this->_socketUDP->put_packet(msgout.get_data()) != Error::OK) + { + ERR_PRINT("Error to send disconnect"); + return; + } + this->_latest_probes.clear(); + if (this->_state == STATE::ForceSynchronize && max >= 5) + { + // We have send ACK, so now we clean all queue and received all message to synchronize + this->queue.clear(); + this->_state = STATE::Connected; + } +} + +void NetworkConnectionCore::disconnect_server() +{ + if (this->_state != STATE::Connected && this->_state != STATE::ForceSynchronize) + return; + send_system_disconnect(); +} + +void NetworkConnectionCore::decode_system_message(BitStream *msgin) +{ + int message = msgin->get_uint8(); + switch (message) + { + case CLFECOMMON::SYSTEM_LOGIN_CODE: + DEBUG_PRINT("SYSTEM_LOGIN_CODE"); + break; + case CLFECOMMON::SYSTEM_SYNC_CODE: + this->receive_system_sync(msgin); + break; + case CLFECOMMON::SYSTEM_STALLED_CODE: + DEBUG_PRINT("SYSTEM_STALLED_CODE"); + break; + case CLFECOMMON::SYSTEM_SERVER_DOWN_CODE: + DEBUG_PRINT("SYSTEM_SERVER_DOWN_CODE"); + break; + case CLFECOMMON::SYSTEM_PROBE_CODE: + this->receive_system_probe(msgin); + break; + default: + ERR_PRINT("Received unknown message [" + itos(message) + "]"); + break; + } +} + +void NetworkConnectionCore::decode_normal_message(BitStream *msgin) +{ + DEBUG_PRINT("Decode normal message"); +} + +void NetworkConnectionCore::receive_system_sync(BitStream * msgin) +{ + int i; + bool valide = true; + + DEBUG_PRINT("SYSTEM_SYNC_CODE"); + uint32_t synchronize = msgin->get_uint32(); + int64_t stime = msgin->get_sint64(); + uint32_t latestsync = msgin->get_uint32(); + PoolByteArray msg_xml = msgin->get_array_uint8(16); + PoolByteArray database_xml = msgin->get_array_uint8(16); + + if ( msg_xml.size() != this->_checksum_msg_xml.size() ) + { + valide = false; + DEBUG_PRINT("MSG XML is incorrect (server:" + itos(msg_xml.size()) +", client:" + itos(this->_checksum_msg_xml.size()) + ")"); + } + else + { + for(i=0; i_checksum_msg_xml[i] ) + { + valide = false; + DEBUG_PRINT("MSG XML is incorrect (pos:" + itos(i) +")"); + } + } + } + + if ( valide == true ) + DEBUG_PRINT("MSG XML is correct"); + else + DEBUG_PRINT("MSG.XML is wrong"); + + + /* + self._Synchronize = msg.readUint32('Synchronize') + stime = msg.readSint64('stime') + self._LatestSync = msg.readUint32('LatestSync') + logging.getLogger(LOGGER).debug("%d %d %d" %(self._Synchronize, stime, self._LatestSync)) + # khanat-opennel-code/code/ryzom/client/src/network_connection.cpp : void CNetworkConnection::receiveSystemSync(CBitMemStream &msgin) + MsgData = msg.readArrayUint8(16, 'MsgData') + DatabaseData = msg.readArrayUint8(16, 'DatabaseData') + logging.getLogger(LOGGER).debug("MsgData:" + str(MsgData)) + logging.getLogger(LOGGER).debug("DatabaseData:" + str(DatabaseData)) + md5Msg = bytes(MsgData) + md5Database = bytes(DatabaseData) + if md5Msg == self._MsgXmlMD5: + logging.getLogger(LOGGER).info("Check MD5 msg.xml : OK") + else: + logging.getLogger(LOGGER).error("Check MD5 msg.xml : KO") + if md5Database == self._DatabaseXmlMD5: + logging.getLogger(LOGGER).info("Check MD5 database.xml : OK") + else: + logging.getLogger(LOGGER).error("Check MD5 database.xml : KO") + logging.getLogger(LOGGER).debug("Msg Received:" + msg.showAllData()) + self._MsPerTick = 100 + self._CurrentServerTick = self._Synchronize + self._CurrentReceivedNumber + 2 + self._CurrentClientTick = self._CurrentServerTick - ( self._LCT + self._MsPerTick ) / self._MsPerTick + self._CurrentClientTime = self._UpdateTime - (self._LCT + self._MsPerTick) + */ +} + +void NetworkConnectionCore::receive_system_probe(BitStream * msgin) +{ + DEBUG_PRINT("SYSTEM_PROBE_CODE size:" + itos(this->_latest_probes.size())); + this->_latest_probes.append(msgin->get_sint32()); +} + +void NetworkConnectionCore::wait_resynchronize(int32_t current_received_number, BitStream * msgin) +{ + bool system_mode; + this->_current_received_number = current_received_number; + system_mode = msgin->get_bool(); + if ( system_mode == true ) + { + int message = msgin->get_uint8(); + switch (message) + { + case CLFECOMMON::SYSTEM_LOGIN_CODE: + DEBUG_PRINT("SYSTEM_LOGIN_CODE"); + break; + case CLFECOMMON::SYSTEM_SYNC_CODE: + DEBUG_PRINT("SYSTEM_SYNC_CODE"); + break; + case CLFECOMMON::SYSTEM_STALLED_CODE: + DEBUG_PRINT("SYSTEM_STALLED_CODE"); + break; + case CLFECOMMON::SYSTEM_SERVER_DOWN_CODE: + DEBUG_PRINT("SYSTEM_SERVER_DOWN_CODE"); + break; + case CLFECOMMON::SYSTEM_PROBE_CODE: + this->receive_system_probe(msgin); + break; + default: + ERR_PRINT("Received unknown message [" + itos(message) + "]"); + break; + } + } + this->_last_received_number = current_received_number; +} + +void NetworkConnectionCore::analyze_message_receieved(int32_t current_received_number, BitStream * msgin) +{ + bool system_mode; + bool ackBool = false; + int ackBit = 0; + int i; + + this->_current_received_number = current_received_number; + system_mode = msgin->get_bool(); + if ( system_mode == true ) + { + INFO_PRINT("Received system message"); + if (this->_current_received_number == this->_last_received_number + 1) + { + INFO_PRINT("Received message"); + } + else if (this->_current_received_number < this->_last_received_number + 1) + { + INFO_PRINT("Received old message"); + return; + } + else if (this->_current_received_number > this->_last_received_number + 1) + { + INFO_PRINT("Received message in future (lost some message)"); + } + } + else + { + INFO_PRINT("Received normal message"); + } + if ( system_mode != true ) + { + ackBool = true; + ackBit = 1; + } + if ( current_received_number - this->_last_received_number < 32 ) + { + this->_ack_bit_mask <<= current_received_number - this->_last_received_number; + this->_ack_bit_mask |= this->_last_ack_bit << (current_received_number - this->_last_received_number - 1); + } + else if (((current_received_number - this->_last_received_number) == 32) && (this->_last_ack_bit != 0)) + this->_ack_bit_mask = 0x80000000; + else + this->_ack_bit_mask = 0x00000000; + this->_last_ack_bit = ackBit; + for(i=this->_last_received_number + 1 ;i < _current_received_number; ++i) + this->_long_ack_bit_field.clear_bit(i & (NUM_BITS_IN_LONG_ACK -1) ); + + // TODO - what's action when we have rotate onthis number (max -> 0) + if( this->_last_received_number > 0x08000000 ) + { + if(this->_last_ack_in_long_ack <= (this->_last_received_number - NUM_BITS_IN_LONG_ACK)) + this->_last_ack_in_long_ack = this->_last_received_number - NUM_BITS_IN_LONG_ACK + 1; + this->_last_received_number = current_received_number; + } + else + { + if(this->_last_ack_in_long_ack - 0x80000000 <= (this->_last_received_number - NUM_BITS_IN_LONG_ACK - 0x80000000)) + this->_last_ack_in_long_ack = this->_last_received_number - NUM_BITS_IN_LONG_ACK + 1; + this->_last_received_number = current_received_number; + } + + if ( system_mode == true ) + this->decode_system_message(msgin); + else + this->decode_normal_message(msgin); +} + +void NetworkConnectionCore::store_message_received(PoolByteArray & msgbytes) +{ + int pos = this->queue.put_msgbytes(msgbytes); + + BitStream * msgin = this->queue.get_msg(pos); + int32_t current_received_number = this->queue.get_received_number(pos); + /// TODO - check if max int execeded current_received_number < 1000 this->_last_received_number > 0x80000000 + if ( this->_state == STATE::ForceSynchronize ) + { + // We have detected a problem of synchro, we wait message ack probe and after server launch a re-sync + wait_resynchronize(current_received_number, msgin); + } + else if ( current_received_number - this->_last_received_number <= 0 ) // Received old message + { + INFO_PRINT("current_received_number : " + itos(current_received_number) + " / queue size : " + itos(this->queue.length())); + this->queue.erase(pos); + return; + } + else if ( this->_last_received_number + 1 == current_received_number ) // Received next message + { + INFO_PRINT("current_received_number : " + itos(current_received_number) + " / queue size : " + itos(this->queue.length())); + analyze_message_receieved(current_received_number, msgin); + this->queue.erase(pos); + } + else // Received new message (but missing some message between) -> go to queue and cross finger to received the next message (for _last_received_number) + { + INFO_PRINT("current_received_number : " + itos(current_received_number) + " / queue size : " + itos(this->queue.length())); + if (this->queue.length() >= SIZE_QUEUE_MESSAGE) + { + ERR_PRINT("Network queue is full / wait re-synchronize"); + this->_state = STATE::ForceSynchronize ; + return; + } + } +} + +void NetworkConnectionCore::send_message() +{ + if ( this->_latest_probes.size() > 0 ) + send_system_ack_probe(); +} + +void NetworkConnectionCore::process(int delta) +{ + if (this->_state != STATE::Connected && this->_state != STATE::ForceSynchronize) + return; + //INFO_PRINT( "Process - delta : " + itos(delta)); + for(int i = 0; (this->_socketUDP->get_available_packet_count() > 0) && (i < MAX_LOOP_READ_BY_STEP) ; ++i) + { + PoolByteArray msgbytes ; + msgbytes = this->_socketUDP->get_packet(); + DEBUG_PRINT("Size msg received : " + itos(msgbytes.size()) ); + store_message_received(msgbytes); + } + send_message(); +} + +void NetworkConnectionCore::terminate_connexion() +{ + DEBUG_PRINT("Terminate network connexion"); + if ( this->_socketUDP == NULL ) + return; + delete this-> _socketUDP; + this->_socketUDP = NULL; +} diff --git a/gdnative/src/network_connection_core.h b/gdnative/src/network_connection_core.h new file mode 100644 index 0000000..30cc950 --- /dev/null +++ b/gdnative/src/network_connection_core.h @@ -0,0 +1,88 @@ +/* + Header NetworkConnectionCore + + 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 . + +*/ + +#ifndef NETWORK_CONNECTION_CORE_H +#define NETWORK_CONNECTION_CORE_H + +#include +#include +#include "bitset.h" +#include "bitstream.h" +#include "clfecommon.h" +#include "store_message.h" +#include "state.h" + +#define MAX_LOOP_READ_BY_STEP 10 +#define NUM_BITS_IN_LONG_ACK 512 + +namespace godot { + +class NetworkConnectionCore : public Object { + GODOT_CLASS(NetworkConnectionCore, Object) +private: + static NetworkConnectionCore *singleton; + + bool _force_resynchronize; + STATE _state; + PacketPeerUDP * _socketUDP; + int32_t _current_received_number; + int32_t _last_received_number; + int32_t _quit_id; + BitSet _long_ack_bit_field; + Array _latest_probes; + Array _checksum_msg_xml; + uint32_t _ack_bit_mask; + int32_t _last_ack_bit; + int32_t _last_ack_in_long_ack; + StoreMessage queue; + +public: + static NetworkConnectionCore * get_singleton(); + + NetworkConnectionCore(); + ~NetworkConnectionCore(); + + int get_state(); + + void define_checksum_msg_xml(Array & checksum_msg_xml); + + void define_socket_udp(PacketPeerUDP * socketUDP); + void autodefine_socket_udp(); + void send_system_login(String host, int64_t port, String user_addr, String user_key, String user_id, String lang); + void send_system_disconnect(); + void send_system_quit(); + void disconnect_server(); + void send_system_ack_probe(); + void decode_system_message(BitStream *msgin); + void decode_normal_message(BitStream *msgin); + void receive_system_sync(BitStream * msgin); + void receive_system_probe(BitStream * msgin); + void wait_resynchronize(int32_t current_received_number, BitStream * msgin); + void analyze_message_receieved(int32_t, BitStream *msgin); + void store_message_received(PoolByteArray & msgbytes); + void send_message(); + void process(int delta); + bool connected(); + void terminate_connexion(); +}; + +} + +#endif diff --git a/gdnative/src/state.h b/gdnative/src/state.h new file mode 100644 index 0000000..2d022f9 --- /dev/null +++ b/gdnative/src/state.h @@ -0,0 +1,38 @@ +/* + Header STATE : to know state of client + + 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 . + +*/ + +#ifndef STATE_H +#define STATE_H + +enum STATE { + NotInitialised = 0, + //NotConnected = 1, // When received a cookie - not used here + //Authenticate = 2, + //Login = 3, + // Synchronize = 4, + Connected = 5, // State when we are connecte + //Probe = 6, + //Stalled = 7, + Disconnect = 8, + Quit = 9, + ForceSynchronize = 10 +}; + +#endif // STATE_H diff --git a/gdnative/src/store_message.cpp b/gdnative/src/store_message.cpp new file mode 100644 index 0000000..a3b999a --- /dev/null +++ b/gdnative/src/store_message.cpp @@ -0,0 +1,127 @@ +/* + + StoreMessage : class to manage packet received by khaganat + If we received message with bad order, with this class we can manage (with limit storage) + + 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 . + + */ + +#include +#include + +#include "bitstream.h" +#include "tools.h" +#include "store_message.h" + +using namespace godot; + +StoreMessage::StoreMessage() +{ + this->clear(); +} + +StoreMessage::~StoreMessage() +{ + +} + +void StoreMessage::clear() +{ + for(int i = 0 ; i < SIZE_QUEUE_MESSAGE ; ++i ) + { + //this->_empty[i] = true; + this->_received_number[i] = 0; + this->_msgin[i].clear(); + } + this->_size = 0; +} + +int StoreMessage::length() +{ + return this->_size; +} + +int StoreMessage::put_msgbytes(PoolByteArray & msgbytes) +{ + int i = 0; + int ii ; + + //while((this->_empty[i] != true)&&(i < SIZE_QUEUE_MESSAGE)) + while((i < SIZE_QUEUE_MESSAGE)&&(this->_msgin[i].size_data() != 0)) + ++i; + + if(i >= SIZE_QUEUE_MESSAGE) // Out of memory + { + ERR_PRINT("Network queue is full (" + itos(i) + " / " + itos(SIZE_QUEUE_MESSAGE) + ")"); + throw "Out of memory"; + } + //INFO_PRINT("-> i:" + itos(i) + "/" + itos(this->_size) + " State:" + itos(this->_msgin[i].size_data()) + " num:" + itos(this->_received_number[i])); + //INFO_PRINT("i:" + itos(i) + " / " + itos(SIZE_QUEUE_MESSAGE) ); + this->_msgin[i].put_data(msgbytes); + int32_t current_received_number = this->_msgin[i].get_sint32(); + this->_received_number[i] = current_received_number; + + // Check we don't have other message with same _received_number (also remove it) + ii = i + 1; + while(ii < SIZE_QUEUE_MESSAGE) + { + if ( this->_received_number[ii] == current_received_number) + this->erase(ii); + ++ii; + } + this->_size ++; + /* + for(int ii = 0 ; ii < SIZE_QUEUE_MESSAGE ; ++ii) + { + INFO_PRINT(itos(ii) + ") i:" + itos(i) + "/" + itos(this->_size) + " State:" + itos(this->_msgin[ii].size_data()) + " num:" + itos(this->_received_number[ii])); + } + */ + return i; +} + +BitStream * StoreMessage::get_msg(int pos) +{ + if ( pos >= SIZE_QUEUE_MESSAGE ) + { + ERR_PRINT("Try to get data out of memory"); + throw "Out of memory"; + } + return & this->_msgin[pos]; +} + +int32_t StoreMessage::get_received_number(int pos) +{ + if ( pos >= SIZE_QUEUE_MESSAGE ) + { + ERR_PRINT("Try to get data out of memory"); + throw "Out of memory"; + } + return this->_received_number[pos]; +} + +void StoreMessage::erase(int pos) +{ + if ( pos >= SIZE_QUEUE_MESSAGE ) + { + ERR_PRINT("Try to erase data out of memory"); + return; + } + //this->_empty[pos] = true; + this->_received_number[pos] = 0; + this->_msgin[pos].clear(); + this->_size -- ; +} diff --git a/gdnative/src/store_message.h b/gdnative/src/store_message.h new file mode 100644 index 0000000..b85cda7 --- /dev/null +++ b/gdnative/src/store_message.h @@ -0,0 +1,47 @@ +/* + Header StoreMessage : message send by server + + 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 . + +*/ + +#ifndef STORE_MESSAGE_H +#define STORE_MESSAGE_H + +#define SIZE_QUEUE_MESSAGE 6 + +namespace godot { + +class StoreMessage +{ + // bool _empty[SIZE_QUEUE_MESSAGE]; + int32_t _received_number[SIZE_QUEUE_MESSAGE]; + BitStream _msgin[SIZE_QUEUE_MESSAGE]; + int _size; +public: + StoreMessage(); + ~StoreMessage(); + void clear(); + int length(); + int put_msgbytes(PoolByteArray & msgbytes); + BitStream * get_msg(int pos); + int32_t get_received_number(int pos); + void erase(int pos); +}; + +} + +#endif // STORE_MESSAGE_H diff --git a/gdnative/src/tools.cpp b/gdnative/src/tools.cpp new file mode 100644 index 0000000..4c4c2df --- /dev/null +++ b/gdnative/src/tools.cpp @@ -0,0 +1,29 @@ +/* + + 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 . + + */ + +#include +#include +#include "tools.h" + +using namespace godot; + +String godot::itos(int64_t p_val) +{ + return String::num_int64(p_val); +} diff --git a/gdnative/src/tools.h b/gdnative/src/tools.h new file mode 100644 index 0000000..0f2e014 --- /dev/null +++ b/gdnative/src/tools.h @@ -0,0 +1,44 @@ +/* + Header Tools + + 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 . + +*/ + +#ifndef TOOLS_H +#define TOOLS_H + +#include + +namespace godot { + +String itos(int64_t p_val); + +#define INFO_PRINT(msg) Godot::print( String(__FUNCTION__) + ":" + String(__FILE__) + ":" + itos( __LINE__) + " " + String(msg)) + +#ifdef DEBUG_ENABLED + +#define DEBUG_PRINT(msg) Godot::print( String(__FUNCTION__) + ":" + String(__FILE__) + ":" + itos( __LINE__) + " " + String(msg)) + +#else + +#define DEBUG_PRINT(msg) + +#endif + +} + +#endif // STORE_MESSAGE_H diff --git a/gdnative/test/bitset.gd b/gdnative/test/bitset.gd index 85d29b6..57f63a4 100644 --- a/gdnative/test/bitset.gd +++ b/gdnative/test/bitset.gd @@ -14,7 +14,7 @@ func _ready(): func test_resize(): var bitset = preload("res://bitset.gdns").new() - print ("[bitset:test_init]") + print ("[bitset:test_resize]") bitset.resize(1024) func test_put(): @@ -33,9 +33,20 @@ func test_put(): #print ("[bitset:test_init] " + bitset.show()) assert( bitset.show() == "0000000000000000000000000000010000000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") +func test_alloc(): + var BitSet = preload("res://bitset.gdns") + print ("[bitset:test_alloc]") + var tab = {} + tab[1478] = BitSet.new() + assert( tab.size() == 1 ) + tab[1479] = BitSet.new() + assert( tab.size() == 2 ) + tab.erase(1478) + assert( tab.size() == 1 ) func test(): print("[bitset] Start check -> start") test_resize() test_put() + test_alloc() print("[bitset] Start check -> end") diff --git a/gui_scene/GUI/login/login_menu.gd b/gui_scene/GUI/login/login_menu.gd index dbe7b65..54337a8 100644 --- a/gui_scene/GUI/login/login_menu.gd +++ b/gui_scene/GUI/login/login_menu.gd @@ -148,8 +148,10 @@ func _on_HTTPRequest_request_completed(result, response_code, headers, body): print("[login_menu:_on_HTTPRequest_request_completed] state:" + state + ", cookie:" + cookie + ", fsaddr:" + fsaddr + ", ringmainurl:" + ringmainurl + ", fartp:" + fartp + ", stat:" + stat + ", r2serverversion:" + r2serverversion + ", r2backuppatchurl:" + r2backuppatchurl + ", r2patchurl:" + r2patchurl) var server_info = server_info_script.nel_server_info.new(body.get_string_from_utf8()); - net_low_level.set_khaganat_server(khaganat_host, khaganat_port) - net_low_level.connect_to_server(UserAddr, UserKey, UserId) + var connexion = load("res://assets/Scripts/Config/connexion.gd").connexion.new() + var lang = connexion.get_language() + print("[login_menu:_on_HTTPRequest_request_completed] khaganat_host:" + khaganat_host + ", khaganat_port:" + str(khaganat_port)) + net_low_level.connect_to_server(khaganat_host, khaganat_port, UserAddr, UserKey, UserId, lang) emit_signal( "login_button_pressed" ) diff --git a/networkconnexion.gdns b/networkconnexion.gdns new file mode 100644 index 0000000..f3c3197 --- /dev/null +++ b/networkconnexion.gdns @@ -0,0 +1,7 @@ +[gd_resource type="NativeScript" load_steps=2 format=2] + +[ext_resource path="res://gdnative.gdnlib" type="GDNativeLibrary" id=1] + +[resource] +class_name = "NetworkConnection" +library = ExtResource( 1 ) diff --git a/project.godot b/project.godot index 5bf0fde..6e8097d 100644 --- a/project.godot +++ b/project.godot @@ -27,6 +27,10 @@ character="*res://game_scene/Game/Character/Character.tscn" net_low_level="*res://assets/Scripts/Network/net_low_level.gd" msg="*res://assets/Scripts/Definition/msg.gd" +[debug] + +settings/stdout/verbose_stdout=true + [display] window/size/width=1280