diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5cfae44
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.rust/
+server/target/
diff --git a/LICENCE.txt b/LICENCE.txt
new file mode 100644
index 0000000..4cde7e4
--- /dev/null
+++ b/LICENCE.txt
@@ -0,0 +1,18 @@
+
+ Server Rust/Client Godot - Simple Multiplayer
+
+ Copyright (C) 2023 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 .
+
diff --git a/server/Cargo.lock b/server/Cargo.lock
new file mode 100644
index 0000000..1ce74a0
--- /dev/null
+++ b/server/Cargo.lock
@@ -0,0 +1,609 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bindgen"
+version = "0.65.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5"
+dependencies = [
+ "bitflags 1.3.2",
+ "cexpr",
+ "clang-sys",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "peeking_take_while",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn",
+ "which",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+
+[[package]]
+name = "bumpalo"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cc"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "wasm-bindgen",
+ "windows-targets",
+]
+
+[[package]]
+name = "clang-sys"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "cmake"
+version = "0.1.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+
+[[package]]
+name = "either"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+
+[[package]]
+name = "enet"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd5c84ebdecb28194d15e063436a4b7863546a9dea268aee131ca23dbb2a21ac"
+dependencies = [
+ "enet-sys",
+ "thiserror",
+]
+
+[[package]]
+name = "enet-sys"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4580f5cb34ba20a73d05e26876f05fd3830a8959fb594b1ecb4d9ddac2eec77"
+dependencies = [
+ "bindgen",
+ "cmake",
+]
+
+[[package]]
+name = "errno"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "home"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "libc"
+version = "0.2.149"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
+
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
+
+[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "memchr"
+version = "2.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+
+[[package]]
+name = "prettyplease"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustix"
+version = "0.38.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed"
+dependencies = [
+ "bitflags 2.4.1",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
+name = "server"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "byteorder",
+ "chrono",
+ "enet",
+ "log",
+]
+
+[[package]]
+name = "shlex"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
+
+[[package]]
+name = "syn"
+version = "2.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.49"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.49"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+
+[[package]]
+name = "which"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
+dependencies = [
+ "either",
+ "home",
+ "once_cell",
+ "rustix",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-core"
+version = "0.51.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
diff --git a/server/Cargo.toml b/server/Cargo.toml
new file mode 100644
index 0000000..23c5d26
--- /dev/null
+++ b/server/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "server"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+enet = "0.3.0"
+anyhow = "1.0.56"
+log = "0.4.20"
+chrono = "0.4.31"
+byteorder = "1.5.0"
diff --git a/server/src/main.rs b/server/src/main.rs
new file mode 100644
index 0000000..28d602e
--- /dev/null
+++ b/server/src/main.rs
@@ -0,0 +1,656 @@
+extern crate enet;
+
+/*
+
+ Server minimal
+
+ Author : Aleajactaest
+ Created : 10 October 2023
+
+ Build:
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+ source $HOME/.cargo/env
+ cargo build
+ target/debug/server-rust
+*/
+
+use std::net::Ipv4Addr;
+use log::{debug, error, info, trace, warn, Level, LevelFilter, Metadata, Record, SetLoggerError};
+
+
+use anyhow::Context;
+use enet::*;
+use std::*;
+use chrono::Utc;
+use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
+
+
+struct ServerLogger;
+
+impl log::Log for ServerLogger {
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ metadata.level() <= Level::Info
+ }
+
+ fn log(&self, record: &Record) {
+ //if self.enabled(record.metadata()) {
+ println!("{} [ {:5} ] {}", Utc::now().format("%Y-%m-%dT%H:%M:%SZ"), record.level(), record.args());
+ //}
+ }
+
+ fn flush(&self) {}
+}
+
+static LOGGER: ServerLogger = ServerLogger;
+
+pub fn loginit(level:LevelFilter) -> Result<(), SetLoggerError> {
+ log::set_logger(&LOGGER)
+ .map(|()| log::set_max_level(level))
+}
+
+//const MAX_USER:usize = 100;
+
+fn push_u64(data:&mut Vec, value:u64) {
+ let mut buf = [0; 8];
+ LittleEndian::write_u64(&mut buf, value);
+ data.push(buf[0]);
+ data.push(buf[1]);
+ data.push(buf[2]);
+ data.push(buf[3]);
+ data.push(buf[4]);
+ data.push(buf[5]);
+ data.push(buf[6]);
+ data.push(buf[7]);
+}
+fn push_f64(data:&mut Vec, value:f64) {
+ let mut buf = [0; 8];
+ LittleEndian::write_f64(&mut buf, value);
+ data.push(buf[0]);
+ data.push(buf[1]);
+ data.push(buf[2]);
+ data.push(buf[3]);
+ data.push(buf[4]);
+ data.push(buf[5]);
+ data.push(buf[6]);
+ data.push(buf[7]);
+}
+
+/*
+enum Simple {
+ Error(String),
+ Okay,
+ Foo([u32; 5]),
+}
+
+impl Clone for Simple {
+ fn clone(&self) -> Simple {
+ match self {
+ Error(a) => Error(a.to_string()),
+ Okay => Okay,
+ Foo(a) => Foo(a.clone()),
+ }
+ }
+}
+*/
+
+enum StateUsers {
+ NotDefined,
+ Inactive,
+ UpdateUser,
+ UpdateAddress,
+ Error,
+ Done,
+}
+
+struct Position {
+ x: f64,
+ y: f64,
+ z: f64,
+}
+
+/*
+ * User
+ */
+struct User {
+ active: bool,
+ username: String,
+ address: Address,
+ id: u64,
+ x: f64,
+ y: f64,
+ z: f64,
+ position_updated: bool
+}
+
+impl User {
+/*
+ pub fn new() -> User {
+ Self {
+ active: false,
+ username: "".to_string(),
+ address: Address::new( Ipv4Addr::new(0,0,0,0), 0 )
+ }
+ }
+*/
+ pub fn set_inactive(&mut self) {
+ self.active = false;
+ }
+ pub fn set_active(&mut self) {
+ self.active = true;
+ }
+ pub fn update_username(&mut self, username: String, id:u64) {
+ self.username = username;
+ self.id = id;
+ }
+ pub fn update_address(&mut self, address: Address, id:u64) {
+ self.address = address;
+ self.id = id;
+ }
+ pub fn clear_username(&mut self) {
+ self.username = "".to_string();
+ }
+ pub fn clear_address(&mut self) {
+ self.address = Address::new(Ipv4Addr::new(0, 0, 0, 0), 0);
+ }
+ pub fn clear_position_updated(&mut self) {
+ self.position_updated = false;
+ }
+ pub fn update_pos(&mut self, x:f64, y:f64, z:f64) {
+ if self.x != x {
+ self.x = x;
+ self.position_updated = true;
+ }
+ if self.y != y {
+ self.y = y;
+ self.position_updated = true;
+ }
+ if self.z != z {
+ self.z = z;
+ self.position_updated = true;
+ }
+ }
+ pub fn get_position(&mut self) -> Position {
+ let pos:Position = Position{x: self.x, y: self.y, z: self.z};
+ return pos;
+ }
+ pub fn push_packet(&self, data:&mut Vec) {
+ push_u64(data, self.id);
+ push_f64(data, self.x);
+ push_f64(data, self.y);
+ push_f64(data, self.z);
+ }
+ /*
+ pub fn get_packet(&mut self) -> Vec {
+ let mut data:Vec = Vec::new();
+ push_u64(&mut data, self.id);
+ push_f64(&mut data, self.x);
+ push_f64(&mut data, self.y);
+ push_f64(&mut data, self.z);
+ data
+ }
+ */
+}
+
+impl std::fmt::Display for User {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "id:{} user:{} active:{} address:{}:{} ({}:{}:{})", self.id, self.username, self.active, self.address.ip(), self.address.port(), self.x, self.y, self.z)
+ }
+}
+
+/*
+ * Users
+ */
+struct Users {
+ users: Vec,
+ lastid: u64,
+}
+
+impl Users {
+ pub fn new() -> Users {
+ Self {
+ lastid: 0,
+ users: Vec::new()
+ }
+ }
+ /*
+ pub fn search(&self, username:String) -> bool {
+ for user in &self.users {
+ println!("{}", user);
+ if user.username == username {
+ return true;
+ }
+ }
+ return false;
+ }
+ */
+ pub fn search_me(&self, username:String, address: Address) -> StateUsers {
+ let mut nb_user:u8 = 0;
+ let mut nb_address:u8 = 0;
+ let mut user_address:bool = false;
+ //let mut is_active:bool = false;
+ let mut user_active:bool = false;
+ let mut address_active:bool = false;
+ let mut cur:StateUsers = StateUsers::NotDefined;
+ // check user & address
+ for user in &self.users {
+ if user.username == username {
+ nb_user+=1;
+ if user.active {
+ user_active = true;
+ }
+ if user.address == address {
+ user_address = true;
+ cur = match cur {
+ StateUsers::NotDefined => {
+ if user.active {
+ trace!("User:Ok, Address:Ok, Active:True");
+ StateUsers::Done
+ } else {
+ trace!("User:Ok, Address:Ok, Active:False");
+ StateUsers::Inactive
+ }
+ }
+ _ => {
+ trace!("User:Ok, Address:Ok, But already checked ?");
+ StateUsers::Error
+ }
+ };
+ }
+ }
+ if user.address == address {
+ nb_address+=1;
+ if user.active {
+ address_active = true;
+ }
+ }
+ }
+ // check
+ if nb_user == 0 && nb_address == 0 {
+ trace!("NotDefined: User: not define, Address: not define");
+ return StateUsers::NotDefined;
+ } else if nb_user == 1 && nb_address == 0 {
+ trace!("UpdateAddress: User: {}, Address: {}", nb_user, nb_address);
+ return StateUsers::UpdateAddress;
+ } else if nb_user == 0 && nb_address == 1 {
+ trace!("UpdateUser: User: {}, Address: {}", nb_user, nb_address);
+ return StateUsers::UpdateUser;
+ } else if nb_user == 1 && nb_address == 1 {
+ if user_address {
+ return cur;
+ } else if user_active && ! address_active {
+ trace!("UpdateUser: User: not define, Address: Ok");
+ return StateUsers::UpdateUser;
+ } else if address_active && ! user_active {
+ trace!("UpdateAddress: User: Ok, Address: not define");
+ return StateUsers::UpdateAddress;
+ } else {
+ trace!("Error: User: {}, Address: {}", nb_user, nb_address);
+ return StateUsers::Error;
+ }
+ }
+ trace!("? User: {}, Address: {}", nb_user, nb_address);
+ return StateUsers::Error;
+ }
+ pub fn get_new_id(&mut self) -> u64 {
+ self.lastid += 1;
+ self.lastid
+ }
+ pub fn add(&mut self, username:String, address: Address) -> u64 {
+ let id = self.get_new_id();
+ self.users.push( User { active: true, username:username, address: address, id: id, x: 0.0, y: 10.0, z:0.0, position_updated:true} );
+ id
+ }
+ pub fn update_pos(&mut self, address: Address, x:f64, y:f64, z:f64) {
+ for user in self.users.iter_mut() {
+ if user.address == address {
+ user.update_pos(x, y, z);
+ }
+ }
+ }
+ pub fn set_inactive(&mut self, address: Address) -> u64 {
+ for user in self.users.iter_mut() {
+ if user.address == address {
+ user.set_inactive();
+ return user.id;
+ }
+ }
+ return 0;
+ }
+ pub fn set_active(&mut self, address: Address) -> u64 {
+ for user in self.users.iter_mut() {
+ if user.address == address {
+ user.set_active();
+ return user.id;
+ }
+ }
+ return 0;
+ }
+ pub fn update_username(&mut self, username:String, address: Address) -> u64 {
+ let id = self.get_new_id();
+ for user in self.users.iter_mut() {
+ if user.address == address {
+ user.update_username(username.clone(), id);
+ user.set_active();
+ } else if user.username == username {
+ user.clear_username();
+ }
+ }
+ id
+ }
+ pub fn update_address(&mut self, username:String, address: Address) -> u64 {
+ let id = self.get_new_id();
+ for user in self.users.iter_mut() {
+ if user.username == username {
+ user.update_address(address.clone(), id);
+ user.set_active();
+ } else if user.address == address {
+ user.clear_address();
+ }
+ }
+ id
+ }
+ pub fn get_id(&mut self, address: Address) -> u64 {
+ for user in &self.users {
+ if user.address == address {
+ return user.id;
+ }
+ }
+ return 0;
+ }
+ pub fn get_user(&mut self, address: Address) -> Result<&User, &'static str> {
+ for user in &self.users {
+ if user.address == address {
+ return Ok(user.clone());
+ }
+ }
+ error!("invalid address {}:{}", address.ip(), address.port());
+ Err("invalid address")
+ }
+ pub fn push_packet(&self, data:&mut Vec) -> u8 {
+ let mut nb:u8 = 0;
+ for user in &self.users {
+ if user.active && user.position_updated {
+ user.push_packet(data);
+ nb += 1;
+ }
+ }
+ nb
+ }
+ pub fn clear_position_updated(&mut self) {
+ for user in self.users.iter_mut() {
+ if user.position_updated {
+ user.clear_position_updated();
+ }
+ }
+ }
+}
+
+impl std::fmt::Display for Users {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "len: {} -- ", self.users.len()).unwrap();
+ for user in self.users.iter() {
+ write!(f, "[{}] ", user).unwrap();
+ }
+ Ok(())
+ }
+}
+
+/*
+impl std::fmt::Display for Vec {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ for user in self.users.iter() {
+ write!(f, "{}, ", self.users)
+ }
+ }
+}
+*/
+
+/*
+impl Users {
+ pub fn print(&self) {
+ println!("len: {}", self.users.len());
+ for user in self.users {
+ println!("active:{} (user:{} address:{}:{})",user.active, user.username, user.address.ip(), user.address.port());
+ }
+ }
+}
+*/
+/*
+impl Copy for User { }
+
+impl Clone for User {
+ fn clone(&self) -> User {
+ match self {
+ active => active.clone(),
+ username => username.clone(),
+ address => address.clone(),
+ }
+ }
+}
+*/
+
+/*
+ * Send a message
+ */
+
+fn send_message(sender:Peer<()>, data: &[u8] ) -> Result<(), Error> {
+ let mut peer = sender.clone();
+ peer.send_packet (
+ Packet::new(data, PacketMode::ReliableSequenced).unwrap(),
+ 1,
+ )
+}
+/*
+fn send_message_connect_ok(sender:Peer<()>, id:u64, x:f64, y:f64, z:f64) -> Result<(), Error> {
+ let mut data:Vec = Vec::new();
+ data.push(1); // return connexion request
+ data.push(0); // return ok
+ // get_packet
+ push_u64(&mut data, id);
+ push_f64(&mut data, x);
+ push_f64(&mut data, y);
+ push_f64(&mut data, z);
+ let c: &[u8] = &data;
+ send_message(sender, c)
+}
+*/
+
+fn send_message_connect_ok(sender:Peer<()>, user: &User) -> Result<(), Error> {
+ let mut data:Vec = Vec::new();
+ data.push(1); // return connexion request
+ data.push(0); // return ok
+ user.push_packet(&mut data);
+ let c: &[u8] = &data;
+ send_message(sender, c)
+}
+
+fn send_message_connect_ko(sender:Peer<()>) -> Result<(), Error> {
+ let mut data:Vec = Vec::new();
+ data.push(1); // return connexion request
+ data.push(2); // return ko
+ let c: &[u8] = &data;
+ send_message(sender, c)
+}
+
+fn show(data: &[u8]) -> String {
+ data.iter().map(|b| format!("{:02X}", b)).collect::>().join(", ")
+}
+
+
+/*
+ * Main
+ */
+fn main() -> anyhow::Result<()> {
+ let enet = Enet::new().context("could not initialize ENet")?;
+
+ //env_logger::init();
+ loginit(LevelFilter::Trace).unwrap();
+
+ // simple_logging::log_to_stderr(LevelFilter::Info);
+ /*
+ debug!("Debug");
+ trace!("Trace");
+ info!("Enet initialized");
+ warn!("Enet initialized");
+ error!("Enet initialized");
+ */
+ let local_addr = Address::new(Ipv4Addr::LOCALHOST, 33333);
+
+ let mut host = enet
+ .create_host::<()>(
+ Some(&local_addr),
+ 10,
+ ChannelLimit::Maximum,
+ BandwidthLimit::Unlimited,
+ BandwidthLimit::Unlimited,
+ )
+ .context("could not create host")?;
+ //let mut users: [User; MAX_USER] = [User { active: false, username:"".to_string(), address: Address::new( Ipv4Addr::new(0,0,0,0), 0)}; MAX_USER];
+ let mut users:Users = Users::new() ;
+ info!("Started");
+ loop {
+ trace!("users: {}", users);
+ match host.service(1000).context("service failed")? {
+ Some(Event::Connect(_)) => debug!("new connection!"),
+ Some(Event::Disconnect(ref sender, _)) => {
+ users.set_inactive(sender.address());
+ debug!("disconnect!");
+ },
+ Some(Event::Receive {
+ ref sender,
+ channel_id,
+ ref packet
+ }) => {
+ debug!(
+ "got packet on channel {}, len: '{}' (who:{}:{})",
+ channel_id,
+ packet.data().len(),
+ sender.address().ip(),
+ sender.address().port()
+ );
+ match channel_id {
+ 1 => {
+ let cmd = packet.data()[0];
+ let size = packet.data()[1] as usize;
+ let player_name = &packet.data()[2..=size+1];
+
+ let s = match str::from_utf8(player_name) {
+ Ok(v) => v,
+ Err(_e) => "",
+ };
+ trace!("cmd: {} size:{} name:{} '{}'", cmd, size, player_name.len(), s);
+ if s.to_string() == "Interdit" || s.to_string() == "" {
+ warn!("Received forbidden account '{}'", s);
+ send_message_connect_ko(sender.clone()).unwrap();
+ continue;
+ }
+ let check = users.search_me(s.to_string(), sender.address());
+ match check {
+ StateUsers::NotDefined => {
+ debug!("NotDefined");
+ let _id = users.add(s.to_string(), sender.address());
+ let ret = users.get_user(sender.address());
+ match ret {
+ Ok(user) => send_message_connect_ok(sender.clone(), user).unwrap(),
+ Err(_e) => {},
+ };
+ }
+ StateUsers::Inactive => {
+ debug!("Inactive");
+ let _id = users.set_active(sender.address());
+ let ret = users.get_user(sender.address());
+ match ret {
+ Ok(user) => send_message_connect_ok(sender.clone(), user).unwrap(),
+ Err(_e) => {},
+ };
+ }
+ StateUsers::UpdateUser => {
+ debug!("UpdateUser");
+ let _id = users.update_username(s.to_string(), sender.address());
+ let ret = users.get_user(sender.address());
+ match ret {
+ Ok(user) => send_message_connect_ok(sender.clone(), user).unwrap(),
+ Err(_e) => {},
+ };
+ }
+ StateUsers::UpdateAddress => {
+ debug!("UpdateAddress");
+ let _id = users.update_address(s.to_string(), sender.address());
+ let ret = users.get_user(sender.address());
+ match ret {
+ Ok(user) => send_message_connect_ok(sender.clone(), user).unwrap(),
+ Err(_e) => {},
+ };
+ }
+ StateUsers::Error => {
+ error!("Bad request from {}:{}", sender.address().ip(),sender.address().port());
+ send_message_connect_ko(sender.clone()).unwrap();
+ }
+ StateUsers::Done => {
+ debug!("Done");
+ let _id = users.get_id(sender.address());
+ let ret = users.get_user(sender.address());
+ match ret {
+ Ok(user) => send_message_connect_ok(sender.clone(), user).unwrap(),
+ Err(_e) => {},
+ };
+ }
+ }
+ }
+ 2 => {
+ let mut xbytes: &[u8] = &packet.data()[0..8];
+ let x = xbytes.read_f64::().unwrap();
+ let mut ybytes: &[u8] = &packet.data()[8..16];
+ let y = ybytes.read_f64::().unwrap();
+ let mut zbytes: &[u8] = &packet.data()[16..24];
+ let z = zbytes.read_f64::().unwrap();
+ users.update_pos(sender.address(), x, y, z);
+ }
+ _ => {
+ let mut peer = sender.clone();
+ peer.send_packet (
+ Packet::new(b"youpia", PacketMode::ReliableSequenced).unwrap(),
+ 1,
+ )
+ .context("sending packet failed")?;
+ }
+ }
+ },
+ _ => (),
+ }
+ // Send all player, position other player
+ {
+ let mut data:Vec = Vec::new();
+ let mut data2:Vec = Vec::new();
+ data.push(3); // return connexion request
+ let nb:u8 = users.push_packet(&mut data2);
+ data.push(nb); // number user
+ data.append(&mut data2);
+ let c: &[u8] = &data;
+ if nb > 0 {
+ for peer in host.peers() {
+ if peer.state() == PeerState::Connected {
+ trace!("peer: {}:{}", peer.address().ip(), peer.address().port());
+ send_message(peer, c);
+ }
+ }
+ users.clear_position_updated();
+ }
+ }
+ /*
+ for peer in host.peers() {
+ if peer.state() == PeerState::Connected {
+ trace!("peer: {}:{}", peer.address().ip(), peer.address().port());
+ let mut data:Vec = Vec::new();
+ let mut data2:Vec = Vec::new();
+ data.push(3); // return connexion request
+ let nb:u8 = users.push_packet(&mut data2);
+ data.push(nb); // number user
+ data.append(&mut data2);
+ let c: &[u8] = &data;
+ send_message(peer, c);
+ }
+ }
+ */
+ }
+}
diff --git a/start-bazar-server.sh b/start-bazar-server.sh
new file mode 100755
index 0000000..9db8db2
--- /dev/null
+++ b/start-bazar-server.sh
@@ -0,0 +1,113 @@
+#!/bin/bash
+#
+# Script to launch server
+#
+# Copyright (C) 2023 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 .
+#
+declare DEBUG=0
+declare HELP=0
+declare BUILD=0
+declare WORKDIR="$(dirname $(readlink -f $0))"
+declare RUSTDIR="$WORKDIR/.rust"
+declare SERVERDIR="$WORKDIR/server"
+
+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 byebye()
+{
+ local CODE=$?
+ if [ $CODE -ne 0 ]
+ then
+ msg_error "return code:$code"
+ else
+ msg_info "End"
+ fi
+ exit $CODE
+}
+
+while getopts hdb flag
+do
+ case "${flag}" in
+ h) HELP=1;;
+ d) DEBUG=1;;
+ b) BUILD=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
+ -b : (re)build program
+EOF
+ exit 1
+fi
+
+trap byebye EXIT
+
+msg_info "Start"
+msg_debug "WORKDIR:$WORKDIR"
+
+
+if [[ ($BUILD -ne 0) || (! -x $SERVERDIR/target/debug/server) ]]
+then
+ export CARGO_HOME="$RUSTDIR/.cargo"
+ export RUSTUP_HOME="$RUSTDIR/.rustup"
+
+ mkdir -p $RUSTDIR
+ if [ ! -f $RUSTDIR/install.sh ]
+ then
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > $RUSTDIR/install.sh
+ fi
+ if [ ! -f $RUSTDIR/.cargo/env ]
+ then
+ sh .rust/install.sh -t $RUSTDIR/.cargo --no-modify-path -y
+ # curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -h
+ fi
+ if [ -f $RUSTDIR/.cargo/env ]
+ then
+ source $RUSTDIR/.cargo/env
+ cd $SERVERDIR
+ cargo build
+ else
+ msg_error "Error to load envi rust"
+ exit 2
+ fi
+fi
+
+$SERVERDIR/target/debug/server
+
+# END (call function byebye)