diff --git a/client/Stream/Stream.gd b/client/Stream/Stream.gd new file mode 100644 index 0000000..109b456 --- /dev/null +++ b/client/Stream/Stream.gd @@ -0,0 +1,335 @@ +extends Node + +# Stream XMPP +# Author : AleaJactaEst +# +# https://xmpp.org/extensions/xep-0178.html +# https://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml + + +# Boucle +# - non connecte +# - connecte en claire +# - connecte en TLS +# - lance l'authentification +# - step authentification +# - identifie + +signal send_msg_debug(message:String) +signal send_msg_error(message:String) +signal new_stanza(stanza) + +enum StreamState { + END, # Stream is over. Starting with this. + START, # Stream hass started. + TLS, # Connection has been made and the first header is send. Let's get ssl! + AUTHENTICATE, # We have negotiated whether to use TLS, let's authenticate. + STANZA # We have authenticated, account is now allowed to send stanzas +} +var stream_status = StreamState.END + +@export var server_ip:String = "localhost": + set = set_server_ip, get = get_server_ip + +func set_server_ip(value:String): + server_ip = value + +func get_server_ip() -> String: + return server_ip + +@export var port_number:int = 5222: + set = set_port_number, get = get_port_number + +func set_port_number(value:int): + port_number = value + +func get_port_number() -> int: + return port_number + +@export var account_name:String = "undefined@localhost": + set = set_account_name, get = get_account_name + +func set_account_name(value:String): + account_name = value + +func get_account_name() -> String: + return account_name + +@export var password:String = "undefined": + set = set_password, get = get_password + +func set_password(value:String): + password = value + +func get_password() -> String: + return password + +@export var locale:String = "en": + set = set_locale, get = get_locale + +func set_locale(value:String): + locale = value + +func get_locale() -> String: + return locale + +@export var xmppclient:bool = false: + get: + return xmppclient + set(value): + xmppclient = value + +var try_connect:int = 0 +var count_connecting_time:float = 0 +var partial_stanza:String = "" +var tcp_peer:StreamPeerTCP = StreamPeerTCP.new() +var ssl_peer:StreamPeerTLS = StreamPeerTLS.new() +var tgt_peer = null +var status:StreamState = StreamState.END + + +func _init(): + var language = OS.get_locale() + set_locale(language) + tgt_peer = tcp_peer + +func _process(delta): + #Global.msg_info("TCP:%d", [tcp_peer.get_status()]) + print(server_ip, ":", port_number, " / get_status:" , tcp_peer.get_status(), " / count_connecting_time:", count_connecting_time, " / stream_status:", stream_status) +# if tcp_peer.get_status() == StreamPeerTCP.STATUS_NONE and stream_status == self.StreamState.TLS: +# #negotiate_tls() +# print("negotiate_tls") +# pass + if (tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED) : + print("STATUS_CONNECTED:", delta) + if (tgt_peer.has_method("poll")): + tgt_peer.poll() + if tgt_peer.get_available_bytes()>0: + var response = tgt_peer.get_string(tgt_peer.get_available_bytes()) + send_msg_debug.emit("Stream: response: " + response) + if stream_status == self.StreamState.STANZA: + #collect_stanza(remove_stream_header(response)) + Global.msg_info("", []) + print("collect_stanza") + else: + print("stream_process") + stream_process(remove_stream_header(response)) +# print(remove_stream_header(response)) + elif stream_status == self.StreamState.END: + start_stream() + stream_status = self.StreamState.START + count_connecting_time = 0 + if tgt_peer.get_status() == StreamPeerTCP.STATUS_CONNECTING: + print("STATUS_CONNECTING:", delta) + count_connecting_time += delta + if (tgt_peer.has_method("poll")): + tgt_peer.poll() + if count_connecting_time > 60: # (1 -> 1s) if it took more than 1s to connect, error + print("**** Stream: Stuck connecting, will now disconnect") + Global.msg_error("Stream: Stuck connecting, will now disconnect", []) + send_msg_debug.emit("Stream: Stuck connecting, will now disconnect") + tgt_peer.disconnect_from_host() #interrupts connection to nothing + set_process(false) # stop listening for packets + try_connect = 20 + stream_status = self.StreamState.END + if tgt_peer.get_status() == StreamPeerTCP.STATUS_NONE and xmppclient: + print("connect_to_server:", xmppclient) + connect_to_server() + xmppclient = false + + +func connect_to_server(): + """ Connect to the server ip and port, and start checking whether there's stream info yet. """ + if tcp_peer.get_status() == StreamPeerTCP.STATUS_CONNECTED: + pass + if try_connect == 0 and tcp_peer.get_status() == StreamPeerTCP.STATUS_NONE: + #print("-> ", server_ip, ":", port_number, "/" , tcp_peer.get_status()) + var res = tcp_peer.connect_to_host(server_ip, port_number) + if res == OK: + count_connecting_time = 0 + stream_status = self.StreamState.END + set_process(true) + tgt_peer = tcp_peer + else: + try_connect = 20 + else: + try_connect -= 1 + + +func send_string(stanza:String) ->void: + """ Send a string in the appropriate encoding. """ + send_msg_debug.emit("Sending data: '%'".format([stanza], "%")) + tgt_peer.put_data(stanza.to_utf8_buffer()) + + +func conv_string_to_PackedByteArray(message:String) -> PackedByteArray: + return message.to_ascii_buffer() + + +#func send_PackedByteArray(message:PackedByteArray) -> void: +# """ Send a PackedByteArray """ +# send_msg_debug.emit("Sending data: '" + message.get_string_from_utf8() + "'") +# tgt_peer.put_data(message) + + +func start_stream() -> void: + """ Send the stream header. + Needs to be done several times over stream negotiation. + """ + var server_name = account_name.split("@")[-1] + var message:String = "" + \ + " " + # " from=\"" + account_name + "\" " + \ + # + locale + "'" + + print(message) + send_string(message) + +func remove_stream_header(text :String) -> String: + var index = 0 + if text.begins_with("") + text = text.substr(index+2).strip_edges() + # strip stream header + var rg = RegEx.new() + rg.compile("<\\s?(stream|stream:stream)\\s") + var result = rg.search(text) + if result: + send_msg_debug.emit("Stream: Response header received") + index = text.find(">", result.get_end()) + text = text.substr(index+1) + return text + + +func stream_process(response :String = "") -> void: + """ Try to authenticate using SASL. We can currently only do plain. + For SCRAM based methods, we need HMAC at the very least. + """ + + if (!response.length() == 0 and stream_status != self.StreamState.STANZA): + if response.begins_with(" 0): + var tmp:String = "" + var sep:String = "" + for item in authentication_methods: + tmp += sep + item + sep = ", " + send_msg_debug.emit("Stream: authentication methods: " + tmp) + negotiate_sasl(authentication_methods) + stream_status = self.StreamState.AUTHENTICATE + + else: + if stream_status == StreamState.TLS: + if response.begins_with(" void: + #var ssl_peer = StreamPeerTLS.new() + # I am unsure how to validate the ssl certificate for an unknown host? + #var ssl_succes = FAILED + var options:TLSOptions = TLSOptions.client_unsafe() + print("accept_stream") + #var ssl_succes = ssl_peer.accept_stream(tcp_peer, options) + var ssl_succes = ssl_peer.connect_to_stream(tcp_peer, "localhost", options) + print("resultat:", ssl_succes) + if ssl_succes == OK: + send_msg_debug.emit("Stream: switched to SSL!") + print("get_status:", ssl_peer.get_status()) + # Wait connection done + while ssl_peer.get_status() == StreamPeerTLS.STATUS_HANDSHAKING: + ssl_peer.poll() + print("get_status:", ssl_peer.get_status()) + tgt_peer = ssl_peer + start_stream() + print("get_status:", ssl_peer.get_status()) + print("-----") + #stream_status == StreamState.START + else: + send_msg_error.emit("SSL failed, error %".format([ssl_succes], "%")) + + +func negotiate_sasl(authentication_methods : Array) -> void: + if (!authentication_methods.has("PLAIN")): + end_stream() + send_msg_debug.emit("Stream: sending request for plain") + var msg:PackedByteArray = PackedByteArray() + msg.push_back(0) + var t = account_name.split("@")[0] + msg += t.to_ascii_buffer() + #msg += conv_string_to_PackedByteArray(account_name.split("@")[0]) + msg.push_back(0) + msg += password.to_ascii_buffer() + print("7:", msg) + + var auth_account:String = Marshalls.raw_to_base64(msg) + var request_sasl:String = "" + auth_account + "" + send_string(request_sasl) + + +func end_stream() -> void: + """ End the stream """ + send_msg_debug.emit("Stream: Ending stream") + send_string("") + if tcp_peer.has_method("disconnect_from_stream"): + tcp_peer.disconnect_from_stream() + else: + tcp_peer.disconnect_from_host() + set_process(false) + stream_status = StreamState.END diff --git a/client/Stream/xmpp_stream_errors.gd b/client/Stream/xmpp_stream_errors.gd new file mode 100644 index 0000000..a2d56d8 --- /dev/null +++ b/client/Stream/xmpp_stream_errors.gd @@ -0,0 +1,147 @@ +### +# This file is part of Godot XMPP Client +# SPDX-FileCopyrightText: 2020 Wolthera van Hovell tot Westerflier +# +# SPDX-License-Identifier: MIT +### + +extends Resource + +class_name XMPPStreamError + +### +# This is a parser for stream errors, that keeps a list of human friendly error-explainations. +# Stream errors, unlike stanza errors, will always close the stream. +### + +enum StreamErrorTypes{ + bad_format, + bad_namespace_prefix, + conflict, + connection_timeout, + host_gone, + host_unknown, + improper_addressing, + internal_server_error, + invalid_from, + invalid_namespace, + invalid_xml, + not_authorized, + not_well_formed, + policy_violation, + remote_connection_failed, + reset, + resource_constraint, + restricted_xml, + see_other_host, + system_shutdown, + undefined_condition, + unsupported_encoding, + unsupported_feature, + unsupported_stanza_type, + unsupported_version +} + +var humane_error_messages = { + StreamErrorTypes.bad_format: + tr("The sent message cannot be processed."), + StreamErrorTypes.bad_namespace_prefix: + tr("The namespace cannot be recognized"), + StreamErrorTypes.conflict: + tr("This connection conflicts with another connection coming from the same address, which makes it impossible to differentiate between the connections."), + StreamErrorTypes.connection_timeout: + tr("This client took too long to respond, and thus the server assumed the device had lost internet connection."), + StreamErrorTypes.host_gone: + tr("The address of the server has changed."), + StreamErrorTypes.host_unknown: + tr("The server does not know the address."), + StreamErrorTypes.improper_addressing: + tr("The address is missing from the sent message."), + StreamErrorTypes.internal_server_error: + tr("The server is experiencing issues, try again later."), + StreamErrorTypes.invalid_from: + tr("This connection is not allowed to sign it's messages with the given address."), + StreamErrorTypes.invalid_namespace: + tr("The message was formatted with an incorrect namespace."), + StreamErrorTypes.invalid_xml: + tr("The message was formatted with invalid xml."), + StreamErrorTypes.not_authorized: + tr("The client is not allowed to sent these messages because it is not authorized to do so."), + StreamErrorTypes.not_well_formed: + tr("The message was formatted with incorrectly formed xml."), + StreamErrorTypes.policy_violation: + tr("The server determined the message violated server policy in some technical manner."), + StreamErrorTypes.remote_connection_failed: + tr("The server is unable to deliver the message because it cannot connect to the other server."), + StreamErrorTypes.reset: + tr("The server closed the connection because it deemed to connection needed to be reset for either feature or security purposes."), + StreamErrorTypes.resource_constraint: + tr("The server is too busy to handle this stream."), + StreamErrorTypes.restricted_xml: + tr("The message contained restricted xml (such as comments, processing instructions, dtd subset, or an xml entity reference)"), + StreamErrorTypes.see_other_host: + tr("The server is redirecting the client to a different host."), + StreamErrorTypes.system_shutdown: + tr("The server is being shut down."), + StreamErrorTypes.undefined_condition: + tr("A special case error has occured. See included xml stream."), + StreamErrorTypes.unsupported_encoding: + tr("The message was encoded with an encoding other than UTF-8, or contained extra bytes that the server is not expecting (as possible with godot's tls functions)."), + StreamErrorTypes.unsupported_feature: + tr("The required stream features are not supported."), + StreamErrorTypes.unsupported_stanza_type: + tr("The sent message is of a stanza type that the server does not recognize."), + StreamErrorTypes.unsupported_version: + tr("This server does not support XMPP version 1.0") +} + +var error_type = StreamErrorTypes.undefined_condition +var extra_data = "" + + +func parse_from_xml(xml:String): + var parser = XMLParser.new() + parser.open_buffer(xml.to_utf8_buffer()) + parse_with_parser(parser) + + +func parse_with_parser(parser:XMLParser): + # Read the error element + if parser.read() == OK and parser.get_node_name() == "stream:error": + if parser.is_empty(): + error_type = 0 + # Read the error inside... + if parser.read() == OK: + var error_name = parser.get_node_name().replace("-", "_") + error_type = StreamErrorTypes[error_name] + if !parser.is_empty() and parser.read() == OK: + extra_data = parser.get_node_data() + return OK + + +func stanza() -> String: + var stanza = [] + stanza.append("") + var error_name = error_name_for_enum(error_type) + if !error_type.empty(): + stanza.append("<"+error_name) + stanza.append("xmlns='urn:ietf:params:xml:ns:xmpp-streams'") + if extra_data.empty(): + stanza.append("/>") + else: + stanza.append(">"+extra_data+"") + stanza.append("") + return stanza.join(" ") + + +func error_name_for_enum(value :int) -> String: + var error_name:String = "" + for i in StreamErrorTypes.keys(): + if StreamErrorTypes[i] == value: + error_name = str(i).replace("_", "-") + return error_name + + +func human_friendly_error_message() -> String: + """ Human friendly error messages for the error dialogue. """ + return humane_error_messages[error_type] diff --git a/client/Stream/xmpp_stream_features.gd b/client/Stream/xmpp_stream_features.gd new file mode 100644 index 0000000..0375c10 --- /dev/null +++ b/client/Stream/xmpp_stream_features.gd @@ -0,0 +1,88 @@ +### +# This file is part of Godot XMPP Client +# SPDX-FileCopyrightText: 2020 Wolthera van Hovell tot Westerflier +# +# SPDX-License-Identifier: MIT +### + +extends Resource + +class_name XMPPStreamFeatures + +### +# Parser for stream features. +## + +@export var xml_string:String = "": + set = parse_from_xml + +@export var parsedDictionary:Dictionary = {} + +enum FeatureReq{ + NO_FEATURE, + NO_REQ, + OPTIONAL, + REQUIRED +} + + +func feature_done(feature:String): + """ Remove the entry as it's done. """ + parsedDictionary.erase(feature) + + +func parse_from_xml(xml:String): + var parser = XMLParser.new() + parser.open_buffer(xml.to_utf8_buffer()) + parser.read() + parse_children(parser, parser.get_node_name()) + + +func parse_children(parser:XMLParser, _parent_name:String): + parsedDictionary = {} + while (parser.read() == OK): + if (parser.get_node_type()== XMLParser.NODE_ELEMENT): + var node_name = parser.get_node_name() + if !parser.is_empty(): + match(node_name): + "mechanisms": + parsedDictionary[node_name] = parse_option_list(parser, node_name, "mechanism") + "compression": + parsedDictionary[node_name] = parse_option_list(parser, node_name, "method") + _: + parsedDictionary[node_name] = parse_requirement(parser, node_name) + else: + parsedDictionary[node_name] = FeatureReq.NO_REQ + # else: + # print("Unhandled xml node type: "+str(parser.get_node_type())) + + +func parse_requirement(parser:XMLParser, parent_name:String): + var required = self.FeatureReq.NO_REQ + while (parser.read() == OK): + if (parser.get_node_type()== XMLParser.NODE_ELEMENT): + var node_name = parser.get_node_name() + if parser.is_empty(): + if node_name == "required": + return self.FeatureReq.REQUIRED + elif node_name == "optional": + return self.FeatureReq.OPTIONAL + elif(parser.get_node_type()== XMLParser.NODE_ELEMENT_END): + var node_name = parser.get_node_name() + if node_name == parent_name: + return required + + +func parse_option_list(parser:XMLParser, parent_name:String, option_name:String): + var options = [] + while (parser.read() == OK): + var _result + if (parser.get_node_type()== XMLParser.NODE_ELEMENT): + if parser.get_node_name() == option_name: + _result =parser.read() + if (parser.get_node_type()== XMLParser.NODE_TEXT): + options.append(parser.get_node_data()) + _result = parser.read() + elif(parser.get_node_type()== XMLParser.NODE_ELEMENT_END): + if parser.get_node_name() == parent_name: + return options diff --git a/client/player/CharacterMovementComponent.gd b/client/player/CharacterMovementComponent.gd index 05831f9..dd2cda7 100644 --- a/client/player/CharacterMovementComponent.gd +++ b/client/player/CharacterMovementComponent.gd @@ -315,21 +315,21 @@ var pose_warping_instance = PoseWarping.new() func _process(delta): - Global.msg_info("delta: %f", [delta]) + Global.msg_debug("delta: %f", [delta]) calc_animation_data() var orientation_warping_condition = rotation_mode != Global.ROTATION_MODE.VELOCITY_DIRECTION and \ movement_state == Global.MOVEMENT_STATE.GROUNDED and \ movement_action == Global.MOVEMENT_ACTION.NONE and \ gait != Global.GAIT.SPRINTING and \ input_is_moving - Global.msg_info("orientation_warping_condition:%s", [str(orientation_warping_condition)]) + Global.msg_debug("orientation_warping_condition:%s", [str(orientation_warping_condition)]) pose_warping_instance.orientation_warping( orientation_warping_condition,camera_root.HObject,animation_velocity,skeleton_ref,"Hips",["Spine","Spine1","Spine2"],0.0,delta) func _physics_process(delta): #Debug() # - Global.msg_info("delta: %f", [delta]) + Global.msg_debug("delta: %f", [delta]) aim_rate_h = abs((camera_root.HObject.rotation.y - previous_aim_rate_h) / delta) previous_aim_rate_h = camera_root.HObject.rotation.y @@ -382,15 +382,15 @@ func _physics_process(delta): #------------------ Gravity ------------------# if is_flying == false and character_node is CharacterBody3D: character_node.velocity.y = lerp(character_node.velocity.y,vertical_velocity.y - character_node.get_floor_normal().y,delta * gravity) - Global.msg_info("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)]) + Global.msg_debug("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)]) var collided = character_node.move_and_slide() - Global.msg_info("ID:%d velocity:%s collided:%s" , [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity), str(collided)]) + Global.msg_debug("ID:%d velocity:%s collided:%s" , [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity), str(collided)]) if character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z > 0.5: input_is_moving = true - Global.msg_info("ID:%d distance^2:%s true", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z )]) + Global.msg_debug("ID:%d distance^2:%s true", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z )]) else: input_is_moving = false - Global.msg_info("ID:%d distance^2:%s false", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z )]) + Global.msg_debug("ID:%d distance^2:%s false", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity.x * character_node.velocity.x + character_node.velocity.z * character_node.velocity.z )]) if ground_check.is_colliding() and is_flying == false: movement_state = Global.MOVEMENT_STATE.GROUNDED @@ -584,13 +584,13 @@ func add_movement_input(direction: Vector3 = Vector3.ZERO, Speed: float = 0, Acc if is_flying == false: character_node.velocity.x = lerp(character_node.velocity.x,(direction*max_speed).x,Acceleration/(max_speed if max_speed != 0 else (abs(character_node.velocity.x) if character_node.velocity.x != 0 else 1.0))*get_physics_process_delta_time()) character_node.velocity.z = lerp(character_node.velocity.z,(direction*max_speed).z,Acceleration/(max_speed if max_speed != 0 else (abs(character_node.velocity.z) if character_node.velocity.z != 0 else 1.0))*get_physics_process_delta_time()) - Global.msg_info("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)]) + Global.msg_debug("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)]) else: character_node.velocity = character_node.velocity.lerp((direction*max_speed),Acceleration/(max_speed if max_speed != 0 else character_node.velocity.x if character_node.velocity.x != 0 else 1.0)*get_physics_process_delta_time()) var body_collided = character_node.move_and_slide() - Global.msg_info("ID:%d body_collided:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(body_collided)]) + Global.msg_debug("ID:%d body_collided:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(body_collided)]) # Get the velocity from the character node - Global.msg_info("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)]) + Global.msg_debug("ID:%d velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity)]) var character_node_velocity = character_node.velocity if character_node is CharacterBody3D else character_node.linear_velocity @@ -598,7 +598,7 @@ func add_movement_input(direction: Vector3 = Vector3.ZERO, Speed: float = 0, Acc movement_direction = atan2(input_velocity.x,input_velocity.z) #input_is_moving = input_velocity.length() > 0.0 input_acceleration = Acceleration * direction * (1 if max_speed != 0 else -1) - Global.msg_info("ID:%d velocity:%s input_velocity:%s direction:%s input_acceleration:%s character_node_velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity), str(input_velocity.length()), str(direction), str(input_acceleration), str(character_node_velocity)]) + Global.msg_debug("ID:%d velocity:%s input_velocity:%s direction:%s input_acceleration:%s character_node_velocity:%s", [character_node.get_node("PlayerNetworkingComponent").id, str(character_node.velocity), str(input_velocity.length()), str(direction), str(input_acceleration), str(character_node_velocity)]) # actual_acceleration = (character_node_velocity - PrevVelocity) / (get_physics_process_delta_time()) PrevVelocity = character_node_velocity diff --git a/client/project.godot b/client/project.godot index 6828c92..818c179 100644 --- a/client/project.godot +++ b/client/project.godot @@ -18,7 +18,8 @@ config/icon="res://icon.svg" [autoload] Multi="*res://scenes/multi.gd" -Global="*res://player/Global.gd" +Global="*res://scripts/Global.gd" +Stream="*res://Stream/Stream.gd" [display] diff --git a/client/scenes/main.gd b/client/scenes/main.gd index c6de0bc..86975cb 100644 --- a/client/scenes/main.gd +++ b/client/scenes/main.gd @@ -35,8 +35,21 @@ func _ready(): Multi.update_my_position.connect(_on_update_me) Multi.update_player_position.connect(_on_update_player) Multi.remove_player.connect(_on_remove_player) + Stream.set_server_ip("localhost") + Stream.set_port_number(5222) + Stream.send_msg_debug.connect(show_stream_debug) + Stream.send_msg_error.connect(show_stream_error) #$Window.world_2d = _MainWindow.world_2d + +func show_stream_debug(msg:String): + print("DEBUG [Stream] ", msg) + + +func show_stream_error(msg:String): + print("ERROR [Stream] ", msg) + + func create_view_window(): pass # var new_window: Window = view_window.instantiate() @@ -77,6 +90,7 @@ func _on_connexion_updated(new_state:Multi.Connexion): $PlayerSpawnLocation.get_child(0).set_activate() $PlayerSpawnLocation.set_visible(true) $CameraStarting.set_current(false) + Stream.xmppclient = true else: $CameraStarting.set_current(true) $Panel/State.set_text("Unknown") diff --git a/client/player/Global.gd b/client/scripts/Global.gd similarity index 100% rename from client/player/Global.gd rename to client/scripts/Global.gd diff --git a/start-bazar-fake-xmpp-server.sh b/start-bazar-fake-xmpp-server.sh new file mode 100755 index 0000000..b3621ef --- /dev/null +++ b/start-bazar-fake-xmpp-server.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +declare WORKDIR="$(dirname $(readlink -f $0))" +declare XMPPDIR="$WORKDIR/.xmpp" + +echo "WORKDIR:$WORKDIR" +echo "XMPPDIR:$XMPPDIR" +docker pull ejabberd/ecs + +#if [ ! -d $XMPPDIR ] +#then +# mkdir -p $XMPPDIR +# sudo chown 9000:9000 database +#fi + +list=$( docker ps -q -a -f name="ejabberd") +if [ -z "$list" ] +then + docker run --name ejabberd \ + --publish 5222:5222 \ + --publish 5269:5269 \ + --publish 5280:5280 \ + --publish 5443:5443 \ + --publish 1883:1883 \ + ejabberd/ecs +else + docker start ejabberd + docker logs -f ejabberd + docker stop +fi + +# https://localhost:5443/admin/ +# docker exec -it ejabberd bin/ejabberdctl register admin localhost passw0rd +# docker exec -it ejabberd bin/ejabberdctl register toto localhost toto +# docker exec -it ejabberd bin/ejabberdctl status +# docker exec -it ejabberd bin/ejabberdctl stats registeredusers +# docker exec -it ejabberd bin/ejabberdctl register titi localhost titi +# docker exec -it ejabberd bin/ejabberdctl register undefined localhost undefined +