mirror of
https://github.com/osmarks/ewo3.git
synced 2025-01-02 21:40:36 +00:00
initial commit
This commit is contained in:
commit
db02d05778
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
/node_modules
|
893
Cargo.lock
generated
Normal file
893
Cargo.lock
generated
Normal file
@ -0,0 +1,893 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-encoding"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "euclid"
|
||||
version = "0.22.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0f0eb73b934648cd7a4a61f1b15391cd95dab0b4da6e2e66c2a072c144b4a20"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ewo3"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"euclid",
|
||||
"fastrand",
|
||||
"futures-util",
|
||||
"hecs",
|
||||
"lazy_static",
|
||||
"noise-functions",
|
||||
"seahash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-macros 0.2.6",
|
||||
"tokio-tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hecs"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cbc675ee8d97b4d206a985137f8ad59666538f56f906474f554467a63c776d"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"serde",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "noise-functions"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822a69eedf004ac2f492119af7a8203790b1c9115b9a9ef6bcd0cde5d6783565"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.35.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "seahash"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros 2.3.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "becd34a233e7e31a3dbf7c7241b38320f57393dcae8e7324b0167d21b8e320b0"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"tokio",
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"rand",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.5",
|
||||
"windows_aarch64_msvc 0.52.5",
|
||||
"windows_i686_gnu 0.52.5",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.5",
|
||||
"windows_x86_64_gnu 0.52.5",
|
||||
"windows_x86_64_gnullvm 0.52.5",
|
||||
"windows_x86_64_msvc 0.52.5",
|
||||
]
|
||||
|
||||
[[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_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[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_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[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_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[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_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
]
|
22
Cargo.toml
Normal file
22
Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "ewo3"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
hecs = { version = "0.10", features = ["column-serialize"] }
|
||||
euclid = { version = "0.22", features = ["serde"] }
|
||||
fastrand = "2"
|
||||
tokio-tungstenite = "0.23"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
futures-util = "0.3"
|
||||
tokio-macros = { version = "0.2.0-alpha.6" }
|
||||
anyhow = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
slab = "0.4"
|
||||
lazy_static = "1"
|
||||
seahash = "4"
|
||||
noise-functions = "0.2"
|
463
package-lock.json
generated
Normal file
463
package-lock.json
generated
Normal file
@ -0,0 +1,463 @@
|
||||
{
|
||||
"name": "ewo3",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.12.15",
|
||||
"esbuild-svelte": "^0.5.3",
|
||||
"sass": "^1.68.0",
|
||||
"svelte-preprocess-sass": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.12.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.15.tgz",
|
||||
"integrity": "sha512-72V4JNd2+48eOVCXx49xoSWHgC3/cCy96e7mbXKY+WOWghN00cCmlGnwVLRhRHorvv0dgCyuMYBZlM2xDM5OQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-svelte": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.5.3.tgz",
|
||||
"integrity": "sha512-KByKD/yt8QaqKjLu32MG3MXBExJYlDM0QwzW3pzKLJR4eev0923DrUKRHPBBjB+OVirUtZnEJE/qitjdW/WyAw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"svelte": "^3.38.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"esbuild": ">=0.9.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz",
|
||||
"integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.68.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.68.0.tgz",
|
||||
"integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": ">=3.0.0 <4.0.0",
|
||||
"immutable": "^4.0.0",
|
||||
"source-map-js": ">=0.6.2 <2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"sass": "sass.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte": {
|
||||
"version": "3.38.3",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.38.3.tgz",
|
||||
"integrity": "sha512-N7bBZJH0iF24wsalFZF+fVYMUOigaAUQMIcEKHO3jstK/iL8VmP9xE+P0/a76+FkNcWt+TDv2Gx1taUoUscrvw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-preprocess-filter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte-preprocess-filter/-/svelte-preprocess-filter-1.0.0.tgz",
|
||||
"integrity": "sha512-92innv59nyEx24xbfcSurB5ocwC8qFdDtGli/JVMHzJsxyvV2yjQKIcbUqU9VIV5mKUWO2PoY93nncS2yF4ULQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/svelte-preprocess-sass": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/svelte-preprocess-sass/-/svelte-preprocess-sass-2.0.1.tgz",
|
||||
"integrity": "sha512-0y4FjRsRWcN7rJeNJnSfZ7LVAz6S7/j9Dg24XFRelr/rjMMjXORdEvXy4r38fUYmyk9Y7yjwlHCiqyGxMHhEbg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"svelte-preprocess-filter": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"sass": "^1.35.2"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true
|
||||
},
|
||||
"braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.3.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
}
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.12.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.15.tgz",
|
||||
"integrity": "sha512-72V4JNd2+48eOVCXx49xoSWHgC3/cCy96e7mbXKY+WOWghN00cCmlGnwVLRhRHorvv0dgCyuMYBZlM2xDM5OQw==",
|
||||
"dev": true
|
||||
},
|
||||
"esbuild-svelte": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-svelte/-/esbuild-svelte-0.5.3.tgz",
|
||||
"integrity": "sha512-KByKD/yt8QaqKjLu32MG3MXBExJYlDM0QwzW3pzKLJR4eev0923DrUKRHPBBjB+OVirUtZnEJE/qitjdW/WyAw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"svelte": "^3.38.3"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"immutable": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz",
|
||||
"integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==",
|
||||
"dev": true
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
||||
"dev": true
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true
|
||||
},
|
||||
"normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||
"dev": true
|
||||
},
|
||||
"readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"picomatch": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"sass": {
|
||||
"version": "1.68.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.68.0.tgz",
|
||||
"integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": ">=3.0.0 <4.0.0",
|
||||
"immutable": "^4.0.0",
|
||||
"source-map-js": ">=0.6.2 <2.0.0"
|
||||
}
|
||||
},
|
||||
"source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||
"dev": true
|
||||
},
|
||||
"svelte": {
|
||||
"version": "3.38.3",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.38.3.tgz",
|
||||
"integrity": "sha512-N7bBZJH0iF24wsalFZF+fVYMUOigaAUQMIcEKHO3jstK/iL8VmP9xE+P0/a76+FkNcWt+TDv2Gx1taUoUscrvw==",
|
||||
"dev": true
|
||||
},
|
||||
"svelte-preprocess-filter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte-preprocess-filter/-/svelte-preprocess-filter-1.0.0.tgz",
|
||||
"integrity": "sha512-92innv59nyEx24xbfcSurB5ocwC8qFdDtGli/JVMHzJsxyvV2yjQKIcbUqU9VIV5mKUWO2PoY93nncS2yF4ULQ==",
|
||||
"dev": true
|
||||
},
|
||||
"svelte-preprocess-sass": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/svelte-preprocess-sass/-/svelte-preprocess-sass-2.0.1.tgz",
|
||||
"integrity": "sha512-0y4FjRsRWcN7rJeNJnSfZ7LVAz6S7/j9Dg24XFRelr/rjMMjXORdEvXy4r38fUYmyk9Y7yjwlHCiqyGxMHhEbg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"svelte-preprocess-filter": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
8
package.json
Normal file
8
package.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.12.15",
|
||||
"esbuild-svelte": "^0.5.3",
|
||||
"sass": "^1.68.0",
|
||||
"svelte-preprocess-sass": "^2.0.1"
|
||||
}
|
||||
}
|
171
src/App.svelte
Normal file
171
src/App.svelte
Normal file
@ -0,0 +1,171 @@
|
||||
<style lang="sass">
|
||||
\:global(*)
|
||||
box-sizing: border-box
|
||||
|
||||
\:global(html)
|
||||
scrollbar-color: black lightgray
|
||||
|
||||
\:global(body)
|
||||
font-family: "Fira Sans", "Noto Sans", "Segoe UI", Verdana, sans-serif
|
||||
font-weight: 300
|
||||
overflow-anchor: none
|
||||
//margin: 0
|
||||
//min-height: 100vh
|
||||
|
||||
\:global(strong)
|
||||
font-weight: bold
|
||||
|
||||
@mixin header
|
||||
border-bottom: 1px solid gray
|
||||
margin: 0
|
||||
margin-bottom: 0.5em
|
||||
font-weight: 500
|
||||
//a
|
||||
//color: inherit
|
||||
|
||||
\:global(h1)
|
||||
@include header
|
||||
\:global(h2)
|
||||
@include header
|
||||
\:global(h3)
|
||||
@include header
|
||||
\:global(h4)
|
||||
@include header
|
||||
\:global(h5)
|
||||
@include header
|
||||
\:global(h6)
|
||||
@include header
|
||||
\:global(ul)
|
||||
list-style-type: square
|
||||
padding: 0
|
||||
padding-left: 1em
|
||||
|
||||
input, button, select
|
||||
border-radius: 0
|
||||
border: 1px solid gray
|
||||
padding: 0.5em
|
||||
|
||||
.game-display
|
||||
.row
|
||||
white-space: nowrap
|
||||
.cell
|
||||
display: inline-block
|
||||
text-align: center
|
||||
|
||||
.wrapper
|
||||
display: flex
|
||||
</style>
|
||||
|
||||
<h1>EWO3 Memetic Edition</h1>
|
||||
|
||||
<div class="wrapper">
|
||||
<div class="game-display">
|
||||
{#each grid as row, y}
|
||||
<div class="row" style={`height: ${VERT}px; ` + (y % 2 === 1 ? `padding-left: ${HORIZ/2}px` : "")}>
|
||||
{#each row as cell}
|
||||
<div class="cell" style={`width: ${HORIZ}px; height: ${VERT}px; line-height: ${VERT}px; opacity: ${cell[1] * 100}%`}>{cell[0]}</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="controls">
|
||||
{#if dead}
|
||||
You have died to death. <a href="#" on:click={restart}>Restart</a>.
|
||||
{/if}
|
||||
{#if players}
|
||||
{players} connected players.
|
||||
{/if}
|
||||
{#if health}
|
||||
Your health is {health}.
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<svelte:window on:keydown={keydown} on:keyup={keyup}></svelte:window>
|
||||
|
||||
<script>
|
||||
import * as util from "./util"
|
||||
|
||||
let dead = false
|
||||
let health
|
||||
let players
|
||||
|
||||
let ws
|
||||
const connect = () => {
|
||||
ws = new WebSocket(window.location.protocol === "https:" ? "wss://ewo.osmarks.net/" : "ws://localhost:8080/")
|
||||
|
||||
ws.addEventListener("message", ev => {
|
||||
const data = JSON.parse(ev.data)
|
||||
if (data.Display) {
|
||||
const newGrid = blankGrid()
|
||||
for (const [q, r, c, o] of data.Display.nearby) {
|
||||
const col = q + (r - (r & 1)) / 2
|
||||
const row = r
|
||||
newGrid[row + OFFSET][col + OFFSET] = [c, o]
|
||||
}
|
||||
grid = newGrid
|
||||
health = data.Display.health
|
||||
}
|
||||
if (data === "Dead") {
|
||||
dead = true
|
||||
}
|
||||
if (data.PlayerCount) {
|
||||
players = data.PlayerCount
|
||||
}
|
||||
for (const key of keysDown) {
|
||||
const input = INPUTS[key]
|
||||
if (input) {
|
||||
ws.send(JSON.stringify(input))
|
||||
}
|
||||
}
|
||||
keysDown = new Set(Array.from(keysDown).map(k => !keysCleared.has(k)))
|
||||
keysCleared = new Set()
|
||||
})
|
||||
|
||||
ws.addEventListener("close", ev => {
|
||||
console.warn("oh no")
|
||||
})
|
||||
}
|
||||
|
||||
const reconnect = () => {
|
||||
if (ws) ws.close()
|
||||
connect()
|
||||
}
|
||||
|
||||
const restart = ev => {
|
||||
ev.preventDefault()
|
||||
dead = false
|
||||
reconnect()
|
||||
}
|
||||
|
||||
const GRIDSIZE = 33
|
||||
const OFFSET = Math.floor(GRIDSIZE/2)
|
||||
const SIZE = 16
|
||||
const HORIZ = Math.sqrt(3) * SIZE
|
||||
const VERT = 3/2 * SIZE
|
||||
|
||||
const blankGrid = () => new Array(GRIDSIZE).fill(null).map(() => new Array(GRIDSIZE).fill(""))
|
||||
|
||||
let grid = blankGrid()
|
||||
|
||||
let keysDown = new Set()
|
||||
let keysCleared = new Set()
|
||||
|
||||
const keydown = ev => {
|
||||
keysDown.add(ev.key)
|
||||
}
|
||||
const keyup = ev => {
|
||||
keysCleared.add(ev.key)
|
||||
}
|
||||
|
||||
const INPUTS = {
|
||||
"w": "UpLeft",
|
||||
"e": "UpRight",
|
||||
"a": "Left",
|
||||
"d": "Right",
|
||||
"z": "DownLeft",
|
||||
"x": "DownRight"
|
||||
}
|
||||
|
||||
connect()
|
||||
</script>
|
5
src/app.js
Normal file
5
src/app.js
Normal file
@ -0,0 +1,5 @@
|
||||
import App from "./App.svelte"
|
||||
|
||||
new App({
|
||||
target: document.body,
|
||||
})
|
25
src/build.js
Normal file
25
src/build.js
Normal file
@ -0,0 +1,25 @@
|
||||
const esbuild = require("esbuild")
|
||||
const sveltePlugin = require("esbuild-svelte")
|
||||
const path = require("path")
|
||||
const { sass } = require("svelte-preprocess-sass")
|
||||
|
||||
esbuild
|
||||
.build({
|
||||
entryPoints: [path.join(__dirname, "app.js")],
|
||||
bundle: true,
|
||||
minify: false,
|
||||
outfile: path.join(__dirname, "../static/app.js"),
|
||||
plugins: [sveltePlugin({
|
||||
preprocess: {
|
||||
style: sass()
|
||||
}
|
||||
})],
|
||||
loader: {
|
||||
".woff": "file",
|
||||
".woff2": "file",
|
||||
".ttf": "file"
|
||||
},
|
||||
logLevel: "info",
|
||||
watch: process.argv.join(" ").includes("watch")
|
||||
})
|
||||
.catch(() => process.exit(1))
|
671
src/main.rs
Normal file
671
src/main.rs
Normal file
@ -0,0 +1,671 @@
|
||||
use hecs::{Entity, World};
|
||||
use euclid::{Point3D, Point2D, Vector2D};
|
||||
use futures_util::{stream::TryStreamExt, SinkExt, StreamExt};
|
||||
use noise_functions::Sample3;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio_tungstenite::tungstenite::protocol::Message;
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
use anyhow::{Result, Context, anyhow};
|
||||
use std::{collections::{hash_map::Entry, HashMap}, hash::{Hash, Hasher}, net::SocketAddr, sync::Arc, thread::current, time::Duration};
|
||||
use slab::Slab;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
struct AxialWorldSpace;
|
||||
struct CubicWorldSpace;
|
||||
type Coord = Point2D<i64, AxialWorldSpace>;
|
||||
type CubicCoord = Point3D<i64, CubicWorldSpace>;
|
||||
type CoordVec = Vector2D<i64, AxialWorldSpace>;
|
||||
|
||||
fn to_cubic(p0: Coord) -> CubicCoord {
|
||||
CubicCoord::new(p0.x, p0.y, -p0.x - p0.y)
|
||||
}
|
||||
|
||||
fn hex_distance(p0: Coord, p1: Coord) -> i64 {
|
||||
let ax_dist = p0 - p1;
|
||||
(ax_dist.x.abs() + ax_dist.y.abs() + (ax_dist.x + ax_dist.y).abs()) / 2
|
||||
}
|
||||
|
||||
fn on_axis(p: CoordVec) -> bool {
|
||||
let p = to_cubic(Coord::origin() + p);
|
||||
let mut zero_ax = 0;
|
||||
if p.x == 0 { zero_ax += 1 }
|
||||
if p.y == 0 { zero_ax += 1 }
|
||||
if p.z == 0 { zero_ax += 1 }
|
||||
zero_ax >= 1
|
||||
}
|
||||
|
||||
async fn handle_connection(raw_stream: TcpStream, addr: SocketAddr, mut frames_rx: mpsc::Receiver<Frame>, inputs_tx: mpsc::Sender<Input>) -> Result<()> {
|
||||
let ws_stream = tokio_tungstenite::accept_async(raw_stream).await.context("websocket handshake failure")?;
|
||||
let (mut outgoing, incoming) = ws_stream.split();
|
||||
|
||||
let broadcast_incoming = incoming.map_err(anyhow::Error::from).try_for_each(|msg| {
|
||||
let inputs_tx = inputs_tx.clone();
|
||||
async move {
|
||||
if msg.is_close() { return Err(anyhow!("connection closed")) }
|
||||
|
||||
let input: Input = serde_json::from_str(msg.to_text()?)?;
|
||||
|
||||
inputs_tx.send(input).await?;
|
||||
|
||||
anyhow::Result::<(), anyhow::Error>::Ok(())
|
||||
}
|
||||
});
|
||||
|
||||
let send_state = async move {
|
||||
while let Some(frame) = frames_rx.recv().await {
|
||||
outgoing.send(Message::Text(serde_json::to_string(&frame)?)).await?;
|
||||
match frame {
|
||||
Frame::Dead => return Ok(()),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
anyhow::Result::<(), anyhow::Error>::Ok(())
|
||||
};
|
||||
|
||||
tokio::select! {
|
||||
result = broadcast_incoming => {
|
||||
println!("{:?}", result)
|
||||
},
|
||||
result = send_state => {
|
||||
println!("{:?}", result)
|
||||
}
|
||||
};
|
||||
|
||||
println!("{} disconnected", &addr);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
enum Input {
|
||||
UpLeft,
|
||||
UpRight,
|
||||
Left,
|
||||
Right,
|
||||
DownLeft,
|
||||
DownRight,
|
||||
Dig
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
enum Frame {
|
||||
Dead,
|
||||
Display { nearby: Vec<(i64, i64, char, f32)>, health: f32 },
|
||||
PlayerCount(usize)
|
||||
}
|
||||
|
||||
struct Client {
|
||||
inputs_rx: mpsc::Receiver<Input>,
|
||||
frames_tx: mpsc::Sender<Frame>,
|
||||
entity: Entity
|
||||
}
|
||||
|
||||
struct GameState {
|
||||
world: World,
|
||||
clients: Slab<Client>,
|
||||
ticks: u64
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Item {
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct PlayerCharacter;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
struct Position(Coord);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
struct MovingInto(Coord);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Health(f32, f32);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Render(char);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Attack { damage: StochasticNumber, energy: f32 }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct RangedAttack { damage: StochasticNumber, energy: f32, range: u64 }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct DespawnOnTick(u64);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct DespawnRandomly(u64);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct EnemyTarget { spawn_range: std::ops::RangeInclusive<i64>, spawn_density: f32, spawn_rate_inv: usize, aggression_range: i64 }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Enemy;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct MoveCost(StochasticNumber);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Collidable;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Velocity(CoordVec);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct DeferredRandomly<T: Clone + std::fmt::Debug + hecs::Bundle>(u64, T);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Terrain;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Obstruction { entry_cost: StochasticNumber, exit_cost: StochasticNumber }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Energy { current: f32, regeneration_rate: f32, burst: f32 }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct DespawnOnImpact;
|
||||
|
||||
impl Energy {
|
||||
fn try_consume(&mut self, cost: f32) -> bool {
|
||||
if self.current >= -1e-12 { // numerics
|
||||
self.current -= cost;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const VIEW: i64 = 15;
|
||||
const WALL: i64 = 128;
|
||||
const RANDOM_DESPAWN_INV_RATE: u64 = 4000;
|
||||
const DIRECTIONS: &[CoordVec] = &[CoordVec::new(0, -1), CoordVec::new(1, -1), CoordVec::new(-1, 0), CoordVec::new(1, 0), CoordVec::new(0, 1), CoordVec::new(-1, 1)];
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum BaseTerrain {
|
||||
Empty,
|
||||
Occupied,
|
||||
VeryOccupied
|
||||
}
|
||||
|
||||
impl BaseTerrain {
|
||||
fn can_enter(&self) -> bool {
|
||||
*self == BaseTerrain::Empty
|
||||
}
|
||||
|
||||
fn symbol(&self) -> Option<char> {
|
||||
match *self {
|
||||
Self::Empty => None,
|
||||
Self::Occupied => Some('#'),
|
||||
Self::VeryOccupied => Some('█')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const NOISE_SCALE: f32 = 0.05;
|
||||
|
||||
fn get_base_terrain(pos: Coord) -> BaseTerrain {
|
||||
let distance = hex_distance(pos, Coord::origin());
|
||||
if distance >= (WALL + 12) {
|
||||
return BaseTerrain::VeryOccupied
|
||||
}
|
||||
if distance >= WALL {
|
||||
return BaseTerrain::Occupied
|
||||
}
|
||||
let pos = to_cubic(pos);
|
||||
let noise = noise_functions::CellDistance.ridged(2, 1.00, 0.20).seed(406).sample3([pos.x as f32 * NOISE_SCALE, pos.y as f32 * NOISE_SCALE, pos.z as f32 * NOISE_SCALE]);
|
||||
if noise >= 0.3 {
|
||||
return BaseTerrain::VeryOccupied
|
||||
}
|
||||
if noise >= 0.2 {
|
||||
return BaseTerrain::Occupied
|
||||
}
|
||||
return BaseTerrain::Empty
|
||||
}
|
||||
|
||||
fn sample_range(range: i64) -> CoordVec {
|
||||
let q = fastrand::i64(-range..=range);
|
||||
let r = fastrand::i64((-range).max(-q-range)..=range.min(-q+range));
|
||||
CoordVec::new(q, r)
|
||||
}
|
||||
|
||||
struct EnemySpec {
|
||||
symbol: char,
|
||||
min_damage: f32,
|
||||
damage_range: f32,
|
||||
initial_health: f32,
|
||||
move_delay: usize,
|
||||
attack_cooldown: u64,
|
||||
ranged: bool
|
||||
}
|
||||
|
||||
impl EnemySpec {
|
||||
// Numbers ported from original EWO. Fudge constants added elsewhere.
|
||||
fn random() -> EnemySpec {
|
||||
match fastrand::usize(0..650) {
|
||||
0..=99 => EnemySpec { symbol: 'I', min_damage: 10.0, damage_range: 5.0, initial_health: 50.0, move_delay: 70, attack_cooldown: 10, ranged: false }, // IBIS
|
||||
100..=199 => EnemySpec { symbol: 'K', min_damage: 5.0, damage_range: 15.0, initial_health: 30.0, move_delay: 40, attack_cooldown: 10, ranged: false }, // KESTREL
|
||||
200..=299 => EnemySpec { symbol: 'S', min_damage: 5.0, damage_range: 5.0, initial_health: 20.0, move_delay: 50, attack_cooldown: 10, ranged: false }, // SNAKE
|
||||
300..=399 => EnemySpec { symbol: 'E', min_damage: 10.0, damage_range: 20.0, initial_health: 80.0, move_delay: 80, attack_cooldown: 10, ranged: false }, // EMU
|
||||
400..=499 => EnemySpec { symbol: 'O', min_damage: 8.0, damage_range: 17.0, initial_health: 150.0, move_delay: 100, attack_cooldown: 10, ranged: false }, // OGRE
|
||||
500..=599 => EnemySpec { symbol: 'R', min_damage: 5.0, damage_range: 5.0, initial_health: 15.0, move_delay: 40, attack_cooldown: 10, ranged: false }, // RAT
|
||||
600..=609 => EnemySpec { symbol: 'M' , min_damage: 20.0, damage_range: 10.0, initial_health: 150.0, move_delay: 70, attack_cooldown: 10, ranged: false }, // MOA
|
||||
610..=649 => EnemySpec { symbol: 'P', min_damage: 10.0, damage_range: 5.0, initial_health: 15.0, move_delay: 20, attack_cooldown: 10, ranged: true }, // PLATYPUS
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn count_hexes(x: i64) -> i64 {
|
||||
x*(x+1)*3+1
|
||||
}
|
||||
|
||||
fn rng_from_hash<H: Hash>(x: H) -> fastrand::Rng {
|
||||
let mut h = seahash::SeaHasher::new();
|
||||
x.hash(&mut h);
|
||||
fastrand::Rng::with_seed(h.finish())
|
||||
}
|
||||
|
||||
fn consume_energy_if_available(e: &mut Option<&mut Energy>, cost: f32) -> bool {
|
||||
e.is_none() || e.as_mut().unwrap().try_consume(cost)
|
||||
}
|
||||
|
||||
// Box-Muller transform
|
||||
fn normal() -> f32 {
|
||||
let u = fastrand::f32();
|
||||
let v = fastrand::f32();
|
||||
(v * std::f32::consts::TAU).cos() * (-2.0 * u.ln()).sqrt()
|
||||
}
|
||||
|
||||
fn normal_scaled(mu: f32, sigma: f32) -> f32 {
|
||||
normal() * sigma + mu
|
||||
}
|
||||
|
||||
fn triangle_distribution(min: f32, max: f32, mode: f32) -> f32 {
|
||||
let sample = fastrand::f32();
|
||||
let threshold = (mode - min) / (max - min);
|
||||
if sample < threshold {
|
||||
min + (sample * (max - min) * (mode - min)).sqrt()
|
||||
} else {
|
||||
max - ((1.0 - sample) * (max - min) * (max - mode)).sqrt()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum StochasticNumber {
|
||||
Constant(f32),
|
||||
Triangle { min: f32, max: f32, mode: f32 }
|
||||
}
|
||||
|
||||
impl StochasticNumber {
|
||||
fn sample(&self) -> f32 {
|
||||
match self {
|
||||
StochasticNumber::Constant(x) => *x,
|
||||
StochasticNumber::Triangle { min, max, mode } => triangle_distribution(*min, *max, *mode)
|
||||
}
|
||||
}
|
||||
|
||||
fn triangle_from_min_range(min: f32, range: f32) -> Self {
|
||||
StochasticNumber::Triangle { min: min, max: min + range, mode: (min + range) / 2.0 }
|
||||
}
|
||||
}
|
||||
|
||||
async fn game_tick(state: &mut GameState) -> Result<()> {
|
||||
let mut terrain_positions = HashMap::new();
|
||||
let mut positions = HashMap::new();
|
||||
|
||||
for (entity, pos) in state.world.query_mut::<hecs::With<&Position, &Collidable>>() {
|
||||
positions.insert(pos.0, entity);
|
||||
}
|
||||
|
||||
for (entity, pos) in state.world.query_mut::<hecs::With<&Position, &Terrain>>() {
|
||||
terrain_positions.insert(pos.0, entity);
|
||||
}
|
||||
|
||||
let mut buffer = hecs::CommandBuffer::new();
|
||||
|
||||
// Spawn enemies
|
||||
for (_entity, (Position(pos), EnemyTarget { spawn_range, spawn_density, spawn_rate_inv, .. })) in state.world.query::<(&Position, &EnemyTarget)>().iter() {
|
||||
if fastrand::usize(0..*spawn_rate_inv) == 0 {
|
||||
let c = count_hexes(*spawn_range.end());
|
||||
let mut newpos = *pos + sample_range(*spawn_range.end());
|
||||
let mut occupied = false;
|
||||
for _ in 0..(c as f32 / spawn_density * 0.005).ceil() as usize {
|
||||
if positions.contains_key(&newpos) {
|
||||
occupied = true;
|
||||
break;
|
||||
}
|
||||
newpos = *pos + sample_range(*spawn_range.end());
|
||||
}
|
||||
if !occupied && get_base_terrain(newpos).can_enter() && hex_distance(newpos, *pos) >= *spawn_range.start() {
|
||||
let spec = EnemySpec::random();
|
||||
if spec.ranged {
|
||||
buffer.spawn((
|
||||
Render(spec.symbol),
|
||||
Health(spec.initial_health, spec.initial_health),
|
||||
Enemy,
|
||||
RangedAttack { damage: StochasticNumber::triangle_from_min_range(spec.min_damage, spec.damage_range), energy: spec.attack_cooldown as f32, range: 4 },
|
||||
Position(newpos),
|
||||
MoveCost(StochasticNumber::Triangle { min: 0.0, max: 2.0 * spec.move_delay as f32 / 3.0, mode: spec.move_delay as f32 / 3.0 }),
|
||||
Collidable,
|
||||
DespawnRandomly(RANDOM_DESPAWN_INV_RATE),
|
||||
Energy { regeneration_rate: 1.0, current: 0.0, burst: 0.0 }
|
||||
));
|
||||
} else {
|
||||
buffer.spawn((
|
||||
Render(spec.symbol),
|
||||
Health(spec.initial_health, spec.initial_health),
|
||||
Enemy,
|
||||
Attack { damage: StochasticNumber::triangle_from_min_range(spec.min_damage, spec.damage_range), energy: spec.attack_cooldown as f32 },
|
||||
Position(newpos),
|
||||
MoveCost(StochasticNumber::Triangle { min: 0.0, max: 2.0 * spec.move_delay as f32 / 3.0, mode: spec.move_delay as f32 / 3.0 }),
|
||||
Collidable,
|
||||
DespawnRandomly(RANDOM_DESPAWN_INV_RATE),
|
||||
Energy { regeneration_rate: 1.0, current: 0.0, burst: 0.0 }
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process enemy motion and ranged attacks
|
||||
for (entity, (Position(pos), ranged, energy)) in state.world.query::<hecs::With<(&Position, Option<&mut RangedAttack>, Option<&mut Energy>), &Enemy>>().iter() {
|
||||
for direction in DIRECTIONS.iter() {
|
||||
if let Some(target) = positions.get(&(*pos + *direction)) {
|
||||
if let Ok(_) = state.world.get::<&EnemyTarget>(*target) {
|
||||
buffer.insert_one(entity, MovingInto(*pos + *direction));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut closest = None;
|
||||
|
||||
// TODO we maybe need a spatial index for this
|
||||
for (_entity, (target_pos, target)) in state.world.query::<(&Position, &EnemyTarget)>().iter() {
|
||||
let distance = hex_distance(*pos, target_pos.0);
|
||||
if distance < target.aggression_range {
|
||||
match closest {
|
||||
Some((_pos, old_distance)) if old_distance < distance => closest = Some((target_pos.0, distance)),
|
||||
None => closest = Some((target_pos.0, distance)),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((target_pos, _)) = closest {
|
||||
if let Some(ranged_attack) = ranged {
|
||||
// slightly smart behaviour for ranged attacker: try to stay just within range
|
||||
let direction = DIRECTIONS.iter().min_by_key(|dir|
|
||||
(hex_distance(*pos + **dir, target_pos) - (ranged_attack.range as i64 - 1)).abs()).unwrap();
|
||||
buffer.insert_one(entity, MovingInto(*pos + *direction));
|
||||
// do ranged attack if valid
|
||||
let atk_dir = target_pos - *pos;
|
||||
if on_axis(atk_dir) && (energy.is_none() || energy.unwrap().try_consume(ranged_attack.energy)) {
|
||||
let atk_dir = atk_dir.clamp(-CoordVec::one(), CoordVec::one());
|
||||
buffer.spawn((
|
||||
Render('*'),
|
||||
Enemy,
|
||||
Attack { damage: ranged_attack.damage, energy: 0.0 },
|
||||
Velocity(atk_dir),
|
||||
Position(*pos),
|
||||
DespawnOnTick(state.ticks.wrapping_add(ranged_attack.range))
|
||||
));
|
||||
}
|
||||
} else {
|
||||
let direction = DIRECTIONS.iter().min_by_key(|dir| hex_distance(*pos + **dir, target_pos)).unwrap();
|
||||
buffer.insert_one(entity, MovingInto(*pos + *direction));
|
||||
}
|
||||
} else {
|
||||
// wander randomly (ethical)
|
||||
buffer.insert_one(entity, MovingInto(*pos + *fastrand::choice(DIRECTIONS).unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
// Process velocity
|
||||
for (entity, (Position(pos), Velocity(vel))) in state.world.query_mut::<(&Position, &Velocity)>() {
|
||||
buffer.insert_one(entity, MovingInto(*pos + *vel));
|
||||
}
|
||||
|
||||
buffer.run_on(&mut state.world);
|
||||
|
||||
// Process inputs
|
||||
for (_id, client) in state.clients.iter_mut() {
|
||||
let mut next_movement = CoordVec::zero();
|
||||
loop {
|
||||
let recv = client.inputs_rx.try_recv();
|
||||
match recv {
|
||||
Err(e) if e == mpsc::error::TryRecvError::Empty => break,
|
||||
Ok(input) => match input {
|
||||
Input::UpLeft => next_movement = CoordVec::new(0, -1),
|
||||
Input::UpRight => next_movement = CoordVec::new(1, -1),
|
||||
Input::Left => next_movement = CoordVec::new(-1, 0),
|
||||
Input::Right => next_movement = CoordVec::new(1, 0),
|
||||
Input::DownRight => next_movement = CoordVec::new(0, 1),
|
||||
Input::DownLeft => next_movement = CoordVec::new(-1, 1),
|
||||
Input::Dig => {
|
||||
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(e.into())
|
||||
}
|
||||
}
|
||||
let position = state.world.get::<&mut Position>(client.entity)?.0;
|
||||
let target = position + next_movement;
|
||||
if get_base_terrain(target).can_enter() && target != position {
|
||||
state.world.insert_one(client.entity, MovingInto(target)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Process motion and attacks
|
||||
for (entity, (Position(current_pos), MovingInto(target_pos), damage, mut energy, move_cost, despawn_on_impact)) in state.world.query::<(&mut Position, &MovingInto, Option<&mut Attack>, Option<&mut Energy>, Option<&MoveCost>, Option<&DespawnOnImpact>)>().iter() {
|
||||
let mut move_cost = move_cost.map(|x| x.0.sample()).unwrap_or(0.0);
|
||||
if let Some(current_terrain) = terrain_positions.get(current_pos) {
|
||||
move_cost += 1.0;
|
||||
}
|
||||
// TODO will break attacks kind of, desirable? Doubtful.
|
||||
if let Some(target_terrain) = terrain_positions.get(target_pos) {
|
||||
move_cost += 1.0;
|
||||
}
|
||||
|
||||
if get_base_terrain(*target_pos).can_enter() {
|
||||
let entry = match positions.entry(*target_pos) {
|
||||
Entry::Occupied(o) => {
|
||||
let target_entity = *o.get();
|
||||
if let Ok(mut x) = state.world.get::<&mut Health>(target_entity) {
|
||||
match damage {
|
||||
Some(Attack { damage, energy: energy_cost }) => {
|
||||
if consume_energy_if_available(&mut energy, *energy_cost) {
|
||||
x.0 -= damage.sample();
|
||||
}
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
if despawn_on_impact.is_some() {
|
||||
buffer.despawn(entity);
|
||||
}
|
||||
if x.0 <= 0.0 {
|
||||
buffer.despawn(target_entity);
|
||||
Some(Entry::Occupied(o))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None // TODO: on pickup or something
|
||||
}
|
||||
},
|
||||
Entry::Vacant(v) => Some(Entry::Vacant(v))
|
||||
};
|
||||
if let Some(entry) = entry {
|
||||
// TODO: perhaps this should be applied to attacks too?
|
||||
if consume_energy_if_available(&mut energy, move_cost) {
|
||||
*entry.or_insert(entity) = entity;
|
||||
positions.remove(current_pos);
|
||||
*current_pos = *target_pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer.remove_one::<MovingInto>(entity);
|
||||
}
|
||||
|
||||
buffer.run_on(&mut state.world);
|
||||
|
||||
for (_entity, energy) in state.world.query_mut::<&mut Energy>() {
|
||||
energy.current = (energy.current + energy.regeneration_rate).min(energy.burst);
|
||||
}
|
||||
|
||||
// Process transient entities
|
||||
for (entity, tick) in state.world.query_mut::<&DespawnOnTick>() {
|
||||
if state.ticks == tick.0 {
|
||||
buffer.despawn(entity);
|
||||
}
|
||||
}
|
||||
|
||||
for (entity, DespawnRandomly(inv_rate)) in state.world.query_mut::<&DespawnRandomly>() {
|
||||
if fastrand::u64(0..*inv_rate) == 0 {
|
||||
buffer.despawn(entity);
|
||||
}
|
||||
}
|
||||
|
||||
buffer.run_on(&mut state.world);
|
||||
|
||||
// Send views to clients
|
||||
for (_id, client) in state.clients.iter() {
|
||||
client.frames_tx.send(Frame::PlayerCount(state.clients.len())).await?;
|
||||
let mut nearby = vec![];
|
||||
if let Ok(pos) = state.world.get::<&Position>(client.entity) {
|
||||
let pos = pos.0;
|
||||
for q in -VIEW..=VIEW {
|
||||
for r in (-VIEW).max(-q - VIEW)..= VIEW.min(-q+VIEW) {
|
||||
let offset = CoordVec::new(q, r);
|
||||
let pos = pos + offset;
|
||||
if let Some(symbol) = get_base_terrain(pos).symbol() {
|
||||
nearby.push((q, r, symbol, 1.0));
|
||||
} else {
|
||||
if let Some(entity) = positions.get(&pos) {
|
||||
let render = state.world.get::<&Render>(*entity)?;
|
||||
let health = if let Ok(h) = state.world.get::<&Health>(*entity) {
|
||||
h.0 / h.1
|
||||
} else { 1.0 };
|
||||
nearby.push((q, r, render.0, health))
|
||||
} else {
|
||||
let mut rng = rng_from_hash(pos);
|
||||
let bg = if rng.usize(0..10) == 0 { ',' } else { '.' };
|
||||
nearby.push((q, r, bg, rng.f32() * 0.1 + 0.9))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let health = state.world.get::<&Health>(client.entity)?.0;
|
||||
client.frames_tx.send(Frame::Display { nearby, health }).await?;
|
||||
} else {
|
||||
client.frames_tx.send(Frame::Dead).await?;
|
||||
}
|
||||
}
|
||||
|
||||
state.ticks = state.ticks.wrapping_add(1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref IDENTS: Vec<char> = {
|
||||
let mut chars = vec![];
|
||||
for range in [
|
||||
'Α'..='ω',
|
||||
'א'..='ת',
|
||||
'Ⓐ'..='ⓩ',
|
||||
'🨀'..='🨅'
|
||||
] {
|
||||
chars.extend(range);
|
||||
}
|
||||
chars.extend("𝔸𝕒𝔹𝕓ℂ𝕔𝔻𝕕ⅅⅆ𝔼𝕖ⅇ𝔽𝕗𝔾𝕘ℍ𝕙𝕀𝕚ⅈ𝕁𝕛ⅉ𝕂𝕜𝕃𝕝𝕄𝕞ℕ𝕟𝕆𝕠ℙ𝕡ℚ𝕢ℝ𝕣𝕊𝕤𝕋𝕥𝕌𝕦𝕍𝕧𝕎𝕨𝕏𝕩𝕐𝕪ℤ𝕫ℾℽℿℼ⅀𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡🩊".chars());
|
||||
chars
|
||||
};
|
||||
}
|
||||
|
||||
fn random_identifier() -> char {
|
||||
*fastrand::choice(IDENTS.iter()).unwrap()
|
||||
}
|
||||
|
||||
fn add_new_player(state: &mut GameState) -> Result<Entity> {
|
||||
let pos = loop {
|
||||
let pos = Coord::origin() + sample_range(WALL - 10);
|
||||
if get_base_terrain(pos).can_enter() {
|
||||
break pos;
|
||||
}
|
||||
};
|
||||
Ok(state.world.spawn((
|
||||
Position(pos),
|
||||
PlayerCharacter,
|
||||
Render(random_identifier()),
|
||||
Collidable,
|
||||
Attack { damage: StochasticNumber::Triangle { min: 20.0, max: 60.0, mode: 20.0 }, energy: 5.0 },
|
||||
Health(128.0, 128.0),
|
||||
EnemyTarget {
|
||||
spawn_density: 0.01,
|
||||
spawn_range: 3..=10,
|
||||
spawn_rate_inv: 20,
|
||||
aggression_range: 5
|
||||
}
|
||||
)))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let addr = std::env::args().nth(1).unwrap_or_else(|| "0.0.0.0:8080".to_string());
|
||||
|
||||
let state = Arc::new(Mutex::new(GameState {
|
||||
world: World::new(),
|
||||
clients: Slab::new(),
|
||||
ticks: 0
|
||||
}));
|
||||
|
||||
let try_socket = TcpListener::bind(&addr).await;
|
||||
let listener = try_socket.expect("Failed to bind");
|
||||
println!("Listening on: {}", addr);
|
||||
|
||||
let state_ = state.clone();
|
||||
tokio::spawn(async move {
|
||||
let state = state_.clone();
|
||||
let mut interval = tokio::time::interval(Duration::from_millis(56));
|
||||
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||
loop {
|
||||
let mut state = state.lock().await;
|
||||
if let Err(e) = game_tick(&mut state).await {
|
||||
println!("{:?}", e);
|
||||
}
|
||||
interval.tick().await;
|
||||
}
|
||||
});
|
||||
|
||||
let state_ = state.clone();
|
||||
while let Ok((stream, addr)) = listener.accept().await {
|
||||
let state_ = state_.clone();
|
||||
let (frames_tx, frames_rx) = mpsc::channel(10);
|
||||
let (inputs_tx, inputs_rx) = mpsc::channel(10);
|
||||
let (id, entity) = {
|
||||
let mut state = state_.lock().await;
|
||||
let entity = add_new_player(&mut state)?; // TODO
|
||||
let client = Client {
|
||||
inputs_rx,
|
||||
frames_tx,
|
||||
entity
|
||||
};
|
||||
let id = state.clients.insert(client);
|
||||
(id, entity)
|
||||
};
|
||||
|
||||
tokio::spawn(async move {
|
||||
println!("conn result {:?}", handle_connection(stream, addr, frames_rx, inputs_tx).await);
|
||||
let mut state = state_.lock().await;
|
||||
state.clients.remove(id);
|
||||
let _ = state.world.despawn(entity);
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
0
src/util.js
Normal file
0
src/util.js
Normal file
71
static/app.css
Normal file
71
static/app.css
Normal file
@ -0,0 +1,71 @@
|
||||
/* fakecss:/home/osmarks/Programming/ewo3/src/App.esbuild-svelte-fake-css */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html {
|
||||
scrollbar-color: black lightgray;
|
||||
}
|
||||
body {
|
||||
font-family:
|
||||
"Fira Sans",
|
||||
"Noto Sans",
|
||||
"Segoe UI",
|
||||
Verdana,
|
||||
sans-serif;
|
||||
font-weight: 300;
|
||||
overflow-anchor: none;
|
||||
}
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
h1 {
|
||||
border-bottom: 1px solid gray;
|
||||
margin: 0;
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
h2 {
|
||||
border-bottom: 1px solid gray;
|
||||
margin: 0;
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
h3 {
|
||||
border-bottom: 1px solid gray;
|
||||
margin: 0;
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
h4 {
|
||||
border-bottom: 1px solid gray;
|
||||
margin: 0;
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
h5 {
|
||||
border-bottom: 1px solid gray;
|
||||
margin: 0;
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
h6 {
|
||||
border-bottom: 1px solid gray;
|
||||
margin: 0;
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
ul {
|
||||
list-style-type: square;
|
||||
padding: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
.game-display.svelte-oncm9j .row.svelte-oncm9j {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.game-display.svelte-oncm9j .row .cell.svelte-oncm9j {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.wrapper.svelte-oncm9j.svelte-oncm9j {
|
||||
display: flex;
|
||||
}
|
802
static/app.js
Normal file
802
static/app.js
Normal file
@ -0,0 +1,802 @@
|
||||
(() => {
|
||||
// node_modules/svelte/internal/index.mjs
|
||||
function noop() {
|
||||
}
|
||||
function run(fn) {
|
||||
return fn();
|
||||
}
|
||||
function blank_object() {
|
||||
return Object.create(null);
|
||||
}
|
||||
function run_all(fns) {
|
||||
fns.forEach(run);
|
||||
}
|
||||
function is_function(thing) {
|
||||
return typeof thing === "function";
|
||||
}
|
||||
function safe_not_equal(a, b) {
|
||||
return a != a ? b == b : a !== b || (a && typeof a === "object" || typeof a === "function");
|
||||
}
|
||||
function is_empty(obj) {
|
||||
return Object.keys(obj).length === 0;
|
||||
}
|
||||
var tasks = new Set();
|
||||
var is_hydrating = false;
|
||||
function start_hydrating() {
|
||||
is_hydrating = true;
|
||||
}
|
||||
function end_hydrating() {
|
||||
is_hydrating = false;
|
||||
}
|
||||
function upper_bound(low, high, key, value) {
|
||||
while (low < high) {
|
||||
const mid = low + (high - low >> 1);
|
||||
if (key(mid) <= value) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid;
|
||||
}
|
||||
}
|
||||
return low;
|
||||
}
|
||||
function init_hydrate(target) {
|
||||
if (target.hydrate_init)
|
||||
return;
|
||||
target.hydrate_init = true;
|
||||
const children2 = target.childNodes;
|
||||
const m = new Int32Array(children2.length + 1);
|
||||
const p = new Int32Array(children2.length);
|
||||
m[0] = -1;
|
||||
let longest = 0;
|
||||
for (let i = 0; i < children2.length; i++) {
|
||||
const current = children2[i].claim_order;
|
||||
const seqLen = upper_bound(1, longest + 1, (idx) => children2[m[idx]].claim_order, current) - 1;
|
||||
p[i] = m[seqLen] + 1;
|
||||
const newLen = seqLen + 1;
|
||||
m[newLen] = i;
|
||||
longest = Math.max(newLen, longest);
|
||||
}
|
||||
const lis = [];
|
||||
const toMove = [];
|
||||
let last = children2.length - 1;
|
||||
for (let cur = m[longest] + 1; cur != 0; cur = p[cur - 1]) {
|
||||
lis.push(children2[cur - 1]);
|
||||
for (; last >= cur; last--) {
|
||||
toMove.push(children2[last]);
|
||||
}
|
||||
last--;
|
||||
}
|
||||
for (; last >= 0; last--) {
|
||||
toMove.push(children2[last]);
|
||||
}
|
||||
lis.reverse();
|
||||
toMove.sort((a, b) => a.claim_order - b.claim_order);
|
||||
for (let i = 0, j = 0; i < toMove.length; i++) {
|
||||
while (j < lis.length && toMove[i].claim_order >= lis[j].claim_order) {
|
||||
j++;
|
||||
}
|
||||
const anchor = j < lis.length ? lis[j] : null;
|
||||
target.insertBefore(toMove[i], anchor);
|
||||
}
|
||||
}
|
||||
function append(target, node) {
|
||||
if (is_hydrating) {
|
||||
init_hydrate(target);
|
||||
if (target.actual_end_child === void 0 || target.actual_end_child !== null && target.actual_end_child.parentElement !== target) {
|
||||
target.actual_end_child = target.firstChild;
|
||||
}
|
||||
if (node !== target.actual_end_child) {
|
||||
target.insertBefore(node, target.actual_end_child);
|
||||
} else {
|
||||
target.actual_end_child = node.nextSibling;
|
||||
}
|
||||
} else if (node.parentNode !== target) {
|
||||
target.appendChild(node);
|
||||
}
|
||||
}
|
||||
function insert(target, node, anchor) {
|
||||
if (is_hydrating && !anchor) {
|
||||
append(target, node);
|
||||
} else if (node.parentNode !== target || anchor && node.nextSibling !== anchor) {
|
||||
target.insertBefore(node, anchor || null);
|
||||
}
|
||||
}
|
||||
function detach(node) {
|
||||
node.parentNode.removeChild(node);
|
||||
}
|
||||
function destroy_each(iterations, detaching) {
|
||||
for (let i = 0; i < iterations.length; i += 1) {
|
||||
if (iterations[i])
|
||||
iterations[i].d(detaching);
|
||||
}
|
||||
}
|
||||
function element(name) {
|
||||
return document.createElement(name);
|
||||
}
|
||||
function text(data) {
|
||||
return document.createTextNode(data);
|
||||
}
|
||||
function space() {
|
||||
return text(" ");
|
||||
}
|
||||
function listen(node, event, handler, options) {
|
||||
node.addEventListener(event, handler, options);
|
||||
return () => node.removeEventListener(event, handler, options);
|
||||
}
|
||||
function attr(node, attribute, value) {
|
||||
if (value == null)
|
||||
node.removeAttribute(attribute);
|
||||
else if (node.getAttribute(attribute) !== value)
|
||||
node.setAttribute(attribute, value);
|
||||
}
|
||||
function children(element2) {
|
||||
return Array.from(element2.childNodes);
|
||||
}
|
||||
function set_data(text2, data) {
|
||||
data = "" + data;
|
||||
if (text2.wholeText !== data)
|
||||
text2.data = data;
|
||||
}
|
||||
var active_docs = new Set();
|
||||
var current_component;
|
||||
function set_current_component(component) {
|
||||
current_component = component;
|
||||
}
|
||||
var dirty_components = [];
|
||||
var binding_callbacks = [];
|
||||
var render_callbacks = [];
|
||||
var flush_callbacks = [];
|
||||
var resolved_promise = Promise.resolve();
|
||||
var update_scheduled = false;
|
||||
function schedule_update() {
|
||||
if (!update_scheduled) {
|
||||
update_scheduled = true;
|
||||
resolved_promise.then(flush);
|
||||
}
|
||||
}
|
||||
function add_render_callback(fn) {
|
||||
render_callbacks.push(fn);
|
||||
}
|
||||
var flushing = false;
|
||||
var seen_callbacks = new Set();
|
||||
function flush() {
|
||||
if (flushing)
|
||||
return;
|
||||
flushing = true;
|
||||
do {
|
||||
for (let i = 0; i < dirty_components.length; i += 1) {
|
||||
const component = dirty_components[i];
|
||||
set_current_component(component);
|
||||
update(component.$$);
|
||||
}
|
||||
set_current_component(null);
|
||||
dirty_components.length = 0;
|
||||
while (binding_callbacks.length)
|
||||
binding_callbacks.pop()();
|
||||
for (let i = 0; i < render_callbacks.length; i += 1) {
|
||||
const callback = render_callbacks[i];
|
||||
if (!seen_callbacks.has(callback)) {
|
||||
seen_callbacks.add(callback);
|
||||
callback();
|
||||
}
|
||||
}
|
||||
render_callbacks.length = 0;
|
||||
} while (dirty_components.length);
|
||||
while (flush_callbacks.length) {
|
||||
flush_callbacks.pop()();
|
||||
}
|
||||
update_scheduled = false;
|
||||
flushing = false;
|
||||
seen_callbacks.clear();
|
||||
}
|
||||
function update($$) {
|
||||
if ($$.fragment !== null) {
|
||||
$$.update();
|
||||
run_all($$.before_update);
|
||||
const dirty = $$.dirty;
|
||||
$$.dirty = [-1];
|
||||
$$.fragment && $$.fragment.p($$.ctx, dirty);
|
||||
$$.after_update.forEach(add_render_callback);
|
||||
}
|
||||
}
|
||||
var outroing = new Set();
|
||||
function transition_in(block, local) {
|
||||
if (block && block.i) {
|
||||
outroing.delete(block);
|
||||
block.i(local);
|
||||
}
|
||||
}
|
||||
var globals = typeof window !== "undefined" ? window : typeof globalThis !== "undefined" ? globalThis : global;
|
||||
var boolean_attributes = new Set([
|
||||
"allowfullscreen",
|
||||
"allowpaymentrequest",
|
||||
"async",
|
||||
"autofocus",
|
||||
"autoplay",
|
||||
"checked",
|
||||
"controls",
|
||||
"default",
|
||||
"defer",
|
||||
"disabled",
|
||||
"formnovalidate",
|
||||
"hidden",
|
||||
"ismap",
|
||||
"loop",
|
||||
"multiple",
|
||||
"muted",
|
||||
"nomodule",
|
||||
"novalidate",
|
||||
"open",
|
||||
"playsinline",
|
||||
"readonly",
|
||||
"required",
|
||||
"reversed",
|
||||
"selected"
|
||||
]);
|
||||
function mount_component(component, target, anchor, customElement) {
|
||||
const { fragment, on_mount, on_destroy, after_update } = component.$$;
|
||||
fragment && fragment.m(target, anchor);
|
||||
if (!customElement) {
|
||||
add_render_callback(() => {
|
||||
const new_on_destroy = on_mount.map(run).filter(is_function);
|
||||
if (on_destroy) {
|
||||
on_destroy.push(...new_on_destroy);
|
||||
} else {
|
||||
run_all(new_on_destroy);
|
||||
}
|
||||
component.$$.on_mount = [];
|
||||
});
|
||||
}
|
||||
after_update.forEach(add_render_callback);
|
||||
}
|
||||
function destroy_component(component, detaching) {
|
||||
const $$ = component.$$;
|
||||
if ($$.fragment !== null) {
|
||||
run_all($$.on_destroy);
|
||||
$$.fragment && $$.fragment.d(detaching);
|
||||
$$.on_destroy = $$.fragment = null;
|
||||
$$.ctx = [];
|
||||
}
|
||||
}
|
||||
function make_dirty(component, i) {
|
||||
if (component.$$.dirty[0] === -1) {
|
||||
dirty_components.push(component);
|
||||
schedule_update();
|
||||
component.$$.dirty.fill(0);
|
||||
}
|
||||
component.$$.dirty[i / 31 | 0] |= 1 << i % 31;
|
||||
}
|
||||
function init(component, options, instance2, create_fragment2, not_equal, props, dirty = [-1]) {
|
||||
const parent_component = current_component;
|
||||
set_current_component(component);
|
||||
const $$ = component.$$ = {
|
||||
fragment: null,
|
||||
ctx: null,
|
||||
props,
|
||||
update: noop,
|
||||
not_equal,
|
||||
bound: blank_object(),
|
||||
on_mount: [],
|
||||
on_destroy: [],
|
||||
on_disconnect: [],
|
||||
before_update: [],
|
||||
after_update: [],
|
||||
context: new Map(parent_component ? parent_component.$$.context : options.context || []),
|
||||
callbacks: blank_object(),
|
||||
dirty,
|
||||
skip_bound: false
|
||||
};
|
||||
let ready = false;
|
||||
$$.ctx = instance2 ? instance2(component, options.props || {}, (i, ret, ...rest) => {
|
||||
const value = rest.length ? rest[0] : ret;
|
||||
if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
|
||||
if (!$$.skip_bound && $$.bound[i])
|
||||
$$.bound[i](value);
|
||||
if (ready)
|
||||
make_dirty(component, i);
|
||||
}
|
||||
return ret;
|
||||
}) : [];
|
||||
$$.update();
|
||||
ready = true;
|
||||
run_all($$.before_update);
|
||||
$$.fragment = create_fragment2 ? create_fragment2($$.ctx) : false;
|
||||
if (options.target) {
|
||||
if (options.hydrate) {
|
||||
start_hydrating();
|
||||
const nodes = children(options.target);
|
||||
$$.fragment && $$.fragment.l(nodes);
|
||||
nodes.forEach(detach);
|
||||
} else {
|
||||
$$.fragment && $$.fragment.c();
|
||||
}
|
||||
if (options.intro)
|
||||
transition_in(component.$$.fragment);
|
||||
mount_component(component, options.target, options.anchor, options.customElement);
|
||||
end_hydrating();
|
||||
flush();
|
||||
}
|
||||
set_current_component(parent_component);
|
||||
}
|
||||
var SvelteElement;
|
||||
if (typeof HTMLElement === "function") {
|
||||
SvelteElement = class extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: "open" });
|
||||
}
|
||||
connectedCallback() {
|
||||
const { on_mount } = this.$$;
|
||||
this.$$.on_disconnect = on_mount.map(run).filter(is_function);
|
||||
for (const key in this.$$.slotted) {
|
||||
this.appendChild(this.$$.slotted[key]);
|
||||
}
|
||||
}
|
||||
attributeChangedCallback(attr2, _oldValue, newValue) {
|
||||
this[attr2] = newValue;
|
||||
}
|
||||
disconnectedCallback() {
|
||||
run_all(this.$$.on_disconnect);
|
||||
}
|
||||
$destroy() {
|
||||
destroy_component(this, 1);
|
||||
this.$destroy = noop;
|
||||
}
|
||||
$on(type, callback) {
|
||||
const callbacks = this.$$.callbacks[type] || (this.$$.callbacks[type] = []);
|
||||
callbacks.push(callback);
|
||||
return () => {
|
||||
const index = callbacks.indexOf(callback);
|
||||
if (index !== -1)
|
||||
callbacks.splice(index, 1);
|
||||
};
|
||||
}
|
||||
$set($$props) {
|
||||
if (this.$$set && !is_empty($$props)) {
|
||||
this.$$.skip_bound = true;
|
||||
this.$$set($$props);
|
||||
this.$$.skip_bound = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
var SvelteComponent = class {
|
||||
$destroy() {
|
||||
destroy_component(this, 1);
|
||||
this.$destroy = noop;
|
||||
}
|
||||
$on(type, callback) {
|
||||
const callbacks = this.$$.callbacks[type] || (this.$$.callbacks[type] = []);
|
||||
callbacks.push(callback);
|
||||
return () => {
|
||||
const index = callbacks.indexOf(callback);
|
||||
if (index !== -1)
|
||||
callbacks.splice(index, 1);
|
||||
};
|
||||
}
|
||||
$set($$props) {
|
||||
if (this.$$set && !is_empty($$props)) {
|
||||
this.$$.skip_bound = true;
|
||||
this.$$set($$props);
|
||||
this.$$.skip_bound = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// src/App.svelte
|
||||
var { window: window_1 } = globals;
|
||||
function get_each_context(ctx, list, i) {
|
||||
const child_ctx = ctx.slice();
|
||||
child_ctx[17] = list[i];
|
||||
child_ctx[19] = i;
|
||||
return child_ctx;
|
||||
}
|
||||
function get_each_context_1(ctx, list, i) {
|
||||
const child_ctx = ctx.slice();
|
||||
child_ctx[20] = list[i];
|
||||
return child_ctx;
|
||||
}
|
||||
function create_each_block_1(ctx) {
|
||||
let div;
|
||||
let t_value = ctx[20][0] + "";
|
||||
let t;
|
||||
let div_style_value;
|
||||
return {
|
||||
c() {
|
||||
div = element("div");
|
||||
t = text(t_value);
|
||||
attr(div, "class", "cell svelte-oncm9j");
|
||||
attr(div, "style", div_style_value = `width: ${ctx[5]}px; height: ${ctx[6]}px; line-height: ${ctx[6]}px; opacity: ${ctx[20][1] * 100}%`);
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, div, anchor);
|
||||
append(div, t);
|
||||
},
|
||||
p(ctx2, dirty) {
|
||||
if (dirty & 8 && t_value !== (t_value = ctx2[20][0] + ""))
|
||||
set_data(t, t_value);
|
||||
if (dirty & 8 && div_style_value !== (div_style_value = `width: ${ctx2[5]}px; height: ${ctx2[6]}px; line-height: ${ctx2[6]}px; opacity: ${ctx2[20][1] * 100}%`)) {
|
||||
attr(div, "style", div_style_value);
|
||||
}
|
||||
},
|
||||
d(detaching) {
|
||||
if (detaching)
|
||||
detach(div);
|
||||
}
|
||||
};
|
||||
}
|
||||
function create_each_block(ctx) {
|
||||
let div;
|
||||
let t;
|
||||
let div_style_value;
|
||||
let each_value_1 = ctx[17];
|
||||
let each_blocks = [];
|
||||
for (let i = 0; i < each_value_1.length; i += 1) {
|
||||
each_blocks[i] = create_each_block_1(get_each_context_1(ctx, each_value_1, i));
|
||||
}
|
||||
return {
|
||||
c() {
|
||||
div = element("div");
|
||||
for (let i = 0; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].c();
|
||||
}
|
||||
t = space();
|
||||
attr(div, "class", "row svelte-oncm9j");
|
||||
attr(div, "style", div_style_value = `height: ${ctx[6]}px; ` + (ctx[19] % 2 === 1 ? `padding-left: ${ctx[5] / 2}px` : ""));
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, div, anchor);
|
||||
for (let i = 0; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].m(div, null);
|
||||
}
|
||||
append(div, t);
|
||||
},
|
||||
p(ctx2, dirty) {
|
||||
if (dirty & 104) {
|
||||
each_value_1 = ctx2[17];
|
||||
let i;
|
||||
for (i = 0; i < each_value_1.length; i += 1) {
|
||||
const child_ctx = get_each_context_1(ctx2, each_value_1, i);
|
||||
if (each_blocks[i]) {
|
||||
each_blocks[i].p(child_ctx, dirty);
|
||||
} else {
|
||||
each_blocks[i] = create_each_block_1(child_ctx);
|
||||
each_blocks[i].c();
|
||||
each_blocks[i].m(div, t);
|
||||
}
|
||||
}
|
||||
for (; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].d(1);
|
||||
}
|
||||
each_blocks.length = each_value_1.length;
|
||||
}
|
||||
},
|
||||
d(detaching) {
|
||||
if (detaching)
|
||||
detach(div);
|
||||
destroy_each(each_blocks, detaching);
|
||||
}
|
||||
};
|
||||
}
|
||||
function create_if_block_2(ctx) {
|
||||
let t0;
|
||||
let a;
|
||||
let t2;
|
||||
let mounted;
|
||||
let dispose;
|
||||
return {
|
||||
c() {
|
||||
t0 = text("You have died to death. ");
|
||||
a = element("a");
|
||||
a.textContent = "Restart";
|
||||
t2 = text(".");
|
||||
attr(a, "href", "#");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, t0, anchor);
|
||||
insert(target, a, anchor);
|
||||
insert(target, t2, anchor);
|
||||
if (!mounted) {
|
||||
dispose = listen(a, "click", ctx[4]);
|
||||
mounted = true;
|
||||
}
|
||||
},
|
||||
p: noop,
|
||||
d(detaching) {
|
||||
if (detaching)
|
||||
detach(t0);
|
||||
if (detaching)
|
||||
detach(a);
|
||||
if (detaching)
|
||||
detach(t2);
|
||||
mounted = false;
|
||||
dispose();
|
||||
}
|
||||
};
|
||||
}
|
||||
function create_if_block_1(ctx) {
|
||||
let t0;
|
||||
let t1;
|
||||
return {
|
||||
c() {
|
||||
t0 = text(ctx[2]);
|
||||
t1 = text(" connected players.");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, t0, anchor);
|
||||
insert(target, t1, anchor);
|
||||
},
|
||||
p(ctx2, dirty) {
|
||||
if (dirty & 4)
|
||||
set_data(t0, ctx2[2]);
|
||||
},
|
||||
d(detaching) {
|
||||
if (detaching)
|
||||
detach(t0);
|
||||
if (detaching)
|
||||
detach(t1);
|
||||
}
|
||||
};
|
||||
}
|
||||
function create_if_block(ctx) {
|
||||
let t0;
|
||||
let t1;
|
||||
let t2;
|
||||
return {
|
||||
c() {
|
||||
t0 = text("Your health is ");
|
||||
t1 = text(ctx[1]);
|
||||
t2 = text(".");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, t0, anchor);
|
||||
insert(target, t1, anchor);
|
||||
insert(target, t2, anchor);
|
||||
},
|
||||
p(ctx2, dirty) {
|
||||
if (dirty & 2)
|
||||
set_data(t1, ctx2[1]);
|
||||
},
|
||||
d(detaching) {
|
||||
if (detaching)
|
||||
detach(t0);
|
||||
if (detaching)
|
||||
detach(t1);
|
||||
if (detaching)
|
||||
detach(t2);
|
||||
}
|
||||
};
|
||||
}
|
||||
function create_fragment(ctx) {
|
||||
let h1;
|
||||
let t1;
|
||||
let div2;
|
||||
let div0;
|
||||
let t2;
|
||||
let div1;
|
||||
let t3;
|
||||
let t4;
|
||||
let mounted;
|
||||
let dispose;
|
||||
let each_value = ctx[3];
|
||||
let each_blocks = [];
|
||||
for (let i = 0; i < each_value.length; i += 1) {
|
||||
each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i));
|
||||
}
|
||||
let if_block0 = ctx[0] && create_if_block_2(ctx);
|
||||
let if_block1 = ctx[2] && create_if_block_1(ctx);
|
||||
let if_block2 = ctx[1] && create_if_block(ctx);
|
||||
return {
|
||||
c() {
|
||||
h1 = element("h1");
|
||||
h1.textContent = "EWO3 Memetic Edition";
|
||||
t1 = space();
|
||||
div2 = element("div");
|
||||
div0 = element("div");
|
||||
for (let i = 0; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].c();
|
||||
}
|
||||
t2 = space();
|
||||
div1 = element("div");
|
||||
if (if_block0)
|
||||
if_block0.c();
|
||||
t3 = space();
|
||||
if (if_block1)
|
||||
if_block1.c();
|
||||
t4 = space();
|
||||
if (if_block2)
|
||||
if_block2.c();
|
||||
attr(div0, "class", "game-display svelte-oncm9j");
|
||||
attr(div1, "class", "controls");
|
||||
attr(div2, "class", "wrapper svelte-oncm9j");
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, h1, anchor);
|
||||
insert(target, t1, anchor);
|
||||
insert(target, div2, anchor);
|
||||
append(div2, div0);
|
||||
for (let i = 0; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].m(div0, null);
|
||||
}
|
||||
append(div2, t2);
|
||||
append(div2, div1);
|
||||
if (if_block0)
|
||||
if_block0.m(div1, null);
|
||||
append(div1, t3);
|
||||
if (if_block1)
|
||||
if_block1.m(div1, null);
|
||||
append(div1, t4);
|
||||
if (if_block2)
|
||||
if_block2.m(div1, null);
|
||||
if (!mounted) {
|
||||
dispose = [
|
||||
listen(window_1, "keydown", ctx[7]),
|
||||
listen(window_1, "keyup", ctx[8])
|
||||
];
|
||||
mounted = true;
|
||||
}
|
||||
},
|
||||
p(ctx2, [dirty]) {
|
||||
if (dirty & 104) {
|
||||
each_value = ctx2[3];
|
||||
let i;
|
||||
for (i = 0; i < each_value.length; i += 1) {
|
||||
const child_ctx = get_each_context(ctx2, each_value, i);
|
||||
if (each_blocks[i]) {
|
||||
each_blocks[i].p(child_ctx, dirty);
|
||||
} else {
|
||||
each_blocks[i] = create_each_block(child_ctx);
|
||||
each_blocks[i].c();
|
||||
each_blocks[i].m(div0, null);
|
||||
}
|
||||
}
|
||||
for (; i < each_blocks.length; i += 1) {
|
||||
each_blocks[i].d(1);
|
||||
}
|
||||
each_blocks.length = each_value.length;
|
||||
}
|
||||
if (ctx2[0]) {
|
||||
if (if_block0) {
|
||||
if_block0.p(ctx2, dirty);
|
||||
} else {
|
||||
if_block0 = create_if_block_2(ctx2);
|
||||
if_block0.c();
|
||||
if_block0.m(div1, t3);
|
||||
}
|
||||
} else if (if_block0) {
|
||||
if_block0.d(1);
|
||||
if_block0 = null;
|
||||
}
|
||||
if (ctx2[2]) {
|
||||
if (if_block1) {
|
||||
if_block1.p(ctx2, dirty);
|
||||
} else {
|
||||
if_block1 = create_if_block_1(ctx2);
|
||||
if_block1.c();
|
||||
if_block1.m(div1, t4);
|
||||
}
|
||||
} else if (if_block1) {
|
||||
if_block1.d(1);
|
||||
if_block1 = null;
|
||||
}
|
||||
if (ctx2[1]) {
|
||||
if (if_block2) {
|
||||
if_block2.p(ctx2, dirty);
|
||||
} else {
|
||||
if_block2 = create_if_block(ctx2);
|
||||
if_block2.c();
|
||||
if_block2.m(div1, null);
|
||||
}
|
||||
} else if (if_block2) {
|
||||
if_block2.d(1);
|
||||
if_block2 = null;
|
||||
}
|
||||
},
|
||||
i: noop,
|
||||
o: noop,
|
||||
d(detaching) {
|
||||
if (detaching)
|
||||
detach(h1);
|
||||
if (detaching)
|
||||
detach(t1);
|
||||
if (detaching)
|
||||
detach(div2);
|
||||
destroy_each(each_blocks, detaching);
|
||||
if (if_block0)
|
||||
if_block0.d();
|
||||
if (if_block1)
|
||||
if_block1.d();
|
||||
if (if_block2)
|
||||
if_block2.d();
|
||||
mounted = false;
|
||||
run_all(dispose);
|
||||
}
|
||||
};
|
||||
}
|
||||
var GRIDSIZE = 33;
|
||||
var SIZE = 16;
|
||||
function instance($$self, $$props, $$invalidate) {
|
||||
let dead = false;
|
||||
let health;
|
||||
let players;
|
||||
let ws;
|
||||
const connect = () => {
|
||||
ws = new WebSocket(window.location.protocol === "https:" ? "wss://ewo.osmarks.net/" : "ws://localhost:8080/");
|
||||
ws.addEventListener("message", (ev) => {
|
||||
const data = JSON.parse(ev.data);
|
||||
if (data.Display) {
|
||||
const newGrid = blankGrid();
|
||||
for (const [q, r, c, o] of data.Display.nearby) {
|
||||
const col = q + (r - (r & 1)) / 2;
|
||||
const row = r;
|
||||
newGrid[row + OFFSET][col + OFFSET] = [c, o];
|
||||
}
|
||||
$$invalidate(3, grid = newGrid);
|
||||
$$invalidate(1, health = data.Display.health);
|
||||
}
|
||||
if (data === "Dead") {
|
||||
$$invalidate(0, dead = true);
|
||||
}
|
||||
if (data.PlayerCount) {
|
||||
$$invalidate(2, players = data.PlayerCount);
|
||||
}
|
||||
for (const key of keysDown) {
|
||||
const input = INPUTS[key];
|
||||
if (input) {
|
||||
ws.send(JSON.stringify(input));
|
||||
}
|
||||
}
|
||||
keysDown = new Set(Array.from(keysDown).map((k) => !keysCleared.has(k)));
|
||||
keysCleared = new Set();
|
||||
});
|
||||
ws.addEventListener("close", (ev) => {
|
||||
console.warn("oh no");
|
||||
});
|
||||
};
|
||||
const reconnect = () => {
|
||||
if (ws)
|
||||
ws.close();
|
||||
connect();
|
||||
};
|
||||
const restart = (ev) => {
|
||||
ev.preventDefault();
|
||||
$$invalidate(0, dead = false);
|
||||
reconnect();
|
||||
};
|
||||
const OFFSET = Math.floor(GRIDSIZE / 2);
|
||||
const HORIZ = Math.sqrt(3) * SIZE;
|
||||
const VERT = 3 / 2 * SIZE;
|
||||
const blankGrid = () => new Array(GRIDSIZE).fill(null).map(() => new Array(GRIDSIZE).fill("\u200B"));
|
||||
let grid = blankGrid();
|
||||
let keysDown = new Set();
|
||||
let keysCleared = new Set();
|
||||
const keydown = (ev) => {
|
||||
keysDown.add(ev.key);
|
||||
};
|
||||
const keyup = (ev) => {
|
||||
keysCleared.add(ev.key);
|
||||
};
|
||||
const INPUTS = {
|
||||
"w": "UpLeft",
|
||||
"e": "UpRight",
|
||||
"a": "Left",
|
||||
"d": "Right",
|
||||
"z": "DownLeft",
|
||||
"x": "DownRight"
|
||||
};
|
||||
connect();
|
||||
return [dead, health, players, grid, restart, HORIZ, VERT, keydown, keyup];
|
||||
}
|
||||
var App = class extends SvelteComponent {
|
||||
constructor(options) {
|
||||
super();
|
||||
init(this, options, instance, create_fragment, safe_not_equal, {});
|
||||
}
|
||||
};
|
||||
var App_default = App;
|
||||
|
||||
// src/app.js
|
||||
new App_default({
|
||||
target: document.body
|
||||
});
|
||||
})();
|
15
static/index.html
Normal file
15
static/index.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="en" height="100vh">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
|
||||
<meta name="description" content="Emu War Online">
|
||||
|
||||
<title>EWO3</title>
|
||||
</style>
|
||||
<link rel="stylesheet" href="app.css">
|
||||
</head>
|
||||
<body>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user