~starkingdoms/starkingdoms

cc06268120ce59ec3fce2bcedbc5594f26a86a10 — c0repwn3r 2 years ago 75de30e
basic handshake with server
18 files changed, 1830 insertions(+), 705 deletions(-)

M Cargo.lock
M client/package.json
M client/src/gateway.ts
M client/src/index.ts
D client/src/protocol/GoodbyeReason.ts
D client/src/protocol/MessageC2S.ts
D client/src/protocol/MessageS2C.ts
D client/src/protocol/State.ts
A client/src/protocol/goodbye_reason.ts
A client/src/protocol/message_c2s.ts
A client/src/protocol/message_s2c.ts
A client/src/protocol/planet.ts
A client/src/protocol/player.ts
A client/src/protocol/starkingdoms-protocol.ts
A client/src/protocol/state.ts
A client/src/serde.ts
M client/yarn.lock
M server/src/handler.rs
M Cargo.lock => Cargo.lock +1 -576
@@ 3,12 3,6 @@
version = 3

[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"

[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 39,39 33,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"

[[package]]
name = "async-recursion"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.14",
]

[[package]]
name = "async-trait"
version = "0.1.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.14",
]

[[package]]
name = "async_io_stream"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c"
dependencies = [
 "futures",
 "pharos",
 "rustc_version",
]

