diff --git a/.gitignore b/.gitignore
index 5cfae44..2126236 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
.rust/
server/target/
+Godot_*
+.current_version
diff --git a/client/.gitignore b/client/.gitignore
new file mode 100644
index 0000000..0b0ef26
--- /dev/null
+++ b/client/.gitignore
@@ -0,0 +1,4 @@
+# Godot 4+ specific ignores
+.godot/
+assets/*.import
+*.import
diff --git a/client/assets/ground.jpg b/client/assets/ground.jpg
new file mode 100644
index 0000000..dee2d4a
Binary files /dev/null and b/client/assets/ground.jpg differ
diff --git a/client/assets/player.glb b/client/assets/player.glb
new file mode 100644
index 0000000..063fb8c
Binary files /dev/null and b/client/assets/player.glb differ
diff --git a/client/assets/root.glb b/client/assets/root.glb
new file mode 100644
index 0000000..6799653
Binary files /dev/null and b/client/assets/root.glb differ
diff --git a/client/assets/root.tscn b/client/assets/root.tscn
new file mode 100644
index 0000000..53dc81c
--- /dev/null
+++ b/client/assets/root.tscn
@@ -0,0 +1,13 @@
+[gd_scene load_steps=3 format=3 uid="uid://c688gu5xrshpg"]
+
+[ext_resource type="PackedScene" uid="uid://b5ej7nfagdlmf" path="res://assets/root.glb" id="1_s8vvr"]
+
+[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_rf26g"]
+data = PackedVector3Array(20, -1, -20, -21, -1, 20, -21, -1, -20, 20, -1, -20, 20, -1, 20, -21, -1, 20, 20, -3, 20, -21, -1, 20, 20, -1, 20, 20, -3, 20, -21, -3, 20, -21, -1, 20, -21, -3, 20, -21, -1, -20, -21, -1, 20, -21, -3, 20, -21, -3, -20, -21, -1, -20, -21, -3, -20, 20, -3, 20, 20, -3, -20, -21, -3, -20, -21, -3, 20, 20, -3, 20, 20, -3, -20, 20, -1, 20, 20, -1, -20, 20, -3, -20, 20, -3, 20, 20, -1, 20, -21, -3, -20, 20, -1, -20, -21, -1, -20, -21, -3, -20, 20, -3, -20, 20, -1, -20)
+
+[node name="root" instance=ExtResource("1_s8vvr")]
+
+[node name="StaticBody3D" type="StaticBody3D" parent="Cube" index="0"]
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="Cube/StaticBody3D" index="0"]
+shape = SubResource("ConcavePolygonShape3D_rf26g")
diff --git a/client/icon.svg b/client/icon.svg
new file mode 100644
index 0000000..b370ceb
--- /dev/null
+++ b/client/icon.svg
@@ -0,0 +1 @@
+
diff --git a/client/project.godot b/client/project.godot
new file mode 100644
index 0000000..6e4ed48
--- /dev/null
+++ b/client/project.godot
@@ -0,0 +1,60 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="Khaganat Short Client Server"
+run/main_scene="res://scenes/main.tscn"
+config/features=PackedStringArray("4.1", "Forward Plus")
+config/icon="res://icon.svg"
+
+[input]
+
+ui_left={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":113,"echo":false,"script":null)
+, null]
+}
+ui_right={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null)
+]
+}
+ui_up={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":122,"echo":false,"script":null)
+]
+}
+ui_down={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194322,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"echo":false,"script":null)
+]
+}
+ui_rotate_player={
+"deadzone": 0.5,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
+]
+}
+
+[rendering]
+
+environment/defaults/default_clear_color=Color(0.682353, 0.678431, 0.631373, 1)
diff --git a/client/scenes/Window.gd b/client/scenes/Window.gd
new file mode 100644
index 0000000..1b80c98
--- /dev/null
+++ b/client/scenes/Window.gd
@@ -0,0 +1,58 @@
+extends Window
+
+var focus_ok:bool = false
+var last_event = null
+
+# Called when the node enters the scene tree for the first time.
+func _ready():
+ pass # Replace with function body.
+
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+func _process(_delta):
+ pass
+
+
+func _on_button_pressed():
+ if $VBoxContainer/TextEdit.get_text() != "":
+ self.hide()
+ #get_parent().get_node("CharacterBody3D").set_enable_event(true)
+ get_parent().connect_enet($VBoxContainer/TextEdit.get_text())
+
+
+func _on_text_edit_text_changed(value:String):
+ if len(value) > 0:
+ $VBoxContainer/Button.disabled = false
+ else:
+ $VBoxContainer/Button.disabled = true
+
+
+func _on_focus_entered():
+ focus_ok = true
+
+
+func _on_focus_exited():
+ focus_ok = false
+
+
+func _on_mouse_entered():
+ focus_ok = true
+ self.get_parent().CharacterBody3D.disabled = true
+
+
+func _on_mouse_exited():
+ focus_ok = false
+ self.get_parent().CharacterBody3D.disabled = false
+
+func open_windows():
+ focus_ok = false
+ get_parent().get_node("CharacterBody3D").set_enable_event(false)
+ self.show()
+
+#func _on_window_input(event):
+# if event.is_pressed() == false:
+# return
+# if focus_ok:
+# return
+# if (event is InputEventKey) && (self.type_event == 1):
+# last_event = event
diff --git a/client/scenes/main.gd b/client/scenes/main.gd
new file mode 100644
index 0000000..31d868e
--- /dev/null
+++ b/client/scenes/main.gd
@@ -0,0 +1,299 @@
+extends Node3D
+
+# The player name.
+var player_name: String
+var connected:bool = false
+var enet:ENetConnection
+var dataEnet:ENetPacketPeer
+var errorEnet:Error
+var id = 0
+var maxplayer = 0
+
+# Server confirm our account
+var account_confirmed:bool = false
+
+const PLAYER = preload("res://scenes/player.tscn")
+
+const PORT = 33333
+const ADDR = "127.0.0.1"
+
+var dtls := PacketPeerDTLS.new()
+var udp := PacketPeerUDP.new()
+
+
+func test_cert(filename):
+ print("------", filename)
+ enet = ENetConnection.new()
+ print(enet)
+ #var cert: X509Certificate = X509Certificate.new()
+ #errorEnet = cert.load(filename)
+ #print("load cert:", errorEnet)
+ #print(cert)
+ #var client_tls_options = TLSOptions.client_unsafe(cert)
+ #print(client_tls_options)
+ errorEnet = enet.create_host(10)
+ if errorEnet != OK:
+ print("ERROR ENET.create_host: ", errorEnet)
+ return
+ #enet.connect_to_host(ADDR, PORT)
+ #errorEnet = enet.dtls_client_setup(ADDR, client_tls_options)
+ #print("dtls_client_setup:", errorEnet)
+ #if errorEnet != OK:
+ # print("ERROR ENET: ", errorEnet)
+ # return
+ dataEnet = enet.connect_to_host(ADDR, PORT, 10)
+ print(dataEnet)
+ if not dataEnet.is_active():
+ print("ERROR enet.connect_to_host: ", dataEnet.is_active())
+ return
+
+
+func create_server_enet():
+ print("------ create_server_enet")
+ test_cert("res://cert.crt")
+
+
+# Called when the node enters the scene tree for the first time.
+func _ready():
+ #test_cert("res://cert.crt")
+ create_server_enet()
+ pass # Replace with function body.
+
+
+func decode_msg(data:PackedByteArray):
+ print("==========================")
+ var cmd = data.decode_u8(0)
+ print("cmd:", cmd)
+ var taille = data.decode_u8(1)
+ print("taille:", taille)
+ var str:String = ""
+ var tmp = data.slice(2,taille+2)
+ print("tmp:", tmp)
+
+ str = tmp.get_string_from_utf8()
+
+ print("str:", str)
+ print("len str:", len(str))
+
+ print("==========================")
+
+func send_account():
+ var data:PackedByteArray = PackedByteArray()
+
+ #data.encode_u8(1,0)
+ data.append(1)
+ data.append(len(player_name))
+ var packed_array = player_name.to_ascii_buffer()
+# var str:PackedStringArray = PackedStringArray()
+# str.push_back(player_name)
+ data += packed_array
+ #data.append_array(str.to_byte_array())
+
+# print("-------------------------")
+# print(len(packed_array))
+# print("player_name: ", player_name)
+# print("packed_array: ", packed_array)
+# print("str: ", str)
+# print("str -> bytes: ", str.to_byte_array())
+# print("data: ", data)
+# print("-------------------------")
+
+ print(player_name, " -> size:", data.size(), " / " , len(player_name) )
+ errorEnet = dataEnet.send(1, data, 1)
+ if errorEnet != OK:
+ print("ERROR ENET: ", errorEnet)
+ return
+ #decode_msg(data)
+
+
+func set_player_position(pos: Vector3):
+ self.get_node("CharacterBody3D").set_global_position(pos)
+
+
+func get_player_position():
+ if not account_confirmed:
+ return
+ print("perso: ", id, " ", self.get_node("CharacterBody3D").get_position())
+ var pos:PackedFloat64Array = PackedFloat64Array()
+ var posRaw:Vector3 = self.get_node("CharacterBody3D").get_position()
+ #posRaw.x = 123456789182729270e15
+ #posRaw.y = 2.0
+ #posRaw.z = 3.0
+ pos.append(posRaw.x)
+ #print("x:", pos.to_byte_array())
+ pos.append(posRaw.y)
+ #print("x+y:", pos.to_byte_array())
+ pos.append(posRaw.z)
+ #print("x+y+z:", pos.to_byte_array())
+ var data:PackedByteArray = PackedByteArray()
+ data += pos.to_byte_array()
+ #data.append(len(player_name))
+ #var packed_array = player_name.to_ascii_buffer()
+ #data += packed_array
+ #print(player_name, " -> size:", data.size(), " / " , len(player_name) )
+ errorEnet = dataEnet.send(2, data, 1)
+ if errorEnet != OK:
+ print("ERROR ENET: ", errorEnet)
+ return
+
+
+func bad_acocunt():
+ player_name = ""
+ self.get_node("Window").open_windows()
+
+
+func get_event_received():
+ var data = dataEnet.get_packet()
+ print("get: ", data)
+ if data[0] == 1: # Return connexion
+ if data[1] == 0: # OK
+ id = data.decode_u64(2)
+ var x = data.decode_double(2+8)
+ var y = data.decode_double(2+16)
+ var z = data.decode_double(2+24)
+ print("id:", id, " x:", x, " y:", y, " z:", z)
+ self.set_player_position(Vector3(x, y, z))
+ account_confirmed = true
+ self.get_node("CharacterBody3D").set_enable_event(true)
+ else: # KO
+ bad_acocunt()
+ elif data[0] == 3: # Get position
+ if id == 0:
+ return
+ var nb = data[1]
+ var pos = 2
+ for i in nb:
+ var mid = data.decode_u64(pos)
+ var mx = data.decode_double(pos+8)
+ var my = data.decode_double(pos+16)
+ var mz = data.decode_double(pos+24)
+ pos += 32
+ if mid == id:
+ print("Me id:", mid, " x:", mx, " y:", my, " z:", mz)
+ continue
+ print("-- id:", mid, " x:", mx, " y:", my, " z:", mz)
+ var child = $Players.find_child(str(mid), false, false)
+ if child == null:
+ print("Not found")
+ if maxplayer > 3:
+ continue
+ var scene = preload("res://scenes/player.tscn")
+ var instance = scene.instantiate()
+ #var current_scene = scene.instance()
+ #var GrabbedInstance = PLAYER.instance()
+ instance.set_name(str(mid))
+ $Players.add_child(instance)
+ #$Players.add_child(scene)
+ maxplayer += 1
+ for child3 in $Players.get_children():
+ print(" -> ", child3.get_name())
+ var child2 = $Players.find_child(str(mid), false, false)
+ child2.set_global_position(Vector3(mx, my, mz))
+
+ else:
+ child.set_global_position(Vector3(mx, my, mz))
+ print("Found:", $Players.get_child_count())
+
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+func _process(_delta):
+ #print("state:", dataEnet.get_state())
+ get_player_position()
+ if dataEnet.get_state() == ENetPacketPeer.STATE_CONNECTED:
+ var event = enet.service()
+ if event[0] == ENetConnection.EVENT_RECEIVE:
+ #print("get: ", dataEnet.get_packet())
+ get_event_received()
+ if player_name != "" and not account_confirmed:
+ send_account()
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_CONNECTING:
+ var event = enet.service()
+ if event[0] == ENetConnection.EVENT_RECEIVE:
+ pass
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_DISCONNECTED:
+ var _event = enet.service()
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_ACKNOWLEDGING_CONNECT:
+ var _event = enet.service()
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_CONNECTION_PENDING:
+ var _event = enet.service()
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_CONNECTION_SUCCEEDED:
+ var _event = enet.service()
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_DISCONNECT_LATER:
+ var _event = enet.service()
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_DISCONNECTING:
+ var _event = enet.service()
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_ACKNOWLEDGING_DISCONNECT:
+ var _event = enet.service()
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_ZOMBIE:
+ var _event = enet.service()
+ else:
+ var _event = enet.service()
+
+
+func _process_ter(_delta):
+ var res = enet.service(1)
+ #print(res)
+ if res[0] == ENetConnection.EVENT_RECEIVE:
+ #print("EVENT_RECEIVE")
+ print(dataEnet.get_packet())
+ #if res[1]
+ var data:PackedByteArray = PackedByteArray()
+ data.append(len(player_name))
+ data.append(123)
+ errorEnet = dataEnet.send(1, data, 1)
+ if errorEnet != OK:
+ print("ERROR ENET: ", errorEnet)
+ return
+
+
+func _process_bis(_delta):
+ if not dataEnet.is_active():
+ create_server_enet()
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_CONNECTING:
+ var res = enet.service(1)
+ print(res)
+ elif dataEnet.get_state() == ENetPacketPeer.STATE_CONNECTED:
+ var res = enet.service(1)
+ print(res)
+ var data:PackedByteArray = PackedByteArray()
+ data.append(len(player_name))
+ data.append(123)
+ errorEnet = dataEnet.send(1, data, 1)
+ if errorEnet != OK:
+ print("ERROR ENET: ", errorEnet)
+ return
+ #print("<> get_state: ", dataEnet.get_state())
+ else:
+ print("get_state: ", dataEnet.get_state())
+ return
+
+ if not connected:
+ if player_name != "":
+ create_server_enet()
+ return
+ var res = enet.service(1)
+ print(res)
+ return
+ if not connected:
+ if player_name != "":
+ create_server_enet()
+ else:
+ var data:PackedByteArray = PackedByteArray()
+ data.append(len(player_name))
+ data.append(123)
+ #print(len(data))
+ print("active:", dataEnet.is_active())
+ print("state:", dataEnet.get_state())
+ print("address:", dataEnet.get_remote_address())
+ print("port:", dataEnet.get_remote_port())
+ errorEnet = dataEnet.send(1, data, 1)
+ if errorEnet != OK:
+ print("ERROR ENET: ", errorEnet)
+ return
+ #enet.socket_send(ADDR, PORT, data)
+
+
+func connect_enet(_name:String):
+ player_name = _name
+ print("My name:" + player_name)
+
diff --git a/client/scenes/main.gdshader b/client/scenes/main.gdshader
new file mode 100644
index 0000000..fc05ebc
--- /dev/null
+++ b/client/scenes/main.gdshader
@@ -0,0 +1,21 @@
+shader_type spatial;
+
+void fragment() {
+ bool v = false;
+ bool w = false;
+ float b = 0.0;
+ float g = 0.2;
+ float r = 0.0;
+ if ( mod(UV.x,0.005) > 0.0025 ) {
+ v = true;
+ };
+ if ( mod(UV.y,0.005) > 0.0025 ) {
+ w = true;
+ };
+ if ( ( v && ! w ) || ( !v && w ) ) {
+ b = 0.0;
+ g = 0.0;
+ r = 0.2;
+ }
+ ALBEDO = vec3(r, g, b);
+}
\ No newline at end of file
diff --git a/client/scenes/main.tscn b/client/scenes/main.tscn
new file mode 100644
index 0000000..65db350
--- /dev/null
+++ b/client/scenes/main.tscn
@@ -0,0 +1,89 @@
+[gd_scene load_steps=11 format=3 uid="uid://bemavktwweaog"]
+
+[ext_resource type="Shader" path="res://scenes/main.gdshader" id="1_caff6"]
+[ext_resource type="PackedScene" uid="uid://cg5uqqd4ibdem" path="res://scenes/player.tscn" id="1_nc7b3"]
+[ext_resource type="Script" path="res://scenes/main.gd" id="1_ts8of"]
+[ext_resource type="Script" path="res://scenes/Window.gd" id="3_uwnj8"]
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_5dcgs"]
+size = Vector3(1000, 1, 1000)
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_gypq5"]
+render_priority = 0
+shader = ExtResource("1_caff6")
+
+[sub_resource type="BoxMesh" id="BoxMesh_fm2j6"]
+material = SubResource("ShaderMaterial_gypq5")
+size = Vector3(1000, 1, 1000)
+
+[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_0qg6h"]
+
+[sub_resource type="Sky" id="Sky_i4xvw"]
+sky_material = SubResource("ProceduralSkyMaterial_0qg6h")
+
+[sub_resource type="Environment" id="Environment_12j7q"]
+background_mode = 2
+background_color = Color(0.803922, 0.776471, 0.733333, 1)
+sky = SubResource("Sky_i4xvw")
+ambient_light_color = Color(0.968627, 0.933333, 0.596078, 1)
+reflected_light_source = 2
+
+[node name="main" type="Node3D"]
+script = ExtResource("1_ts8of")
+
+[node name="ground" type="StaticBody3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0)
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="ground"]
+shape = SubResource("BoxShape3D_5dcgs")
+
+[node name="MeshInstance3D" type="MeshInstance3D" parent="ground"]
+mesh = SubResource("BoxMesh_fm2j6")
+
+[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
+transform = Transform3D(-0.866025, 0, -0.5, -0.25, 0.866025, 0.433013, 0.433013, 0.5, -0.75, 0, 50, 0)
+shadow_enabled = true
+shadow_opacity = 0.5
+
+[node name="CharacterBody3D" parent="." instance=ExtResource("1_nc7b3")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 6, 0)
+
+[node name="Players" type="Node3D" parent="."]
+
+[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
+environment = SubResource("Environment_12j7q")
+
+[node name="Window" type="Window" parent="."]
+title = "Connexion"
+initial_position = 1
+size = Vector2i(300, 100)
+script = ExtResource("3_uwnj8")
+
+[node name="VBoxContainer" type="VBoxContainer" parent="Window"]
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="Label" type="Label" parent="Window/VBoxContainer"]
+layout_mode = 2
+text = "Login"
+horizontal_alignment = 1
+
+[node name="TextEdit" type="LineEdit" parent="Window/VBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+placeholder_text = "Account"
+
+[node name="Button" type="Button" parent="Window/VBoxContainer"]
+layout_mode = 2
+disabled = true
+text = "OK"
+
+[connection signal="focus_entered" from="Window" to="Window" method="_on_focus_entered"]
+[connection signal="focus_exited" from="Window" to="Window" method="_on_focus_exited"]
+[connection signal="mouse_entered" from="Window" to="Window" method="_on_mouse_entered"]
+[connection signal="mouse_exited" from="Window" to="Window" method="_on_mouse_exited"]
+[connection signal="text_changed" from="Window/VBoxContainer/TextEdit" to="Window" method="_on_text_edit_text_changed"]
+[connection signal="pressed" from="Window/VBoxContainer/Button" to="Window" method="_on_button_pressed"]
diff --git a/client/scenes/player.gd b/client/scenes/player.gd
new file mode 100644
index 0000000..e936823
--- /dev/null
+++ b/client/scenes/player.gd
@@ -0,0 +1,67 @@
+extends CharacterBody3D
+
+
+const SPEED = 30.0
+const JUMP_VELOCITY = 14.5
+
+# Get the gravity from the project settings to be synced with RigidBody nodes.
+var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
+@export var event_disabled:bool = true
+
+# How fast the player moves in meters per second.
+@export var speed = 14
+# The downward acceleration when in the air, in meters per second squared.
+@export var fall_acceleration = 75
+
+var target_velocity = Vector3.ZERO
+
+var direction = Vector3.FORWARD
+var h_sensitivity:float = 0.1
+var v_sensitivity:float = 0.1
+var camrot_h:float = 0.0
+var camrot_v:float = 0.0
+var h_acceleration:float = 10.0
+var v_acceleration:float = 10.0
+var input_view_camera_move_player_follow_mouse:bool = false
+
+func _input(event):
+ if event_disabled:
+ return
+ if event is InputEventMouseButton:
+ if Input.is_action_pressed("ui_rotate_player"):
+ input_view_camera_move_player_follow_mouse = true
+ else:
+ input_view_camera_move_player_follow_mouse = false
+
+ if event is InputEventMouseMotion and input_view_camera_move_player_follow_mouse:
+ camrot_h += -event.relative.x * h_sensitivity
+ camrot_v += -event.relative.y * v_sensitivity
+
+func _physics_process(delta:float):
+ if event_disabled:
+ return
+ var h_rot:float = $h.global_transform.basis.get_euler().y
+ # Add the gravity.
+ if not is_on_floor():
+ velocity.y -= gravity * delta
+
+ # Handle Jump.
+ if Input.is_action_just_pressed("ui_accept") and is_on_floor():
+ velocity.y = JUMP_VELOCITY
+
+ # Get the input direction and handle the movement/deceleration.
+ # As good practice, you should replace UI actions with custom gameplay actions.
+ var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down").rotated(-h_rot)
+ direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
+ if direction:
+ velocity.x = direction.x * SPEED
+ velocity.z = direction.z * SPEED
+ else:
+ velocity.x = move_toward(velocity.x, 0, SPEED)
+ velocity.z = move_toward(velocity.z, 0, SPEED)
+ $h.rotation_degrees.y = lerp($h.rotation_degrees.y, camrot_h, delta * h_acceleration)
+ $h/v.rotation_degrees.x = lerp($h/v.rotation_degrees.x, camrot_v, delta * v_acceleration)
+ move_and_slide()
+
+func set_enable_event(state:bool):
+ event_disabled = ! state
diff --git a/client/scenes/player.tscn b/client/scenes/player.tscn
new file mode 100644
index 0000000..1d07649
--- /dev/null
+++ b/client/scenes/player.tscn
@@ -0,0 +1,24 @@
+[gd_scene load_steps=4 format=3 uid="uid://cg5uqqd4ibdem"]
+
+[ext_resource type="PackedScene" uid="uid://bng6cjt7kq1hv" path="res://assets/player.glb" id="1_bpxp1"]
+[ext_resource type="Script" path="res://scenes/player.gd" id="1_br7n0"]
+
+[sub_resource type="SphereShape3D" id="SphereShape3D_cjbav"]
+
+[node name="CharacterBody3D" type="CharacterBody3D"]
+script = ExtResource("1_br7n0")
+
+[node name="Pivot" type="Node3D" parent="."]
+
+[node name="player" parent="Pivot" instance=ExtResource("1_bpxp1")]
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
+transform = Transform3D(2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 1, 0)
+shape = SubResource("SphereShape3D_cjbav")
+
+[node name="h" type="Node3D" parent="."]
+
+[node name="v" type="Node3D" parent="h"]
+
+[node name="Camera3D" type="Camera3D" parent="h/v"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 5)
diff --git a/precheck.gd b/precheck.gd
new file mode 100644
index 0000000..f720f16
--- /dev/null
+++ b/precheck.gd
@@ -0,0 +1,37 @@
+extends MainLoop
+#extends Node
+
+# print("Example")
+
+
+# Called when the node enters the scene tree for the first time.
+#func _ready():
+# print("Example _ready")
+# # print( get_user_data_dir() )
+# # print(Performance.get_monitor(Performance.TIME_FPS))
+# pass # Replace with function body.
+
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+#func _process(delta):
+# print("Example _process")
+# pass
+func _process(delta):
+ return true
+
+func _init():
+ var info:String = ""
+ #info = get_base_script()
+ var processName:String = OS.get_processor_name()
+ var modelName:String = OS.get_model_name()
+ var osName:String = OS.get_name()
+ var version:String = OS.get_version()
+ var detailCardGraphics: PackedStringArray = OS.get_video_adapter_driver_info()
+ var idHardware:String = OS.get_unique_id()
+ var idGodot:String = str(Engine.get_version_info())
+ #for i in range(OS.get_screen_cound()):
+ # print(i)
+ var data = " - ".join(detailCardGraphics)
+ print( processName + "!" + modelName + "!" + osName + "!" + version + "!" + data + "!" + idHardware + "!" + idGodot)
+
+
diff --git a/start-bazar-client.sh b/start-bazar-client.sh
new file mode 100755
index 0000000..7b6de37
--- /dev/null
+++ b/start-bazar-client.sh
@@ -0,0 +1,181 @@
+#!/bin/bash
+
+declare DEBUG=0
+declare HELP=0
+declare EDITOR=0
+declare FORCE=0
+declare IMPORT=0
+declare ERASEIMPORT=0
+declare WORKDIR="$(dirname $(readlink -f $0))"
+declare GODOT_SRC="https://downloads.tuxfamily.org/godotengine/4.1.2/Godot_v4.1.2-stable_linux.x86_64.zip"
+declare OUTZIP="$WORKDIR/$(basename $GODOT_SRC)"
+declare CLIENTDIR="$WORKDIR/client"
+declare OPTION=""
+declare NEWPRG=0
+declare DISABLEAUTODETECTCARD=0
+
+function msg_debug()
+{
+ if [ $DEBUG -ne 0 ]
+ then
+ echo "### DEBUG : $*" >&2
+ fi
+}
+
+function msg_info()
+{
+ echo "--- INFO : $*" >&2
+}
+
+function msg_error()
+{
+ echo "*** ERROR : $*" >&2
+}
+
+function download()
+{
+ local package="$1"
+ local out="$2"
+ if [[ $FORCE -eq 0 && -f $2 ]]
+ then
+ return 0
+ fi
+ which curl 1>/dev/null 2>/dev/null
+ if [ $? -eq 0 ]
+ then
+ curl -o $out $package
+ if [ $? -eq 0 ]
+ then
+ msg_info "Package GODOT downloaded"
+ return 0
+ fi
+ fi
+ which wget 1>/dev/null 2>/dev/null
+ if [ $? -eq 0 ]
+ then
+ wget $package -O $out
+ if [ $? -eq 0 ]
+ then
+ msg_info "Package GODOT downloaded"
+ return 0
+ fi
+ fi
+ msg_error "Impossible to download"
+ exit 2
+}
+
+function extract()
+{
+ local compressed_file="$1"
+ which unzip 1>/dev/null 2>/dev/null
+ if [ $? -eq 0 ]
+ then
+ fileout=$(unzip -Z1 $compressed_file)
+ if [[ $FORCE -eq 0 && -f $fileout ]]
+ then
+ echo $fileout
+ return 0
+ fi
+ unzip -u $compressed_file -d $WORKDIR 1>&2
+ if [ $? -eq 0 ]
+ then
+ msg_info "Uncompressed GODOT"
+ echo $fileout
+ NEWPRG=1
+ return 0
+ fi
+ fi
+ msg_error "Impossible to extract"
+ exit 2
+}
+
+
+while getopts hdeo:s:fix flag
+do
+ case "${flag}" in
+ h) HELP=1;;
+ d) DEBUG=1;;
+ e) EDITOR=1;;
+ o) OUTZIP=${OPTARG};;
+ s) GODOT_SRC=${OPTARG};;
+ f) FORCE=1;;
+ i) IMPORT=1;;
+ x) ERASEIMPORT=1;;
+ y) DISABLEAUTODETECTCARD=1;;
+ *) HELP=1;;
+ esac
+done
+
+if [[ $HELP -ne 0 ]]
+then
+ cat << EOF
+$(basename $0) [Option] : Donwload Launch Godot
+ Option:
+ -h : Show help
+ -d : Show debug message
+ -e : Start Godot in editor mode
+ -f : force download & uncompress
+ -i : force import data
+ -x : erase import data
+ -y : Disable auto detect host (OS/CPU/GPU)
+ -o : target godot file (downloaded)
+ -s : Url to download a specific godot version
+EOF
+ exit 1
+fi
+
+msg_info "Start"
+msg_debug "WORKDIR:$WORKDIR OUTZIP:$OUTZIP GODOT_SRC:$GODOT_SRC"
+download "$GODOT_SRC" "$OUTZIP"
+EXE=$(extract "$OUTZIP")
+msg_info "Prg:$EXE"
+
+if [ $NEWPRG -ne 0 ]
+then
+ echo "--- New program detected"
+ ERASEIMPORT=1
+ IMPORT=1
+elif [ $DISABLEAUTODETECTCARD -eq 0 ]
+then
+ echo "--- Check host"
+ $WORKDIR/$EXE --script precheck.gd > $WORKDIR/.current_version.tmp
+ if [ -f $WORKDIR/.current_version ]
+ then
+ diff $WORKDIR/.current_version.tmp $WORKDIR/.current_version >/dev/null
+ if [ $? -ne 0 ]
+ then
+ ERASEIMPORT=1
+ IMPORT=1
+ mv $WORKDIR/.current_version.tmp $WORKDIR/.current_version
+ else
+ rm $WORKDIR/.current_version.tmp
+ fi
+ else
+ ERASEIMPORT=1
+ IMPORT=1
+ mv $WORKDIR/.current_version.tmp $WORKDIR/.current_version
+ fi
+fi
+
+if [ $ERASEIMPORT -ne 0 ]
+then
+ echo "--- Erase imported data"
+ rm -f $WORKDIR/.godot/imported/*
+fi
+
+if [[ ($IMPORT -ne 0) || (! -d $WORKDIR/.godot) ]]
+then
+ echo "--- Launch import (please wait)"
+ $WORKDIR/$EXE --editor --quit
+ echo "--- Import finished"
+fi
+
+if [ $EDITOR -ne 0 ]
+then
+ OPTION="$OPTION -e"
+fi
+
+cd $CLIENTDIR
+$WORKDIR/$EXE $OPTION
+
+msg_info "End"