[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 95,24 56,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"

[[package]]
name = "base64"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"

[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"

[[package]]
name = "bit_field"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"

[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 128,12 77,6 @@ dependencies = [
]

[[package]]
name = "bumpalo"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"

[[package]]
name = "bytemuck"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 196,12 139,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"

[[package]]
name = "colored"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 213,27 150,6 @@ dependencies = [
]

[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
 "cfg-if",
 "wasm-bindgen",
]

[[package]]
name = "console_log"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f"
dependencies = [
 "log",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "cpufeatures"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 243,15 159,6 @@ dependencies = [
]

[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
 "cfg-if",
]

[[package]]
name = "crossbeam"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 319,12 226,6 @@ dependencies = [
]

[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"

[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 378,22 279,6 @@ dependencies = [
]

[[package]]
name = "exr"
version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdd2162b720141a91a054640662d3edce3d50a944a50ffca5313cd951abb35b4"
dependencies = [
 "bit_field",
 "flume",
 "half",
 "lebe",
 "miniz_oxide 0.6.2",
 "rayon-core",
 "smallvec",
 "zune-inflate",
]

[[package]]
name = "fastrand"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 403,38 288,6 @@ dependencies = [
]

[[package]]
name = "fdeflate"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10"
dependencies = [
 "simd-adler32",
]

[[package]]
name = "flate2"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
dependencies = [
 "crc32fast",
 "miniz_oxide 0.6.2",
]

[[package]]
name = "flume"
version = "0.10.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
dependencies = [
 "futures-core",
 "futures-sink",
 "nanorand",
 "pin-project",
 "spin",
]

[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 457,7 310,6 @@ checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-executor",
 "futures-io",
 "futures-sink",
 "futures-task",


@@ 481,34 333,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"

[[package]]
name = "futures-executor"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
dependencies = [
 "futures-core",
 "futures-task",
 "futures-util",
]

[[package]]
name = "futures-io"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"

[[package]]
name = "futures-macro"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 2.0.14",
]

[[package]]
name = "futures-sink"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 526,13 356,9 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [
 "futures-channel",
 "futures-core",
 "futures-io",
 "futures-macro",
 "futures-sink",
 "futures-task",
 "memchr",
 "pin-project-lite",
 "pin-utils",
 "slab",


@@ 555,20 381,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [
 "cfg-if",
 "js-sys",
 "libc",
 "wasi",
 "wasm-bindgen",
]

[[package]]
name = "gif"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045"
dependencies = [
 "color_quant",
 "weezl",
]

[[package]]


@@ 591,15 405,6 @@ dependencies = [
]

[[package]]
name = "half"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0"
dependencies = [
 "crunchy",
]

[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 698,25 503,6 @@ dependencies = [
]

[[package]]
name = "image"
version = "0.24.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a"
dependencies = [
 "bytemuck",
 "byteorder",
 "color_quant",
 "exr",
 "gif",
 "jpeg-decoder",
 "num-rational",
 "num-traits",
 "png",
 "qoi",
 "tiff",
]

[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 753,36 539,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"

[[package]]
name = "jpeg-decoder"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
dependencies = [
 "rayon",
]

[[package]]
name = "js-sys"
version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
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 = "lebe"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"

[[package]]
name = "libc"
version = "0.2.141"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 801,16 563,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"

[[package]]
name = "lock_api"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
 "autocfg",
 "scopeguard",
]

[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 820,15 572,6 @@ dependencies = [
]

[[package]]
name = "markdown"
version = "1.0.0-alpha.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de49c677e95e00eaa74c42a0b07ea55e1e0b1ebca5b2cbc7657f288cd714eb"
dependencies = [
 "unicode-id",
]

[[package]]
name = "matrixmultiply"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 853,25 596,6 @@ dependencies = [
]

[[package]]
name = "miniz_oxide"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
dependencies = [
 "adler",
]

[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
 "adler",
 "simd-adler32",
]

[[package]]
name = "mio"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 911,15 635,6 @@ dependencies = [
]

[[package]]
name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
 "getrandom",
]

[[package]]
name = "num-complex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1035,36 750,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"

[[package]]
name = "pharos"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414"
dependencies = [
 "futures",
 "rustc_version",
]

[[package]]
name = "pin-project"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
dependencies = [
 "pin-project-internal",
]

[[package]]
name = "pin-project-internal"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 1.0.109",
]

[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1077,19 762,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"

[[package]]
name = "png"
version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa"
dependencies = [
 "bitflags",
 "crc32fast",
 "fdeflate",
 "flate2",
 "miniz_oxide 0.7.1",
]

[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1193,15 865,6 @@ dependencies = [
]

[[package]]
name = "qoi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
dependencies = [
 "bytemuck",
]

[[package]]
name = "quote"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1268,28 931,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"

[[package]]
name = "rayon"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
dependencies = [
 "either",
 "rayon-core",
]

[[package]]
name = "rayon-core"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
dependencies = [
 "crossbeam-channel",
 "crossbeam-deque",
 "crossbeam-utils",
 "num_cpus",
]

[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1316,60 957,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"

[[package]]
name = "rmp"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f"
dependencies = [
 "byteorder",
 "num-traits",
 "paste",
]

[[package]]
name = "rmp-serde"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e"
dependencies = [
 "byteorder",
 "rmp",
 "serde",
]

[[package]]
name = "robust"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5864e7ef1a6b7bcf1d6ca3f655e65e724ed3b52546a0d0a663c991522f552ea"

[[package]]
name = "ron"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff"
dependencies = [
 "base64 0.13.1",
 "bitflags",
 "serde",
]

[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"

[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
 "semver",
]

[[package]]
name = "rustix"
version = "0.37.11"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1414,12 1013,6 @@ dependencies = [
]

[[package]]
name = "send_wrapper"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"

[[package]]
name = "serde"
version = "1.0.160"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1475,12 1068,6 @@ dependencies = [
]

[[package]]
name = "simd-adler32"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f"

[[package]]
name = "simple_logger"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1531,41 1118,6 @@ dependencies = [
]

[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
 "lock_api",
]

[[package]]
name = "starkingdoms-client"
version = "0.1.0"
dependencies = [
 "async-recursion",
 "async-trait",
 "base64 0.21.0",
 "console_error_panic_hook",
 "console_log",
 "futures",
 "image",
 "js-sys",
 "lazy_static",
 "log",
 "markdown",
 "rmp-serde",
 "ron",
 "serde",
 "starkingdoms-protocol",
 "url",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
 "ws_stream_wasm",
]

[[package]]
name = "starkingdoms-protocol"
version = "0.1.0"
dependencies = [


@@ 1650,17 1202,6 @@ dependencies = [
]

[[package]]
name = "tiff"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471"
dependencies = [
 "flate2",
 "jpeg-decoder",
 "weezl",
]

[[package]]
name = "time"
version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1796,7 1337,7 @@ version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
dependencies = [
 "base64 0.13.1",
 "base64",
 "byteorder",
 "bytes",
 "http",


@@ 1822,12 1363,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"

[[package]]
name = "unicode-id"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d70b6494226b36008c8366c288d77190b3fad2eb4c10533139c1c1f461127f1a"

[[package]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 1888,88 1423,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

[[package]]
name = "wasm-bindgen"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
dependencies = [
 "cfg-if",
 "wasm-bindgen-macro",
]

[[package]]
name = "wasm-bindgen-backend"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
dependencies = [
 "bumpalo",
 "log",
 "once_cell",
 "proc-macro2",
 "quote",
 "syn 1.0.109",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-futures"
version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
dependencies = [
 "cfg-if",
 "js-sys",
 "wasm-bindgen",
 "web-sys",
]

[[package]]
name = "wasm-bindgen-macro"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
dependencies = [
 "quote",
 "wasm-bindgen-macro-support",
]

[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
dependencies = [
 "proc-macro2",
 "quote",
 "syn 1.0.109",
 "wasm-bindgen-backend",
 "wasm-bindgen-shared",
]

[[package]]
name = "wasm-bindgen-shared"
version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"

[[package]]
name = "web-sys"
version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
dependencies = [
 "js-sys",
 "wasm-bindgen",
]

[[package]]
name = "weezl"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"

[[package]]
name = "which"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 2158,31 1611,3 @@ name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"

[[package]]
name = "ws_stream_wasm"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5"
dependencies = [
 "async_io_stream",
 "futures",
 "js-sys",
 "log",
 "pharos",
 "rustc_version",
 "send_wrapper",
 "thiserror",
 "wasm-bindgen",
 "wasm-bindgen-futures",
 "web-sys",
]

[[package]]
name = "zune-inflate"
version = "0.2.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "440a08fd59c6442e4b846ea9b10386c38307eae728b216e1ab2c305d1c9daaf8"
dependencies = [
 "simd-adler32",
]

M client/package.json => client/package.json +3 -2
@@ 6,14 6,15 @@
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview"
    "preview": "vite preview",
    "protobuf": "mkdir -p ./src/protocol && protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=./src/protocol -I ../protocol/src/pbuf ../protocol/src/pbuf/starkingdoms-protocol.proto"
  },
  "devDependencies": {
    "ts-proto": "^1.146.0",
    "typescript": "^4.9.3",
    "vite": "^4.2.0"
  },
  "dependencies": {
    "@msgpack/msgpack": "^3.0.0-beta2",
    "pixi.js": "^7.2.4"
  }
}

M client/src/gateway.ts => client/src/gateway.ts +73 -3
@@ 1,17 1,87 @@
import {Logger} from "./logger";
import { encode } from "@msgpack/msgpack";
import {MessageC2S} from "./protocol/MessageC2S";
import {MessageC2SHello, MessageC2SHello_packetInfo} from "./protocol/message_c2s";
import {State} from "./protocol/state";
import {decode, encode} from "./serde";
import {
    MessageS2CGoodbye,
    MessageS2CGoodbye_packetInfo,
    MessageS2CHello,
    MessageS2CHello_packetInfo
} from "./protocol/message_s2c";

const logger = new Logger("Gateway");

export async function gateway_connect(gateway_url: string) {
export interface GatewayClient {
    state: State;
    socket: WebSocket;
    username: string | null;
    version: number | null;
}

function toHexString(byteArray) {
    return Array.from(byteArray, function(byte) {
        return ('0' + (byte & 0xFF).toString(16)).slice(-2);
    }).join('')
}


export async function gateway_connect(gateway_url: string, username: string): GatewayClient {
    logger.info("FAST CONNECT - Connecting to gateway socket at " + gateway_url);

    let ws = await _websocket_connect(gateway_url);

    logger.debug("[fastconnect] connected to gateway, performing handshake with server");

    let client: GatewayClient = {
        state: State.Handshake,
        socket: ws,
        username: null,
        version: null
    };

    let handshake_start_msg = MessageC2SHello.encode({
        version: 1,
        requestedUsername: username,
        nextState: State.Play
    }).finish();
    client.socket.send(encode(MessageC2SHello_packetInfo.type, handshake_start_msg));

    client.socket.addEventListener('message', async (msg) => {
        let pkt_info = decode(new Uint8Array(await msg.data.arrayBuffer()));
        let pkt_id = pkt_info[0];
        let pkt_data = pkt_info[1];

        if (pkt_id == 0) {
            // not a real message, skip
            return;
        }

        if (client.state == State.Handshake) {
            if (pkt_id == MessageS2CHello_packetInfo.type) {
                let pkt = MessageS2CHello.decode(pkt_data);

                logger.info(`FAST CONNECT - Handshake finished with server with protocol v${pkt.version}, assigned username ${pkt.givenUsername}, switching to state ${pkt.nextState}`);

                client.state = pkt.nextState;
                client.username = pkt.givenUsername;
                client.version = pkt.version;
            } else if (pkt_id == MessageS2CGoodbye_packetInfo.type) {
                let pkt = MessageS2CGoodbye.decode(pkt_data);

                logger.error(`Disconnected by server. Reason: ${pkt.reason}`);

                client.state = State.Handshake;
                client.username = null;
                client.version = null;

                throw "Disconnected by server";
            } else {
                logger.warn(`server sent unexpected packet ${pkt_id} for state Handshake`);
            }
        } else if (client.state == State.Play) {
            // TODO
        }
    })
}

let socket: WebSocket | undefined = undefined;

M client/src/index.ts => client/src/index.ts +12 -4
@@ 1,18 1,26 @@
//import * as PIXI from "pixi.js";

import {Logger, logSetup} from "./logger";
import {gateway_connect} from "./gateway";
import {gateway_connect, GatewayClient} from "./gateway";

logSetup();
const logger = new Logger("client");

async function client_main() {
export interface GlobalData {
    client: GatewayClient | null
}

export const global: GlobalData = {
    client: null
}

async function client_main(server: string, username: string) {
    logger.info("StarKingdoms client - starting");

    await gateway_connect("ws://localhost:3000/ws");
    global.client = await gateway_connect(server, username);
}

client_main().then(() => {});
client_main("ws://localhost:3000/ws", "core").then(() => {});

/*


D client/src/protocol/GoodbyeReason.ts => client/src/protocol/GoodbyeReason.ts +0 -42
@@ 1,42 0,0 @@
export enum GoodbyeReason {
    UnexpectedPacket,
    UnexpectedNextState,
    UsernameTaken,
    PingPongTimeout,
    Done
}

export class GoodbyeReason_UnsupportedProtocol {
    supported: number;
    got: number;

    constructor(supported: number, got: number) {
        this.supported = supported;
        this.got = got;
    }

    to_object(): object {
        return { UnsupportedProtocol: {supported: this.supported, got: this.got} }
    }
}

// @ts-ignore
export function enum_GoodbyeReason_serialize(r: GoodbyeReason): string {
    if (r == GoodbyeReason.UnexpectedPacket) {
        return "UnexpectedPacket";
    } else if (r == GoodbyeReason.UnexpectedNextState) {
        return "UnexpectedNextState";
    } else if (r == GoodbyeReason.UsernameTaken) {
        return "UsernameTaken";
    } else if (r == GoodbyeReason.PingPongTimeout) {
        return "PingPongTimeout";
    } else if (r == GoodbyeReason.Done) {
        return "Done";
    }
}

export function enum_GoodbyeReason_deserialize(r: string): GoodbyeReason {
    if (r == "UnexpectedPacket") {

    }
}
\ No newline at end of file

D client/src/protocol/MessageC2S.ts => client/src/protocol/MessageC2S.ts +0 -58
@@ 1,58 0,0 @@
import {State} from "./State";
import {enum_GoodbyeReason_serialize, GoodbyeReason, GoodbyeReason_UnsupportedProtocol} from "./GoodbyeReason";

export class MessageC2S_Hello {
    version: number;
    requested_username: string;
    next_state: State;

    constructor(version: number, requested_username: string, next_state: State) {
        this.version = version;
        this.requested_username = requested_username;
        this.next_state = next_state;
    }

    to_object(): object {
        return { Hello: { version: this.version, requested_username: this.requested_username, next_state: this.next_state }}
    }
}

export class MessageC2S_Goodbye {
    reason: GoodbyeReason | GoodbyeReason_UnsupportedProtocol;

    constructor(reason: GoodbyeReason | GoodbyeReason_UnsupportedProtocol) {
        this.reason = reason;
    }

    to_object(): object {
        let reason;

        if (this.reason instanceof GoodbyeReason_UnsupportedProtocol) {
            reason = this.reason.to_object();
        } else {
            reason = enum_GoodbyeReason_serialize(this.reason);
        }

        return { Goodbye: { reason: reason } }
    }
}

export class MessageC2S_Chat {
    message: string;

    constructor(message: string) {
        this.message = message;
    }

    to_object(): object {
        return { Chat: { message: this.message }}
    }
}

export class MessageC2S_Ping {
    constructor() {}

    to_object(): object {
        return { Ping: {} }
    }
}
\ No newline at end of file

D client/src/protocol/MessageS2C.ts => client/src/protocol/MessageS2C.ts +0 -11
@@ 1,11 0,0 @@
import {State} from "./State";

export class MessageS2C_Hello {
    version: number;
    given_username: string;
    next_state: State;

    constructor(version: number, given_username: string, next_state: State) {
        this.version
    }
}
\ No newline at end of file

D client/src/protocol/State.ts => client/src/protocol/State.ts +0 -4
@@ 1,4 0,0 @@
export enum State {
    Handshake,
    Play
}
\ No newline at end of file

A client/src/protocol/goodbye_reason.ts => client/src/protocol/goodbye_reason.ts +60 -0
@@ 0,0 1,60 @@
/* eslint-disable */

export const protobufPackage = "protocol.goodbye_reason";

export enum GoodbyeReason {
  UnsupportedProtocol = 0,
  UnexpectedPacket = 1,
  UnexpectedNextState = 2,
  UsernameTaken = 3,
  PingPongTimeout = 4,
  Done = 5,
  UNRECOGNIZED = -1,
}

export function goodbyeReasonFromJSON(object: any): GoodbyeReason {
  switch (object) {
    case 0:
    case "UnsupportedProtocol":
      return GoodbyeReason.UnsupportedProtocol;
    case 1:
    case "UnexpectedPacket":
      return GoodbyeReason.UnexpectedPacket;
    case 2:
    case "UnexpectedNextState":
      return GoodbyeReason.UnexpectedNextState;
    case 3:
    case "UsernameTaken":
      return GoodbyeReason.UsernameTaken;
    case 4:
    case "PingPongTimeout":
      return GoodbyeReason.PingPongTimeout;
    case 5:
    case "Done":
      return GoodbyeReason.Done;
    case -1:
    case "UNRECOGNIZED":
    default:
      return GoodbyeReason.UNRECOGNIZED;
  }
}

export function goodbyeReasonToJSON(object: GoodbyeReason): string {
  switch (object) {
    case GoodbyeReason.UnsupportedProtocol:
      return "UnsupportedProtocol";
    case GoodbyeReason.UnexpectedPacket:
      return "UnexpectedPacket";
    case GoodbyeReason.UnexpectedNextState:
      return "UnexpectedNextState";
    case GoodbyeReason.UsernameTaken:
      return "UsernameTaken";
    case GoodbyeReason.PingPongTimeout:
      return "PingPongTimeout";
    case GoodbyeReason.Done:
      return "Done";
    case GoodbyeReason.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

A client/src/protocol/message_c2s.ts => client/src/protocol/message_c2s.ts +415 -0
@@ 0,0 1,415 @@
/* eslint-disable */
import * as _m0 from "protobufjs/minimal";
import { GoodbyeReason, goodbyeReasonFromJSON, goodbyeReasonToJSON } from "./goodbye_reason";
import { State, stateFromJSON, stateToJSON } from "./state";

export const protobufPackage = "protocol.message_c2s";

export interface MessageC2SHello {
  /** Version of the protocol. Currently always 1 */
  version: number;
  /** The username that the client is requesting. */
  requestedUsername: string;
  /** The state the connection will go into after the handshake. */
  nextState: State;
}

export enum MessageC2SHello_packetInfo {
  unknown = 0,
  type = 1,
  UNRECOGNIZED = -1,
}

export function messageC2SHello_packetInfoFromJSON(object: any): MessageC2SHello_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageC2SHello_packetInfo.unknown;
    case 1:
    case "type":
      return MessageC2SHello_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageC2SHello_packetInfo.UNRECOGNIZED;
  }
}

export function messageC2SHello_packetInfoToJSON(object: MessageC2SHello_packetInfo): string {
  switch (object) {
    case MessageC2SHello_packetInfo.unknown:
      return "unknown";
    case MessageC2SHello_packetInfo.type:
      return "type";
    case MessageC2SHello_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

export interface MessageC2SGoodbye {
  /** The reason the client is disconnecting the server */
  reason: GoodbyeReason;
}

export enum MessageC2SGoodbye_packetInfo {
  unknown = 0,
  type = 2,
  UNRECOGNIZED = -1,
}

export function messageC2SGoodbye_packetInfoFromJSON(object: any): MessageC2SGoodbye_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageC2SGoodbye_packetInfo.unknown;
    case 2:
    case "type":
      return MessageC2SGoodbye_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageC2SGoodbye_packetInfo.UNRECOGNIZED;
  }
}

export function messageC2SGoodbye_packetInfoToJSON(object: MessageC2SGoodbye_packetInfo): string {
  switch (object) {
    case MessageC2SGoodbye_packetInfo.unknown:
      return "unknown";
    case MessageC2SGoodbye_packetInfo.type:
      return "type";
    case MessageC2SGoodbye_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

export interface MessageC2SChat {
  /** The chat message to sent */
  message: string;
}

export enum MessageC2SChat_packetInfo {
  unknown = 0,
  type = 3,
  UNRECOGNIZED = -1,
}

export function messageC2SChat_packetInfoFromJSON(object: any): MessageC2SChat_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageC2SChat_packetInfo.unknown;
    case 3:
    case "type":
      return MessageC2SChat_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageC2SChat_packetInfo.UNRECOGNIZED;
  }
}

export function messageC2SChat_packetInfoToJSON(object: MessageC2SChat_packetInfo): string {
  switch (object) {
    case MessageC2SChat_packetInfo.unknown:
      return "unknown";
    case MessageC2SChat_packetInfo.type:
      return "type";
    case MessageC2SChat_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

export interface MessageC2SPing {
}

export enum MessageC2SPing_packetInfo {
  unknown = 0,
  type = 4,
  UNRECOGNIZED = -1,
}

export function messageC2SPing_packetInfoFromJSON(object: any): MessageC2SPing_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageC2SPing_packetInfo.unknown;
    case 4:
    case "type":
      return MessageC2SPing_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageC2SPing_packetInfo.UNRECOGNIZED;
  }
}

export function messageC2SPing_packetInfoToJSON(object: MessageC2SPing_packetInfo): string {
  switch (object) {
    case MessageC2SPing_packetInfo.unknown:
      return "unknown";
    case MessageC2SPing_packetInfo.type:
      return "type";
    case MessageC2SPing_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

function createBaseMessageC2SHello(): MessageC2SHello {
  return { version: 0, requestedUsername: "", nextState: 0 };
}

export const MessageC2SHello = {
  encode(message: MessageC2SHello, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    if (message.version !== 0) {
      writer.uint32(8).uint32(message.version);
    }
    if (message.requestedUsername !== "") {
      writer.uint32(18).string(message.requestedUsername);
    }
    if (message.nextState !== 0) {
      writer.uint32(24).int32(message.nextState);
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageC2SHello {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageC2SHello();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 8) {
            break;
          }

          message.version = reader.uint32();
          continue;
        case 2:
          if (tag != 18) {
            break;
          }

          message.requestedUsername = reader.string();
          continue;
        case 3:
          if (tag != 24) {
            break;
          }

          message.nextState = reader.int32() as any;
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): MessageC2SHello {
    return {
      version: isSet(object.version) ? Number(object.version) : 0,
      requestedUsername: isSet(object.requestedUsername) ? String(object.requestedUsername) : "",
      nextState: isSet(object.nextState) ? stateFromJSON(object.nextState) : 0,
    };
  },

  toJSON(message: MessageC2SHello): unknown {
    const obj: any = {};
    message.version !== undefined && (obj.version = Math.round(message.version));
    message.requestedUsername !== undefined && (obj.requestedUsername = message.requestedUsername);
    message.nextState !== undefined && (obj.nextState = stateToJSON(message.nextState));
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageC2SHello>, I>>(base?: I): MessageC2SHello {
    return MessageC2SHello.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageC2SHello>, I>>(object: I): MessageC2SHello {
    const message = createBaseMessageC2SHello();
    message.version = object.version ?? 0;
    message.requestedUsername = object.requestedUsername ?? "";
    message.nextState = object.nextState ?? 0;
    return message;
  },
};

function createBaseMessageC2SGoodbye(): MessageC2SGoodbye {
  return { reason: 0 };
}

export const MessageC2SGoodbye = {
  encode(message: MessageC2SGoodbye, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    if (message.reason !== 0) {
      writer.uint32(8).int32(message.reason);
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageC2SGoodbye {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageC2SGoodbye();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 8) {
            break;
          }

          message.reason = reader.int32() as any;
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): MessageC2SGoodbye {
    return { reason: isSet(object.reason) ? goodbyeReasonFromJSON(object.reason) : 0 };
  },

  toJSON(message: MessageC2SGoodbye): unknown {
    const obj: any = {};
    message.reason !== undefined && (obj.reason = goodbyeReasonToJSON(message.reason));
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageC2SGoodbye>, I>>(base?: I): MessageC2SGoodbye {
    return MessageC2SGoodbye.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageC2SGoodbye>, I>>(object: I): MessageC2SGoodbye {
    const message = createBaseMessageC2SGoodbye();
    message.reason = object.reason ?? 0;
    return message;
  },
};

function createBaseMessageC2SChat(): MessageC2SChat {
  return { message: "" };
}

export const MessageC2SChat = {
  encode(message: MessageC2SChat, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    if (message.message !== "") {
      writer.uint32(10).string(message.message);
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageC2SChat {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageC2SChat();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 10) {
            break;
          }

          message.message = reader.string();
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): MessageC2SChat {
    return { message: isSet(object.message) ? String(object.message) : "" };
  },

  toJSON(message: MessageC2SChat): unknown {
    const obj: any = {};
    message.message !== undefined && (obj.message = message.message);
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageC2SChat>, I>>(base?: I): MessageC2SChat {
    return MessageC2SChat.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageC2SChat>, I>>(object: I): MessageC2SChat {
    const message = createBaseMessageC2SChat();
    message.message = object.message ?? "";
    return message;
  },
};

function createBaseMessageC2SPing(): MessageC2SPing {
  return {};
}

export const MessageC2SPing = {
  encode(_: MessageC2SPing, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageC2SPing {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageC2SPing();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(_: any): MessageC2SPing {
    return {};
  },

  toJSON(_: MessageC2SPing): unknown {
    const obj: any = {};
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageC2SPing>, I>>(base?: I): MessageC2SPing {
    return MessageC2SPing.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageC2SPing>, I>>(_: I): MessageC2SPing {
    const message = createBaseMessageC2SPing();
    return message;
  },
};

type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

export type DeepPartial<T> = T extends Builtin ? T
  : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
  : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
  : Partial<T>;

type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin ? P
  : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };

function isSet(value: any): boolean {
  return value !== null && value !== undefined;
}

A client/src/protocol/message_s2c.ts => client/src/protocol/message_s2c.ts +630 -0
@@ 0,0 1,630 @@
/* eslint-disable */
import * as _m0 from "protobufjs/minimal";
import { GoodbyeReason, goodbyeReasonFromJSON, goodbyeReasonToJSON } from "./goodbye_reason";
import { Planet } from "./planet";
import { Player } from "./player";
import { State, stateFromJSON, stateToJSON } from "./state";

export const protobufPackage = "protocol.message_s2c";

export interface MessageS2CHello {
  /** The version of the protocol in use. Currently always 1. */
  version: number;
  /** The username actually assigned to the player */
  givenUsername: string;
  /** The state to switch the game into */
  nextState: State;
}

export enum MessageS2CHello_packetInfo {
  unknown = 0,
  type = 5,
  UNRECOGNIZED = -1,
}

export function messageS2CHello_packetInfoFromJSON(object: any): MessageS2CHello_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageS2CHello_packetInfo.unknown;
    case 5:
    case "type":
      return MessageS2CHello_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageS2CHello_packetInfo.UNRECOGNIZED;
  }
}

export function messageS2CHello_packetInfoToJSON(object: MessageS2CHello_packetInfo): string {
  switch (object) {
    case MessageS2CHello_packetInfo.unknown:
      return "unknown";
    case MessageS2CHello_packetInfo.type:
      return "type";
    case MessageS2CHello_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

export interface MessageS2CGoodbye {
  /** The reason for the disconnect */
  reason: GoodbyeReason;
}

export enum MessageS2CGoodbye_packetInfo {
  unknown = 0,
  type = 6,
  UNRECOGNIZED = -1,
}

export function messageS2CGoodbye_packetInfoFromJSON(object: any): MessageS2CGoodbye_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageS2CGoodbye_packetInfo.unknown;
    case 6:
    case "type":
      return MessageS2CGoodbye_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageS2CGoodbye_packetInfo.UNRECOGNIZED;
  }
}

export function messageS2CGoodbye_packetInfoToJSON(object: MessageS2CGoodbye_packetInfo): string {
  switch (object) {
    case MessageS2CGoodbye_packetInfo.unknown:
      return "unknown";
    case MessageS2CGoodbye_packetInfo.type:
      return "type";
    case MessageS2CGoodbye_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

export interface MessageS2CChat {
  /** The username of the player who sent the message */
  from: string;
  /** The contents of the chat message */
  message: string;
}

export enum MessageS2CChat_packetInfo {
  unknown = 0,
  type = 7,
  UNRECOGNIZED = -1,
}

export function messageS2CChat_packetInfoFromJSON(object: any): MessageS2CChat_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageS2CChat_packetInfo.unknown;
    case 7:
    case "type":
      return MessageS2CChat_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageS2CChat_packetInfo.UNRECOGNIZED;
  }
}

export function messageS2CChat_packetInfoToJSON(object: MessageS2CChat_packetInfo): string {
  switch (object) {
    case MessageS2CChat_packetInfo.unknown:
      return "unknown";
    case MessageS2CChat_packetInfo.type:
      return "type";
    case MessageS2CChat_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

export interface MessageS2CPong {
}

export enum MessageS2CPong_packetInfo {
  unknown = 0,
  type = 8,
  UNRECOGNIZED = -1,
}

export function messageS2CPong_packetInfoFromJSON(object: any): MessageS2CPong_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageS2CPong_packetInfo.unknown;
    case 8:
    case "type":
      return MessageS2CPong_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageS2CPong_packetInfo.UNRECOGNIZED;
  }
}

export function messageS2CPong_packetInfoToJSON(object: MessageS2CPong_packetInfo): string {
  switch (object) {
    case MessageS2CPong_packetInfo.unknown:
      return "unknown";
    case MessageS2CPong_packetInfo.type:
      return "type";
    case MessageS2CPong_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

export interface MessageS2CPlayersUpdate {
  /** List of all players in the server */
  players: Player[];
}

export enum MessageS2CPlayersUpdate_packetInfo {
  unknown = 0,
  type = 9,
  UNRECOGNIZED = -1,
}

export function messageS2CPlayersUpdate_packetInfoFromJSON(object: any): MessageS2CPlayersUpdate_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageS2CPlayersUpdate_packetInfo.unknown;
    case 9:
    case "type":
      return MessageS2CPlayersUpdate_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageS2CPlayersUpdate_packetInfo.UNRECOGNIZED;
  }
}

export function messageS2CPlayersUpdate_packetInfoToJSON(object: MessageS2CPlayersUpdate_packetInfo): string {
  switch (object) {
    case MessageS2CPlayersUpdate_packetInfo.unknown:
      return "unknown";
    case MessageS2CPlayersUpdate_packetInfo.type:
      return "type";
    case MessageS2CPlayersUpdate_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

export interface MessageS2CPlanetData {
  /** List of all planets on the server */
  planets: Planet[];
}

export enum MessageS2CPlanetData_packetInfo {
  unknown = 0,
  type = 10,
  UNRECOGNIZED = -1,
}

export function messageS2CPlanetData_packetInfoFromJSON(object: any): MessageS2CPlanetData_packetInfo {
  switch (object) {
    case 0:
    case "unknown":
      return MessageS2CPlanetData_packetInfo.unknown;
    case 10:
    case "type":
      return MessageS2CPlanetData_packetInfo.type;
    case -1:
    case "UNRECOGNIZED":
    default:
      return MessageS2CPlanetData_packetInfo.UNRECOGNIZED;
  }
}

export function messageS2CPlanetData_packetInfoToJSON(object: MessageS2CPlanetData_packetInfo): string {
  switch (object) {
    case MessageS2CPlanetData_packetInfo.unknown:
      return "unknown";
    case MessageS2CPlanetData_packetInfo.type:
      return "type";
    case MessageS2CPlanetData_packetInfo.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

function createBaseMessageS2CHello(): MessageS2CHello {
  return { version: 0, givenUsername: "", nextState: 0 };
}

export const MessageS2CHello = {
  encode(message: MessageS2CHello, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    if (message.version !== 0) {
      writer.uint32(8).uint32(message.version);
    }
    if (message.givenUsername !== "") {
      writer.uint32(18).string(message.givenUsername);
    }
    if (message.nextState !== 0) {
      writer.uint32(24).int32(message.nextState);
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageS2CHello {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageS2CHello();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 8) {
            break;
          }

          message.version = reader.uint32();
          continue;
        case 2:
          if (tag != 18) {
            break;
          }

          message.givenUsername = reader.string();
          continue;
        case 3:
          if (tag != 24) {
            break;
          }

          message.nextState = reader.int32() as any;
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): MessageS2CHello {
    return {
      version: isSet(object.version) ? Number(object.version) : 0,
      givenUsername: isSet(object.givenUsername) ? String(object.givenUsername) : "",
      nextState: isSet(object.nextState) ? stateFromJSON(object.nextState) : 0,
    };
  },

  toJSON(message: MessageS2CHello): unknown {
    const obj: any = {};
    message.version !== undefined && (obj.version = Math.round(message.version));
    message.givenUsername !== undefined && (obj.givenUsername = message.givenUsername);
    message.nextState !== undefined && (obj.nextState = stateToJSON(message.nextState));
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageS2CHello>, I>>(base?: I): MessageS2CHello {
    return MessageS2CHello.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageS2CHello>, I>>(object: I): MessageS2CHello {
    const message = createBaseMessageS2CHello();
    message.version = object.version ?? 0;
    message.givenUsername = object.givenUsername ?? "";
    message.nextState = object.nextState ?? 0;
    return message;
  },
};

function createBaseMessageS2CGoodbye(): MessageS2CGoodbye {
  return { reason: 0 };
}

export const MessageS2CGoodbye = {
  encode(message: MessageS2CGoodbye, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    if (message.reason !== 0) {
      writer.uint32(8).int32(message.reason);
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageS2CGoodbye {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageS2CGoodbye();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 8) {
            break;
          }

          message.reason = reader.int32() as any;
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): MessageS2CGoodbye {
    return { reason: isSet(object.reason) ? goodbyeReasonFromJSON(object.reason) : 0 };
  },

  toJSON(message: MessageS2CGoodbye): unknown {
    const obj: any = {};
    message.reason !== undefined && (obj.reason = goodbyeReasonToJSON(message.reason));
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageS2CGoodbye>, I>>(base?: I): MessageS2CGoodbye {
    return MessageS2CGoodbye.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageS2CGoodbye>, I>>(object: I): MessageS2CGoodbye {
    const message = createBaseMessageS2CGoodbye();
    message.reason = object.reason ?? 0;
    return message;
  },
};

function createBaseMessageS2CChat(): MessageS2CChat {
  return { from: "", message: "" };
}

export const MessageS2CChat = {
  encode(message: MessageS2CChat, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    if (message.from !== "") {
      writer.uint32(10).string(message.from);
    }
    if (message.message !== "") {
      writer.uint32(18).string(message.message);
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageS2CChat {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageS2CChat();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 10) {
            break;
          }

          message.from = reader.string();
          continue;
        case 2:
          if (tag != 18) {
            break;
          }

          message.message = reader.string();
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): MessageS2CChat {
    return {
      from: isSet(object.from) ? String(object.from) : "",
      message: isSet(object.message) ? String(object.message) : "",
    };
  },

  toJSON(message: MessageS2CChat): unknown {
    const obj: any = {};
    message.from !== undefined && (obj.from = message.from);
    message.message !== undefined && (obj.message = message.message);
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageS2CChat>, I>>(base?: I): MessageS2CChat {
    return MessageS2CChat.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageS2CChat>, I>>(object: I): MessageS2CChat {
    const message = createBaseMessageS2CChat();
    message.from = object.from ?? "";
    message.message = object.message ?? "";
    return message;
  },
};

function createBaseMessageS2CPong(): MessageS2CPong {
  return {};
}

export const MessageS2CPong = {
  encode(_: MessageS2CPong, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageS2CPong {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageS2CPong();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(_: any): MessageS2CPong {
    return {};
  },

  toJSON(_: MessageS2CPong): unknown {
    const obj: any = {};
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageS2CPong>, I>>(base?: I): MessageS2CPong {
    return MessageS2CPong.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageS2CPong>, I>>(_: I): MessageS2CPong {
    const message = createBaseMessageS2CPong();
    return message;
  },
};

function createBaseMessageS2CPlayersUpdate(): MessageS2CPlayersUpdate {
  return { players: [] };
}

export const MessageS2CPlayersUpdate = {
  encode(message: MessageS2CPlayersUpdate, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    for (const v of message.players) {
      Player.encode(v!, writer.uint32(10).fork()).ldelim();
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageS2CPlayersUpdate {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageS2CPlayersUpdate();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 10) {
            break;
          }

          message.players.push(Player.decode(reader, reader.uint32()));
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): MessageS2CPlayersUpdate {
    return { players: Array.isArray(object?.players) ? object.players.map((e: any) => Player.fromJSON(e)) : [] };
  },

  toJSON(message: MessageS2CPlayersUpdate): unknown {
    const obj: any = {};
    if (message.players) {
      obj.players = message.players.map((e) => e ? Player.toJSON(e) : undefined);
    } else {
      obj.players = [];
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageS2CPlayersUpdate>, I>>(base?: I): MessageS2CPlayersUpdate {
    return MessageS2CPlayersUpdate.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageS2CPlayersUpdate>, I>>(object: I): MessageS2CPlayersUpdate {
    const message = createBaseMessageS2CPlayersUpdate();
    message.players = object.players?.map((e) => Player.fromPartial(e)) || [];
    return message;
  },
};

function createBaseMessageS2CPlanetData(): MessageS2CPlanetData {
  return { planets: [] };
}

export const MessageS2CPlanetData = {
  encode(message: MessageS2CPlanetData, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    for (const v of message.planets) {
      Planet.encode(v!, writer.uint32(10).fork()).ldelim();
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): MessageS2CPlanetData {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBaseMessageS2CPlanetData();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 10) {
            break;
          }

          message.planets.push(Planet.decode(reader, reader.uint32()));
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): MessageS2CPlanetData {
    return { planets: Array.isArray(object?.planets) ? object.planets.map((e: any) => Planet.fromJSON(e)) : [] };
  },

  toJSON(message: MessageS2CPlanetData): unknown {
    const obj: any = {};
    if (message.planets) {
      obj.planets = message.planets.map((e) => e ? Planet.toJSON(e) : undefined);
    } else {
      obj.planets = [];
    }
    return obj;
  },

  create<I extends Exact<DeepPartial<MessageS2CPlanetData>, I>>(base?: I): MessageS2CPlanetData {
    return MessageS2CPlanetData.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<MessageS2CPlanetData>, I>>(object: I): MessageS2CPlanetData {
    const message = createBaseMessageS2CPlanetData();
    message.planets = object.planets?.map((e) => Planet.fromPartial(e)) || [];
    return message;
  },
};

type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

export type DeepPartial<T> = T extends Builtin ? T
  : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
  : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
  : Partial<T>;

type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin ? P
  : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };

function isSet(value: any): boolean {
  return value !== null && value !== undefined;
}

A client/src/protocol/planet.ts => client/src/protocol/planet.ts +154 -0
@@ 0,0 1,154 @@
/* eslint-disable */
import * as _m0 from "protobufjs/minimal";

export const protobufPackage = "protocol.planet";

export enum PlanetType {
  Earth = 0,
  UNRECOGNIZED = -1,
}

export function planetTypeFromJSON(object: any): PlanetType {
  switch (object) {
    case 0:
    case "Earth":
      return PlanetType.Earth;
    case -1:
    case "UNRECOGNIZED":
    default:
      return PlanetType.UNRECOGNIZED;
  }
}

export function planetTypeToJSON(object: PlanetType): string {
  switch (object) {
    case PlanetType.Earth:
      return "Earth";
    case PlanetType.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

export interface Planet {
  /** Type of the planet */
  planetType: PlanetType;
  /** Translation on the X axis, in game units */
  x: number;
  /** Translation on the Y axis, in game units */
  y: number;
  /** The radius of the planet extending out from (x, y) */
  radius: number;
}

function createBasePlanet(): Planet {
  return { planetType: 0, x: 0, y: 0, radius: 0 };
}

export const Planet = {
  encode(message: Planet, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    if (message.planetType !== 0) {
      writer.uint32(8).int32(message.planetType);
    }
    if (message.x !== 0) {
      writer.uint32(21).float(message.x);
    }
    if (message.y !== 0) {
      writer.uint32(29).float(message.y);
    }
    if (message.radius !== 0) {
      writer.uint32(37).float(message.radius);
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): Planet {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBasePlanet();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 8) {
            break;
          }

          message.planetType = reader.int32() as any;
          continue;
        case 2:
          if (tag != 21) {
            break;
          }

          message.x = reader.float();
          continue;
        case 3:
          if (tag != 29) {
            break;
          }

          message.y = reader.float();
          continue;
        case 4:
          if (tag != 37) {
            break;
          }

          message.radius = reader.float();
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): Planet {
    return {
      planetType: isSet(object.planetType) ? planetTypeFromJSON(object.planetType) : 0,
      x: isSet(object.x) ? Number(object.x) : 0,
      y: isSet(object.y) ? Number(object.y) : 0,
      radius: isSet(object.radius) ? Number(object.radius) : 0,
    };
  },

  toJSON(message: Planet): unknown {
    const obj: any = {};
    message.planetType !== undefined && (obj.planetType = planetTypeToJSON(message.planetType));
    message.x !== undefined && (obj.x = message.x);
    message.y !== undefined && (obj.y = message.y);
    message.radius !== undefined && (obj.radius = message.radius);
    return obj;
  },

  create<I extends Exact<DeepPartial<Planet>, I>>(base?: I): Planet {
    return Planet.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<Planet>, I>>(object: I): Planet {
    const message = createBasePlanet();
    message.planetType = object.planetType ?? 0;
    message.x = object.x ?? 0;
    message.y = object.y ?? 0;
    message.radius = object.radius ?? 0;
    return message;
  },
};

type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

export type DeepPartial<T> = T extends Builtin ? T
  : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
  : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
  : Partial<T>;

type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin ? P
  : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };

function isSet(value: any): boolean {
  return value !== null && value !== undefined;
}

A client/src/protocol/player.ts => client/src/protocol/player.ts +127 -0
@@ 0,0 1,127 @@
/* eslint-disable */
import * as _m0 from "protobufjs/minimal";

export const protobufPackage = "protocol.player";

export interface Player {
  /** The rotation, clockwise, in degrees, of the player */
  rotation: number;
  /** The translation on the X axis, in game units, of the player */
  x: number;
  /** The translation on the Y axis, in game units, of the player */
  y: number;
  /** The username of the player */
  username: string;
}

function createBasePlayer(): Player {
  return { rotation: 0, x: 0, y: 0, username: "" };
}

export const Player = {
  encode(message: Player, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    if (message.rotation !== 0) {
      writer.uint32(13).float(message.rotation);
    }
    if (message.x !== 0) {
      writer.uint32(21).float(message.x);
    }
    if (message.y !== 0) {
      writer.uint32(29).float(message.y);
    }
    if (message.username !== "") {
      writer.uint32(34).string(message.username);
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): Player {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBasePlayer();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 13) {
            break;
          }

          message.rotation = reader.float();
          continue;
        case 2:
          if (tag != 21) {
            break;
          }

          message.x = reader.float();
          continue;
        case 3:
          if (tag != 29) {
            break;
          }

          message.y = reader.float();
          continue;
        case 4:
          if (tag != 34) {
            break;
          }

          message.username = reader.string();
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): Player {
    return {
      rotation: isSet(object.rotation) ? Number(object.rotation) : 0,
      x: isSet(object.x) ? Number(object.x) : 0,
      y: isSet(object.y) ? Number(object.y) : 0,
      username: isSet(object.username) ? String(object.username) : "",
    };
  },

  toJSON(message: Player): unknown {
    const obj: any = {};
    message.rotation !== undefined && (obj.rotation = message.rotation);
    message.x !== undefined && (obj.x = message.x);
    message.y !== undefined && (obj.y = message.y);
    message.username !== undefined && (obj.username = message.username);
    return obj;
  },

  create<I extends Exact<DeepPartial<Player>, I>>(base?: I): Player {
    return Player.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<Player>, I>>(object: I): Player {
    const message = createBasePlayer();
    message.rotation = object.rotation ?? 0;
    message.x = object.x ?? 0;
    message.y = object.y ?? 0;
    message.username = object.username ?? "";
    return message;
  },
};

type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

export type DeepPartial<T> = T extends Builtin ? T
  : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
  : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
  : Partial<T>;

type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin ? P
  : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };

function isSet(value: any): boolean {
  return value !== null && value !== undefined;
}

A client/src/protocol/starkingdoms-protocol.ts => client/src/protocol/starkingdoms-protocol.ts +157 -0
@@ 0,0 1,157 @@
/* eslint-disable */
import * as Long from "long";
import * as _m0 from "protobufjs/minimal";

export const protobufPackage = "protocol";

export interface PacketWrapper {
  /** What is the Packet ID of this packet? */
  packetId: number;
  /** Protobuf-encoded bytearray containing the actual packet */
  packetData: Uint8Array;
}

function createBasePacketWrapper(): PacketWrapper {
  return { packetId: 0, packetData: new Uint8Array() };
}

export const PacketWrapper = {
  encode(message: PacketWrapper, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
    if (message.packetId !== 0) {
      writer.uint32(8).int64(message.packetId);
    }
    if (message.packetData.length !== 0) {
      writer.uint32(18).bytes(message.packetData);
    }
    return writer;
  },

  decode(input: _m0.Reader | Uint8Array, length?: number): PacketWrapper {
    const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
    let end = length === undefined ? reader.len : reader.pos + length;
    const message = createBasePacketWrapper();
    while (reader.pos < end) {
      const tag = reader.uint32();
      switch (tag >>> 3) {
        case 1:
          if (tag != 8) {
            break;
          }

          message.packetId = longToNumber(reader.int64() as Long);
          continue;
        case 2:
          if (tag != 18) {
            break;
          }

          message.packetData = reader.bytes();
          continue;
      }
      if ((tag & 7) == 4 || tag == 0) {
        break;
      }
      reader.skipType(tag & 7);
    }
    return message;
  },

  fromJSON(object: any): PacketWrapper {
    return {
      packetId: isSet(object.packetId) ? Number(object.packetId) : 0,
      packetData: isSet(object.packetData) ? bytesFromBase64(object.packetData) : new Uint8Array(),
    };
  },

  toJSON(message: PacketWrapper): unknown {
    const obj: any = {};
    message.packetId !== undefined && (obj.packetId = Math.round(message.packetId));
    message.packetData !== undefined &&
      (obj.packetData = base64FromBytes(message.packetData !== undefined ? message.packetData : new Uint8Array()));
    return obj;
  },

  create<I extends Exact<DeepPartial<PacketWrapper>, I>>(base?: I): PacketWrapper {
    return PacketWrapper.fromPartial(base ?? {});
  },

  fromPartial<I extends Exact<DeepPartial<PacketWrapper>, I>>(object: I): PacketWrapper {
    const message = createBasePacketWrapper();
    message.packetId = object.packetId ?? 0;
    message.packetData = object.packetData ?? new Uint8Array();
    return message;
  },
};

declare var self: any | undefined;
declare var window: any | undefined;
declare var global: any | undefined;
var tsProtoGlobalThis: any = (() => {
  if (typeof globalThis !== "undefined") {
    return globalThis;
  }
  if (typeof self !== "undefined") {
    return self;
  }
  if (typeof window !== "undefined") {
    return window;
  }
  if (typeof global !== "undefined") {
    return global;
  }
  throw "Unable to locate global object";
})();

function bytesFromBase64(b64: string): Uint8Array {
  if (tsProtoGlobalThis.Buffer) {
    return Uint8Array.from(tsProtoGlobalThis.Buffer.from(b64, "base64"));
  } else {
    const bin = tsProtoGlobalThis.atob(b64);
    const arr = new Uint8Array(bin.length);
    for (let i = 0; i < bin.length; ++i) {
      arr[i] = bin.charCodeAt(i);
    }
    return arr;
  }
}

function base64FromBytes(arr: Uint8Array): string {
  if (tsProtoGlobalThis.Buffer) {
    return tsProtoGlobalThis.Buffer.from(arr).toString("base64");
  } else {
    const bin: string[] = [];
    arr.forEach((byte) => {
      bin.push(String.fromCharCode(byte));
    });
    return tsProtoGlobalThis.btoa(bin.join(""));
  }
}

type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;

export type DeepPartial<T> = T extends Builtin ? T
  : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
  : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
  : Partial<T>;

type KeysOfUnion<T> = T extends T ? keyof T : never;
export type Exact<P, I extends P> = P extends Builtin ? P
  : P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };

function longToNumber(long: Long): number {
  if (long.gt(Number.MAX_SAFE_INTEGER)) {
    throw new tsProtoGlobalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
  }
  return long.toNumber();
}

// If you get a compile-error about 'Constructor<Long> and ... have no overlap',
// add '--ts_proto_opt=esModuleInterop=true' as a flag when calling 'protoc'.
if (_m0.util.Long !== Long) {
  _m0.util.Long = Long as any;
  _m0.configure();
}

function isSet(value: any): boolean {
  return value !== null && value !== undefined;
}

A client/src/protocol/state.ts => client/src/protocol/state.ts +36 -0
@@ 0,0 1,36 @@
/* eslint-disable */

export const protobufPackage = "protocol.state";

export enum State {
  Handshake = 0,
  Play = 1,
  UNRECOGNIZED = -1,
}

export function stateFromJSON(object: any): State {
  switch (object) {
    case 0:
    case "Handshake":
      return State.Handshake;
    case 1:
    case "Play":
      return State.Play;
    case -1:
    case "UNRECOGNIZED":
    default:
      return State.UNRECOGNIZED;
  }
}

export function stateToJSON(object: State): string {
  switch (object) {
    case State.Handshake:
      return "Handshake";
    case State.Play:
      return "Play";
    case State.UNRECOGNIZED:
    default:
      return "UNRECOGNIZED";
  }
}

A client/src/serde.ts => client/src/serde.ts +14 -0
@@ 0,0 1,14 @@
import {PacketWrapper} from "./protocol/starkingdoms-protocol";

export function encode(id: number, pktd: Uint8Array): Uint8Array {
    let pkt = PacketWrapper.encode({
        packetId: id,
        packetData: pktd
    }).finish();
    return pkt;
}

export function decode(pktd: Uint8Array): [number, Uint8Array] {
    let pkt = PacketWrapper.decode(pktd);
    return [pkt.packetId, pkt.packetData];
}
\ No newline at end of file

M client/yarn.lock => client/yarn.lock +147 -5
@@ 112,11 112,6 @@
  resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.16.tgz#260f19b0a3300d22c3a3f52722c671dc561edaa3"
  integrity sha512-xJ7OH/nanouJO9pf03YsL9NAFQBHd8AqfrQd7Pf5laGyyTt/gToul6QYOA/i5i/q8y9iaM5DQFNTgpi995VkOg==

"@msgpack/msgpack@^3.0.0-beta2":
  version "3.0.0-beta2"
  resolved "https://registry.yarnpkg.com/@msgpack/msgpack/-/msgpack-3.0.0-beta2.tgz#5bccee30f84df220b33905e3d8249ba96deca0b7"
  integrity sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==

"@pixi/accessibility@7.2.4":
  version "7.2.4"
  resolved "https://registry.yarnpkg.com/@pixi/accessibility/-/accessibility-7.2.4.tgz#3198d0059c230c668b1179457346a3b5dcba6e64"


@@ 332,6 327,59 @@
    eventemitter3 "^4.0.0"
    url "^0.11.0"

"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
  version "1.1.2"
  resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
  integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==

"@protobufjs/base64@^1.1.2":
  version "1.1.2"
  resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
  integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==

"@protobufjs/codegen@^2.0.4":
  version "2.0.4"
  resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
  integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==

"@protobufjs/eventemitter@^1.1.0":
  version "1.1.0"
  resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
  integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==

"@protobufjs/fetch@^1.1.0":
  version "1.1.0"
  resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
  integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==
  dependencies:
    "@protobufjs/aspromise" "^1.1.1"
    "@protobufjs/inquire" "^1.1.0"

"@protobufjs/float@^1.0.2":
  version "1.0.2"
  resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
  integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==

"@protobufjs/inquire@^1.1.0":
  version "1.1.0"
  resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
  integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==

"@protobufjs/path@^1.1.2":
  version "1.1.2"
  resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
  integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==

"@protobufjs/pool@^1.1.0":
  version "1.1.0"
  resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
  integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==

"@protobufjs/utf8@^1.1.0":
  version "1.1.0"
  resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
  integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==

"@types/css-font-loading-module@^0.0.7":
  version "0.0.7"
  resolved "https://registry.yarnpkg.com/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz#2f98ede46acc0975de85c0b7b0ebe06041d24601"


@@ 342,16 390,53 @@
  resolved "https://registry.yarnpkg.com/@types/earcut/-/earcut-2.1.1.tgz#573a0af609f17005c751f6f4ffec49cfe358ea51"
  integrity sha512-w8oigUCDjElRHRRrMvn/spybSMyX8MTkKA5Dv+tS1IE/TgmNZPqUYtvYBXGY8cieSE66gm+szeK+bnbxC2xHTQ==

"@types/long@^4.0.1":
  version "4.0.2"
  resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
  integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==

"@types/node@>=13.7.0":
  version "18.15.11"
  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f"
  integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==

"@types/object-hash@^1.3.0":
  version "1.3.4"
  resolved "https://registry.yarnpkg.com/@types/object-hash/-/object-hash-1.3.4.tgz#079ba142be65833293673254831b5e3e847fe58b"
  integrity sha512-xFdpkAkikBgqBdG9vIlsqffDV8GpvnPEzs0IUtr1v3BEB97ijsFQ4RXVbUZwjFThhB4MDSTUfvmxUD5PGx0wXA==

"@types/offscreencanvas@^2019.6.4":
  version "2019.7.0"
  resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz#e4a932069db47bb3eabeb0b305502d01586fa90d"
  integrity sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==

case-anything@^2.1.10:
  version "2.1.10"
  resolved "https://registry.yarnpkg.com/case-anything/-/case-anything-2.1.10.tgz#d18a6ca968d54ec3421df71e3e190f3bced23410"
  integrity sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ==

colord@^2.9.3:
  version "2.9.3"
  resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
  integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==

dataloader@^1.4.0:
  version "1.4.0"
  resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.4.0.tgz#bca11d867f5d3f1b9ed9f737bd15970c65dff5c8"
  integrity sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==

detect-libc@^1.0.3:
  version "1.0.3"
  resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
  integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==

dprint-node@^1.0.7:
  version "1.0.7"
  resolved "https://registry.yarnpkg.com/dprint-node/-/dprint-node-1.0.7.tgz#f571eaf61affb3a696cff1bdde78a021875ba540"
  integrity sha512-NTZOW9A7ipb0n7z7nC3wftvsbceircwVHSgzobJsEQa+7RnOMbhrfX5IflA6CtC4GA63DSAiHYXa4JKEy9F7cA==
  dependencies:
    detect-libc "^1.0.3"

earcut@^2.2.4:
  version "2.2.4"
  resolved "https://registry.yarnpkg.com/earcut/-/earcut-2.2.4.tgz#6d02fd4d68160c114825d06890a92ecaae60343a"


@@ 419,11 504,21 @@ ismobilejs@^1.1.0:
  resolved "https://registry.yarnpkg.com/ismobilejs/-/ismobilejs-1.1.1.tgz#c56ca0ae8e52b24ca0f22ba5ef3215a2ddbbaa0e"
  integrity sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==

long@^4.0.0:
  version "4.0.0"
  resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
  integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==

nanoid@^3.3.4:
  version "3.3.6"
  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
  integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==

object-hash@^1.3.1:
  version "1.3.1"
  resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df"
  integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==

path-parse@^1.0.7:
  version "1.0.7"
  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"


@@ 479,6 574,25 @@ postcss@^8.4.21:
    picocolors "^1.0.0"
    source-map-js "^1.0.2"

protobufjs@^6.11.3, protobufjs@^6.8.8:
  version "6.11.3"
  resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74"
  integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==
  dependencies:
    "@protobufjs/aspromise" "^1.1.2"
    "@protobufjs/base64" "^1.1.2"
    "@protobufjs/codegen" "^2.0.4"
    "@protobufjs/eventemitter" "^1.1.0"
    "@protobufjs/fetch" "^1.1.0"
    "@protobufjs/float" "^1.0.2"
    "@protobufjs/inquire" "^1.1.0"
    "@protobufjs/path" "^1.1.2"
    "@protobufjs/pool" "^1.1.0"
    "@protobufjs/utf8" "^1.1.0"
    "@types/long" "^4.0.1"
    "@types/node" ">=13.7.0"
    long "^4.0.0"

punycode@1.3.2:
  version "1.3.2"
  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"


@@ 515,6 629,34 @@ supports-preserve-symlinks-flag@^1.0.0:
  resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==

ts-poet@^6.4.1:
  version "6.4.1"
  resolved "https://registry.yarnpkg.com/ts-poet/-/ts-poet-6.4.1.tgz#e68d314a07cf9c0d568a3bfd87023ec91ff77964"
  integrity sha512-AjZEs4h2w4sDfwpHMxQKHrTlNh2wRbM5NRXmLz0RiH+yPGtSQFbe9hBpNocU8vqVNgfh0BIOiXR80xDz3kKxUQ==
  dependencies:
    dprint-node "^1.0.7"

ts-proto-descriptors@1.8.0:
  version "1.8.0"
  resolved "https://registry.yarnpkg.com/ts-proto-descriptors/-/ts-proto-descriptors-1.8.0.tgz#ba4a26c156a77f76c68d7dac0d049bd2aa3f0920"
  integrity sha512-iV20plcI8+GRkeZIAygxOOH0p2xpOsKfw9kI1W20NCwawi1/4bG/YRd9rQY9XSJP+lD9j7XbSy3tFFuikfsljw==
  dependencies:
    long "^4.0.0"
    protobufjs "^6.8.8"

ts-proto@^1.146.0:
  version "1.146.0"
  resolved "https://registry.yarnpkg.com/ts-proto/-/ts-proto-1.146.0.tgz#4017c700976d3657009c4e7e741377a4272ffc27"
  integrity sha512-OyBZRjmqqw+aatLEUbRooWO6VKTtOLJQyaQFMciigEZPNgTsWtApqHpQDtqDMQFWEXhIARqEV+B7ZJx8cljhZA==
  dependencies:
    "@types/object-hash" "^1.3.0"
    case-anything "^2.1.10"
    dataloader "^1.4.0"
    object-hash "^1.3.1"
    protobufjs "^6.11.3"
    ts-poet "^6.4.1"
    ts-proto-descriptors "1.8.0"

typescript@^4.9.3:
  version "4.9.5"
  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"

M server/src/handler.rs => server/src/handler.rs +1 -0
@@ 78,6 78,7 @@ pub async fn handle_client(mgr: ClientManager, data: Arc<RwLock<PhysicsData>>, r
                State::Handshake => {
                    match pkt {
                        MessageC2S::Hello(pkt) => {
                            info!("client sent hello");
                            if !matches!(pkt.next_state.unwrap(), State::Play) {
                                error!("client sent unexpected state {:?} (expected: Play)", pkt.next_state);
                                let msg = MessageS2C::Goodbye(MessageS2CGoodbye {