summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock174
-rw-r--r--client/game.gd60
-rw-r--r--client/map/tiles/floor.gd5
-rw-r--r--client/menu/blur_setup.gd1
-rw-r--r--client/menu/character.gd12
-rw-r--r--client/menu/communicate/popup_message/popup_message.gd117
-rw-r--r--client/menu/communicate/popup_message/popup_message.tscn86
-rw-r--r--client/menu/communicate/popup_message/server_message.gd13
-rw-r--r--client/menu/communicate/popup_message/server_message.tscn6
-rw-r--r--client/menu/hairstyle_preview.gd2
-rw-r--r--client/menu/ingame.gd39
-rw-r--r--client/menu/lobby.gd42
-rw-r--r--client/menu/menu_background.gd32
-rw-r--r--client/menu/play.gd1
-rw-r--r--client/player/character/character.gd106
-rw-r--r--client/player/character/character.tscn8
-rw-r--r--client/player/controllable_player.gd13
-rw-r--r--client/player/player.gd2
-rw-r--r--data/index.yaml2
-rw-r--r--data/maps/salad.yaml81
-rw-r--r--locale/en.ini3
-rw-r--r--locale/tools/Cargo.toml6
-rw-r--r--pixel-client/Cargo.toml12
-rw-r--r--pixel-client/tools/Cargo.toml4
-rw-r--r--protocol.md3
-rw-r--r--server/Cargo.toml14
-rw-r--r--server/bot/Cargo.toml6
-rw-r--r--server/bot/src/algos/simple.rs3
-rw-r--r--server/client-lib/Cargo.toml10
-rw-r--r--server/discover/src/main.rs8
-rw-r--r--server/protocol/Cargo.toml4
-rw-r--r--server/registry/Cargo.toml8
-rw-r--r--server/registry/src/list.rs24
-rw-r--r--server/registry/src/main.rs6
-rw-r--r--server/replaytool/Cargo.toml14
-rw-r--r--server/src/commands.rs2
-rw-r--r--server/src/entity/customers.rs2
-rw-r--r--server/src/entity/tutorial.rs24
-rw-r--r--server/src/network/register.rs2
39 files changed, 574 insertions, 383 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b8b6fff8..40952269 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "addr2line"
-version = "0.22.0"
+version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
+checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
dependencies = [
"gimli",
]
@@ -18,6 +18,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -221,9 +227,9 @@ dependencies = [
[[package]]
name = "aws-lc-rs"
-version = "1.8.1"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ae74d9bd0a7530e8afd1770739ad34b36838829d6ad61818f9230f683f5ad77"
+checksum = "2f95446d919226d587817a7d21379e6eb099b97b45110a7f272a444ca5c54070"
dependencies = [
"aws-lc-sys",
"mirai-annotations",
@@ -233,9 +239,9 @@ dependencies = [
[[package]]
name = "aws-lc-sys"
-version = "0.20.1"
+version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f0e249228c6ad2d240c2dc94b714d711629d52bad946075d8e9b2f5391f0703"
+checksum = "b3ddc4a5b231dd6958b140ff3151b6412b3f4321fab354f399eec8f14b06df62"
dependencies = [
"bindgen",
"cc",
@@ -248,17 +254,17 @@ dependencies = [
[[package]]
name = "backtrace"
-version = "0.3.73"
+version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
+checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [
"addr2line",
- "cc",
"cfg-if",
"libc",
- "miniz_oxide",
+ "miniz_oxide 0.8.0",
"object",
"rustc-demangle",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -380,9 +386,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
name = "bytes"
-version = "1.7.1"
+version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
+checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
[[package]]
name = "c_linked_list"
@@ -398,12 +404,13 @@ checksum = "fdd7a427adc0135366d99db65b36dae9237130997e560ed61118041fb72be6e8"
[[package]]
name = "cc"
-version = "1.1.8"
+version = "1.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549"
+checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
dependencies = [
"jobserver",
"libc",
+ "shlex",
]
[[package]]
@@ -444,9 +451,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.16"
+version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
+checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
dependencies = [
"clap_builder",
"clap_derive",
@@ -454,9 +461,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.15"
+version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
+checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
dependencies = [
"anstream",
"anstyle",
@@ -466,9 +473,9 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.5.13"
+version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck",
"proc-macro2",
@@ -484,9 +491,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "cmake"
-version = "0.1.50"
+version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130"
+checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a"
dependencies = [
"cc",
]
@@ -535,15 +542,15 @@ dependencies = [
[[package]]
name = "core-foundation-sys"
-version = "0.8.6"
+version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "cpufeatures"
-version = "0.2.12"
+version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
+checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
dependencies = [
"libc",
]
@@ -726,7 +733,7 @@ dependencies = [
"flume",
"half",
"lebe",
- "miniz_oxide",
+ "miniz_oxide 0.7.4",
"rayon-core",
"smallvec",
"zune-inflate",
@@ -768,7 +775,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920"
dependencies = [
"crc32fast",
- "miniz_oxide",
+ "miniz_oxide 0.7.4",
]
[[package]]
@@ -966,15 +973,15 @@ dependencies = [
[[package]]
name = "gimli"
-version = "0.29.0"
+version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
+checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
[[package]]
name = "glam"
-version = "0.28.0"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94"
+checksum = "c28091a37a5d09b555cb6628fd954da299b536433834f5b8e59eba78e0cbbf8a"
dependencies = [
"serde",
]
@@ -1421,9 +1428,9 @@ checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126"
[[package]]
name = "indexmap"
-version = "2.3.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0"
+checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
dependencies = [
"equivalent",
"hashbrown",
@@ -1529,9 +1536,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]]
name = "libc"
-version = "0.2.155"
+version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "libfuzzer-sys"
@@ -1556,9 +1563,13 @@ dependencies = [
[[package]]
name = "libyml"
-version = "0.0.4"
+version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64804cc6a5042d4f05379909ba25b503ec04e2c082151d62122d5dcaa274b961"
+checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980"
+dependencies = [
+ "anyhow",
+ "version_check",
+]
[[package]]
name = "linux-raw-sys"
@@ -1695,10 +1706,19 @@ dependencies = [
]
[[package]]
+name = "miniz_oxide"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
name = "mio"
-version = "1.0.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
+checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
dependencies = [
"hermit-abi 0.3.9",
"libc",
@@ -1831,9 +1851,9 @@ dependencies = [
[[package]]
name = "object"
-version = "0.36.3"
+version = "0.36.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9"
+checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
dependencies = [
"memchr",
]
@@ -1984,7 +2004,7 @@ dependencies = [
"crc32fast",
"fdeflate",
"flate2",
- "miniz_oxide",
+ "miniz_oxide 0.7.4",
]
[[package]]
@@ -2026,9 +2046,9 @@ dependencies = [
[[package]]
name = "prettyplease"
-version = "0.2.20"
+version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e"
+checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
dependencies = [
"proc-macro2",
"syn",
@@ -2140,9 +2160,9 @@ dependencies = [
[[package]]
name = "quote"
-version = "1.0.36"
+version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
@@ -2377,7 +2397,7 @@ dependencies = [
"pin-project-lite",
"quinn",
"rustls",
- "rustls-native-certs 0.7.1",
+ "rustls-native-certs 0.7.2",
"rustls-pemfile",
"rustls-pki-types",
"serde",
@@ -2520,9 +2540,9 @@ checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
[[package]]
name = "rustix"
-version = "0.38.34"
+version = "0.38.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
dependencies = [
"bitflags 2.6.0",
"errno",
@@ -2533,9 +2553,9 @@ dependencies = [
[[package]]
name = "rustls"
-version = "0.23.12"
+version = "0.23.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044"
+checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8"
dependencies = [
"aws-lc-rs",
"log",
@@ -2549,9 +2569,9 @@ dependencies = [
[[package]]
name = "rustls-native-certs"
-version = "0.7.1"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba"
+checksum = "04182dffc9091a404e0fc069ea5cd60e5b866c3adf881eff99a32d048242dffa"
dependencies = [
"openssl-probe",
"rustls-pemfile",
@@ -2591,9 +2611,9 @@ checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
[[package]]
name = "rustls-webpki"
-version = "0.102.6"
+version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e"
+checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [
"aws-lc-rs",
"ring",
@@ -2737,19 +2757,17 @@ dependencies = [
[[package]]
name = "serde_yml"
-version = "0.0.11"
+version = "0.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48e76bab63c3fd98d27c17f9cbce177f64a91f5e69ac04cafe04e1bb25d1dc3c"
+checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd"
dependencies = [
"indexmap",
"itoa",
"libyml",
- "log",
"memchr",
"ryu",
"serde",
- "serde_json",
- "tempfile",
+ "version_check",
]
[[package]]
@@ -2868,9 +2886,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
-version = "2.0.72"
+version = "2.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
+checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
dependencies = [
"proc-macro2",
"quote",
@@ -3058,14 +3076,14 @@ dependencies = [
[[package]]
name = "tokio-tungstenite"
-version = "0.23.1"
+version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd"
+checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9"
dependencies = [
"futures-util",
"log",
"rustls",
- "rustls-native-certs 0.7.1",
+ "rustls-native-certs 0.8.0",
"rustls-pki-types",
"tokio",
"tokio-rustls",
@@ -3227,9 +3245,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "tungstenite"
-version = "0.23.0"
+version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8"
+checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a"
dependencies = [
"byteorder",
"bytes",
@@ -3239,7 +3257,7 @@ dependencies = [
"log",
"rand 0.8.5",
"rustls",
- "rustls-native-certs 0.7.1",
+ "rustls-native-certs 0.7.2",
"rustls-pki-types",
"sha1",
"thiserror",
@@ -3279,9 +3297,9 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]]
name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-normalization"
@@ -3773,20 +3791,6 @@ name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
-dependencies = [
- "zeroize_derive",
-]
-
-[[package]]
-name = "zeroize_derive"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
[[package]]
name = "zstd"
diff --git a/client/game.gd b/client/game.gd
index 76bb271a..fe1e9ba6 100644
--- a/client/game.gd
+++ b/client/game.gd
@@ -21,9 +21,8 @@ extends Node3D
signal update_players(players: Dictionary)
signal data_updated()
signal in_lobby_updated(in_lobby: bool)
+signal join_state_updated(state: JoinState)
signal text_message(player: int, text: String, timeout_initial: float, timeout_remaining: float)
-signal joined()
-signal left()
signal update_tutorial_running(running: bool)
enum SpectatingMode {
@@ -31,6 +30,12 @@ enum SpectatingMode {
FREE,
}
+enum JoinState {
+ SPECTATING,
+ WAITING,
+ JOINED,
+}
+
var player_id: int = -1
var item_names: Array = []
var item_index_by_name: Dictionary = {}
@@ -42,10 +47,10 @@ var maps: Array = []
var bot_algos: Array
var text_message_history: Array[Array] = []
+var join_state: JoinState = JoinState.SPECTATING
+
var in_lobby := false
var is_replay := false
-var is_joined := false
-var join_sent := false
var tutorial_running := false
var tutorial_queue := []
var last_position := Vector2(0, 0)
@@ -99,8 +104,7 @@ func handle_packet(p):
in_lobby_updated.connect(player_instance.onscreen_controls.in_lobby_updated)
player_instance.onscreen_controls.in_lobby_updated(in_lobby)
camera.target = player_instance.movement_base
- is_joined = true
- joined.emit()
+ set_join_state(JoinState.JOINED)
else:
player_instance = Player.new(p.id, p.name, p.position, p.character, self)
players[p.id] = player_instance
@@ -114,8 +118,7 @@ func handle_packet(p):
tutorial_queue.erase(player.current_item_message)
pinned_items.clear_item(p.id)
if p.id == player_id:
- is_joined = false
- left.emit()
+ set_join_state(JoinState.SPECTATING)
camera.target = $Center
if player.hand != null:
player.hand.queue_free()
@@ -244,18 +247,15 @@ func handle_packet(p):
map.gi_bake()
await get_parent()._menu_open()
map.autobake = true
-
- if in_lobby: popup_message.lobby()
- else: popup_message.ingame()
+
+ in_lobby_updated.emit(in_lobby)
else:
map.autobake = false
await get_parent()._menu_exit()
-
+
lobby.visible = in_lobby
- if lobby and not join_sent:
- join()
-
- in_lobby_updated.emit(in_lobby)
+ if lobby and join_state == JoinState.SPECTATING:
+ toggle_join()
"score":
if p.time_remaining != null:
overlay.update(p.demands_failed, p.demands_completed, p.points, p.time_remaining)
@@ -291,7 +291,7 @@ func handle_packet(p):
"server_message":
var mstr := get_message_str(p.message)
if p.error:
- # popup_message.display_server_msg(tr("c.error.server").format([mstr]))
+ popup_message.display_server_msg(tr("c.error.server").format([mstr]))
push_error(tr("c.error.server").format([mstr]))
else:
popup_message.display_server_msg(mstr)
@@ -310,7 +310,7 @@ func handle_packet(p):
else:
# Positional hint message
if message == null:
- popup_message.clear_server_msg()
+ popup_message.clear_server_msg(position_)
else:
popup_message.display_server_msg_positional(get_message_str(message), position_, false)
"environment":
@@ -323,16 +323,20 @@ func handle_packet(p):
_: push_error("Unrecognized packet type: %s" % p.type)
-func join():
- if join_sent:
- push_error("Join was already sent. Tried to join twice.")
- return
- join_sent = true
- mp.send_join(Global.get_profile("username"), Global.get_profile("character"))
+func set_join_state(state: JoinState):
+ join_state = state
+ join_state_updated.emit(state)
-func leave():
- join_sent = false
- mp.send_leave(player_id)
+func toggle_join():
+ match join_state:
+ JoinState.SPECTATING:
+ set_join_state(JoinState.WAITING)
+ mp.send_join(Global.get_profile("username"), Global.get_profile("character"))
+ JoinState.WAITING:
+ push_error("Join/Leave action already toggled.")
+ JoinState.JOINED:
+ set_join_state(JoinState.WAITING)
+ mp.send_leave(player_id)
func _process(delta):
update_center()
@@ -359,7 +363,7 @@ func get_tile_interactive(pos: Vector2i) -> bool:
func update_center():
- if is_joined:
+ if join_state != JoinState.SPECTATING:
return
if Input.get_vector("left", "right", "forwards", "backwards").normalized().length() > .1:
spectating_mode = SpectatingMode.FREE
diff --git a/client/map/tiles/floor.gd b/client/map/tiles/floor.gd
index 8e75834b..dd51c928 100644
--- a/client/map/tiles/floor.gd
+++ b/client/map/tiles/floor.gd
@@ -16,11 +16,12 @@
class_name Floor
extends Tile
-var opt
+var opt: bool
+
func _init(ctx: TileFactory.TileCC):
opt = ctx.floor_mesher != null
super(ctx)
- if opt: ctx.floor_mesher.add_tile(ctx.position)
+ if not base_mesh: ctx.floor_mesher.add_tile(ctx.position)
func get_base_mesh():
if opt: return null
diff --git a/client/menu/blur_setup.gd b/client/menu/blur_setup.gd
index 331d1f47..9d55a9d4 100644
--- a/client/menu/blur_setup.gd
+++ b/client/menu/blur_setup.gd
@@ -14,6 +14,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
extends Control
+class_name BlurSetup
func _ready():
update(Global.get_setting("graphics.ui_blur"))
diff --git a/client/menu/character.gd b/client/menu/character.gd
index 6af30250..dd3bc5cd 100644
--- a/client/menu/character.gd
+++ b/client/menu/character.gd
@@ -18,7 +18,6 @@
extends Menu
@onready var character: Character = $Node3D/Character
-@onready var num_hairstyles := character.hairstyles.keys().size()
@onready var back_button := $VBoxContainer/bottom_panel/back
@onready var map: Map = $Node3D/Map
@onready var username_edit = $VBoxContainer/top_panel/a/username
@@ -26,7 +25,7 @@ extends Menu
func _ready():
super()
$VBoxContainer/top_panel/a/username.text = Global.get_profile("username")
- character.select_hairstyle(Global.get_profile("character"))
+ character.set_style(Global.get_profile("character"))
init_map()
func init_map():
@@ -53,6 +52,7 @@ func init_map():
for y in tiles.size():
for x in tiles[y].size():
map.set_tile(Vector2i(x,y) - co, gt.call([x,y]), [[x,y-1],[x-1,y],[x,y+1],[x+1,y]].map(gt))
+ map.flush()
func _input(_event):
if Input.is_action_just_pressed("ui_cancel"):
@@ -68,9 +68,9 @@ func _on_back_pressed():
replace_menu("res://menu/main.tscn")
func _on_character_back_pressed():
- Global.set_profile("character", (Global.get_profile("character") - 1) % num_hairstyles)
- character.select_hairstyle(Global.get_profile("character"))
+ Global.set_profile("character", max(Global.get_profile("character") - 1, 0))
+ character.set_style(Global.get_profile("character"))
func _on_character_forward_pressed():
- Global.set_profile("character", (Global.get_profile("character") + 1) % num_hairstyles)
- character.select_hairstyle(Global.get_profile("character"))
+ Global.set_profile("character", max(Global.get_profile("character") + 1, 0))
+ character.set_style(Global.get_profile("character"))
diff --git a/client/menu/communicate/popup_message/popup_message.gd b/client/menu/communicate/popup_message/popup_message.gd
index 6c2c2c0e..98bd94e3 100644
--- a/client/menu/communicate/popup_message/popup_message.gd
+++ b/client/menu/communicate/popup_message/popup_message.gd
@@ -14,45 +14,34 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
-extends MarginContainer
+extends Control
class_name PopupMessage
+const SERVER_MESSAGE_SCENE = preload("res://menu/communicate/popup_message/server_message.tscn")
+
var is_ingame := false
var is_joined := false
-@onready var server_msg = $VBox/ServerMessage
-@onready var server_msg_positional = $ServerMessagePositional
-@onready var hint_msg = $VBox/HintMessage
-
-@onready var server_msg_timer: Timer = $ServerTimer
-@onready var hint_msg_timer: Timer = $HintTimer
-
-@onready var server_msg_label: Label = $VBox/ServerMessage/CenterContainer/Label
-@onready var server_msg_positional_label: Label = $ServerMessagePositional/ServerMessage/CenterContainer/Label
-@onready var hint_msg_label: Label = $VBox/HintMessage/CenterContainer/Label
+var positional_messages = {}
-@onready var server_msg_positional_panel: PanelContainer = $ServerMessagePositional/ServerMessage
+@onready var positional_messages_node: Control = $Positional
+@onready var server_msg = $Static/VBox/ServerMessage
+@onready var hint_msg = $Static/VBox/HintMessage
-@onready var auto_hint_timers: Node = $AutoHintTimers
+@onready var server_msg_label: Label = $Static/VBox/ServerMessage/CenterContainer/Label
+@onready var hint_msg_label: Label = $Static/VBox/HintMessage/CenterContainer/Label
-@onready var reset_timer = $Reset
-@onready var join_while_running_timer = $JoinWhileRunning
+@onready var auto_hint_timers: Node = $Timers/AutoHints
+@onready var server_msg_timer: Timer = $Timers/Server
+@onready var hint_msg_timer: Timer = $Timers/Hint
+@onready var reset_timer = $Timers/Reset
+@onready var join_while_running_timer = $Timers/JoinWhileRunning
@onready var game: Game = $"../Game"
-var server_message_position := Vector2.ZERO
-var last_server_message_panel_size := Vector2.ZERO
-
func _ready():
- game.joined.connect(
- func player_joined():
- is_joined = true
- update_state()
- )
- game.left.connect(
- func player_joined():
- is_joined = false
- update_state()
+ game.join_state_updated.connect(func(state: Game.JoinState):
+ is_joined = state == Game.JoinState.JOINED
)
game.update_tutorial_running.connect(
func a(running: bool):
@@ -61,25 +50,26 @@ func _ready():
else:
update_state()
)
+ game.in_lobby_updated.connect(
+ func a(in_lobby):
+ is_ingame = not in_lobby
+ update_state()
+ )
func _process(_delta: float):
- if server_msg_positional.visible:
- var pos_3d = Vector3(server_message_position.x + 0.5, 1.5, server_message_position.y + 0.5)
+ for pos: Vector2 in positional_messages.keys():
+ var msg: PositionalMessage = positional_messages[pos]
+ var pos_3d = Vector3(pos.x + 0.5, 1.5, pos.y + 0.5)
var pos_2d = get_viewport().get_camera_3d().unproject_position(pos_3d)
- var server_message_panel_size = server_msg_positional_panel.size
- server_msg_positional.position = pos_2d.clamp(Vector2.ZERO + 0.5 * server_message_panel_size, Vector2(get_viewport_rect().size) - 0.5 * server_message_panel_size)
- if server_message_panel_size != last_server_message_panel_size:
- last_server_message_panel_size = server_message_panel_size
- server_msg_positional_panel.position = -0.5 * last_server_message_panel_size
-
-func ingame():
- is_ingame = true
- update_state()
-
-func lobby():
- is_ingame = false
- update_state()
+ msg.node_2d.position = pos_2d.clamp(
+ Vector2.ZERO + 0.5 * msg.node.size,
+ Vector2(get_viewport_rect().size) - 0.5 * msg.node.size
+ )
+
+ if msg.node.size != msg.last_size:
+ msg.last_size = msg.node.size
+ msg.node.position = -0.5 * msg.last_size
func update_state():
if is_ingame and is_joined:
@@ -91,30 +81,35 @@ func update_state():
stop_game_hints()
func display_server_msg(msg: String, auto_remove := true):
- clear_server_msg()
server_msg.show()
server_msg_label.text = msg
if auto_remove:
server_msg_timer.start()
-func display_server_msg_positional(msg: String, pos: Vector2, auto_remove := true):
+func _on_server_timeout() -> void:
clear_server_msg()
- server_msg_positional.show()
- server_message_position = pos
- server_msg_positional_label.text = msg
- server_msg_positional_panel.size = Vector2.ZERO
-
- if auto_remove:
- server_msg_timer.start()
-func clear_server_msg():
- server_msg_timer.stop()
- server_msg.hide()
- server_msg_positional.hide()
+func display_server_msg_positional(text: String, pos: Vector2, use_monospace: bool):
+ var msg := PositionalMessage.new()
+ msg.node = SERVER_MESSAGE_SCENE.instantiate()
+ msg.node_2d = Node2D.new()
+ positional_messages_node.add_child(msg.node_2d)
+ msg.node_2d.add_child(msg.node)
+ msg.node.set_text(text, use_monospace)
+ msg.node.size = Vector2.ZERO
+ msg.position = pos
+ positional_messages[pos] = msg
-func _on_server_timer_timeout():
- clear_server_msg()
+func clear_server_msg(position_ = null):
+ if position_ == null:
+ server_msg_timer.stop()
+ server_msg.hide()
+ else:
+ if position_ in positional_messages:
+ var msg: PositionalMessage = positional_messages[position_]
+ msg.node_2d.queue_free()
+ positional_messages.erase(position_)
func display_hint_msg(msg: String):
hint_msg.show()
@@ -220,7 +215,7 @@ func _on_rotate_camera_timeout():
)]))
func _on_join_while_running_timeout():
- if not game.is_joined and not Global.get_hint("has_seen_join_while_running"):
+ if not game.join_state == Game.JoinState.JOINED and not Global.get_hint("has_seen_join_while_running"):
Global.set_hint("has_seen_join_while_running", true)
display_hint_msg(tr("c.hint.join_while_running").format([display_keybind("menu")]))
@@ -228,3 +223,9 @@ func _on_performance_timeout() -> void:
if not Global.get_hint("has_seen_performance") and Engine.get_frames_per_second() < DisplayServer.screen_get_refresh_rate() * 0.75:
Global.set_hint("has_seen_performance", true)
display_hint_msg(tr("c.hint.framerate_low"))
+
+class PositionalMessage:
+ var node: ServerMessage
+ var node_2d: Node2D
+ var position: Vector2
+ var last_size: Vector2
diff --git a/client/menu/communicate/popup_message/popup_message.tscn b/client/menu/communicate/popup_message/popup_message.tscn
index 799712e1..880e8670 100644
--- a/client/menu/communicate/popup_message/popup_message.tscn
+++ b/client/menu/communicate/popup_message/popup_message.tscn
@@ -33,25 +33,35 @@ content_margin_top = 8.0
content_margin_right = 32.0
content_margin_bottom = 8.0
-[node name="PopupMessage" type="MarginContainer"]
+[node name="PopupMessage" type="Control"]
+layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
-theme = ExtResource("1_a1566")
script = ExtResource("2_sbew6")
-[node name="VBox" type="VBoxContainer" parent="."]
+[node name="Static" type="MarginContainer" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 2
+theme = ExtResource("1_a1566")
+
+[node name="VBox" type="VBoxContainer" parent="Static"]
layout_mode = 2
mouse_filter = 2
-[node name="ServerMessage" parent="VBox" instance=ExtResource("3_m3rok")]
+[node name="ServerMessage" parent="Static/VBox" instance=ExtResource("3_m3rok")]
visible = false
layout_mode = 2
-[node name="HintMessage" type="PanelContainer" parent="VBox"]
+[node name="HintMessage" type="PanelContainer" parent="Static/VBox"]
visible = false
material = SubResource("ShaderMaterial_k0m35")
layout_mode = 2
@@ -60,12 +70,12 @@ mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_vq4dg")
script = ExtResource("4_pvwmw")
-[node name="CenterContainer" type="HBoxContainer" parent="VBox/HintMessage"]
+[node name="CenterContainer" type="HBoxContainer" parent="Static/VBox/HintMessage"]
layout_mode = 2
mouse_filter = 2
alignment = 1
-[node name="MarginContainer" type="MarginContainer" parent="VBox/HintMessage/CenterContainer"]
+[node name="MarginContainer" type="MarginContainer" parent="Static/VBox/HintMessage/CenterContainer"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_left = 4
@@ -73,7 +83,7 @@ theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 4
-[node name="TextureRect" type="TextureRect" parent="VBox/HintMessage/CenterContainer/MarginContainer"]
+[node name="TextureRect" type="TextureRect" parent="Static/VBox/HintMessage/CenterContainer/MarginContainer"]
custom_minimum_size = Vector2(28, 28)
layout_mode = 2
mouse_filter = 2
@@ -81,7 +91,7 @@ texture = ExtResource("5_2dxsd")
expand_mode = 1
stretch_mode = 4
-[node name="Label" type="Label" parent="VBox/HintMessage/CenterContainer"]
+[node name="Label" type="Label" parent="Static/VBox/HintMessage/CenterContainer"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_fonts/font = SubResource("FontVariation_qfltj")
@@ -89,60 +99,66 @@ theme_override_styles/normal = SubResource("StyleBoxEmpty_3rgop")
text = "A hint is worth more than a thousand manuals"
autowrap_mode = 3
-[node name="ServerTimer" type="Timer" parent="."]
+[node name="Positional" type="Control" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 2
+
+[node name="Timers" type="Node" parent="."]
+
+[node name="Server" type="Timer" parent="Timers"]
wait_time = 5.0
one_shot = true
-[node name="HintTimer" type="Timer" parent="."]
+[node name="Hint" type="Timer" parent="Timers"]
wait_time = 10.0
one_shot = true
-[node name="AutoHintTimers" type="Node" parent="."]
+[node name="AutoHints" type="Node" parent="Timers"]
-[node name="Move" type="Timer" parent="AutoHintTimers"]
+[node name="Move" type="Timer" parent="Timers/AutoHints"]
wait_time = 2.0
one_shot = true
-[node name="Performance" type="Timer" parent="AutoHintTimers"]
+[node name="Performance" type="Timer" parent="Timers/AutoHints"]
wait_time = 20.0
one_shot = true
-[node name="Boost" type="Timer" parent="AutoHintTimers"]
+[node name="Boost" type="Timer" parent="Timers/AutoHints"]
wait_time = 90.0
one_shot = true
-[node name="Interact" type="Timer" parent="AutoHintTimers"]
+[node name="Interact" type="Timer" parent="Timers/AutoHints"]
wait_time = 15.0
one_shot = true
-[node name="RotateCamera" type="Timer" parent="AutoHintTimers"]
+[node name="RotateCamera" type="Timer" parent="Timers/AutoHints"]
wait_time = 120.0
one_shot = true
-[node name="Zoom" type="Timer" parent="AutoHintTimers"]
+[node name="Zoom" type="Timer" parent="Timers/AutoHints"]
wait_time = 135.0
one_shot = true
-[node name="Reset" type="Timer" parent="."]
+[node name="Reset" type="Timer" parent="Timers"]
wait_time = 10.0
one_shot = true
-[node name="JoinWhileRunning" type="Timer" parent="."]
+[node name="JoinWhileRunning" type="Timer" parent="Timers"]
wait_time = 5.0
one_shot = true
-[node name="ServerMessagePositional" type="Node2D" parent="."]
-visible = false
-
-[node name="ServerMessage" parent="ServerMessagePositional" instance=ExtResource("3_m3rok")]
-
-[connection signal="timeout" from="ServerTimer" to="." method="_on_server_timer_timeout"]
-[connection signal="timeout" from="HintTimer" to="." method="_on_hint_timer_timeout"]
-[connection signal="timeout" from="AutoHintTimers/Move" to="." method="_on_move_timeout"]
-[connection signal="timeout" from="AutoHintTimers/Performance" to="." method="_on_performance_timeout"]
-[connection signal="timeout" from="AutoHintTimers/Boost" to="." method="_on_boost_timeout"]
-[connection signal="timeout" from="AutoHintTimers/Interact" to="." method="_on_interact_timeout"]
-[connection signal="timeout" from="AutoHintTimers/RotateCamera" to="." method="_on_rotate_camera_timeout"]
-[connection signal="timeout" from="AutoHintTimers/Zoom" to="." method="_on_zoom_timeout"]
-[connection signal="timeout" from="Reset" to="." method="_on_reset_timeout"]
-[connection signal="timeout" from="JoinWhileRunning" to="." method="_on_join_while_running_timeout"]
+[connection signal="timeout" from="Timers/Server" to="." method="_on_server_timeout"]
+[connection signal="timeout" from="Timers/Hint" to="Static" method="_on_hint_timer_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/Move" to="Static" method="_on_move_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/Performance" to="Static" method="_on_performance_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/Boost" to="Static" method="_on_boost_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/Interact" to="Static" method="_on_interact_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/RotateCamera" to="Static" method="_on_rotate_camera_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/Zoom" to="Static" method="_on_zoom_timeout"]
+[connection signal="timeout" from="Timers/Reset" to="Static" method="_on_reset_timeout"]
+[connection signal="timeout" from="Timers/JoinWhileRunning" to="Static" method="_on_join_while_running_timeout"]
diff --git a/client/menu/communicate/popup_message/server_message.gd b/client/menu/communicate/popup_message/server_message.gd
new file mode 100644
index 00000000..fc12ee76
--- /dev/null
+++ b/client/menu/communicate/popup_message/server_message.gd
@@ -0,0 +1,13 @@
+extends BlurSetup
+class_name ServerMessage
+
+const DEFAULT_FONT = preload("res://menu/theme/font-josefin-sans.woff2")
+const MONOSPACE_FONT = preload("res://menu/theme/font-azaret-mono.woff2")
+
+@onready var label: Label = $CenterContainer/Label
+
+func set_text(text: String, use_monospace := true):
+ label.text = text
+ var font: FontVariation = label.get_theme_font("font")
+ font.base_font = MONOSPACE_FONT if use_monospace else DEFAULT_FONT
+ label.add_theme_font_size_override("font_size", 16 if use_monospace else 20)
diff --git a/client/menu/communicate/popup_message/server_message.tscn b/client/menu/communicate/popup_message/server_message.tscn
index 63160942..2a848419 100644
--- a/client/menu/communicate/popup_message/server_message.tscn
+++ b/client/menu/communicate/popup_message/server_message.tscn
@@ -1,7 +1,7 @@
[gd_scene load_steps=8 format=3 uid="uid://dq61p3a8og2b6"]
[ext_resource type="Shader" path="res://menu/blur_mix.gdshader" id="1_qv8ew"]
-[ext_resource type="Script" path="res://menu/blur_setup.gd" id="2_80a6b"]
+[ext_resource type="Script" path="res://menu/communicate/popup_message/server_message.gd" id="2_csqo8"]
[ext_resource type="FontFile" uid="uid://bk704sc5gkrb3" path="res://menu/theme/font-azaret-mono.woff2" id="3_dw20j"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_q3bbd"]
@@ -20,6 +20,7 @@ corner_radius_bottom_right = 16
corner_radius_bottom_left = 16
[sub_resource type="FontVariation" id="FontVariation_qfltj"]
+resource_local_to_scene = true
base_font = ExtResource("3_dw20j")
variation_embolden = 0.75
@@ -35,7 +36,7 @@ size_flags_horizontal = 4
size_flags_vertical = 0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_vq4dg")
-script = ExtResource("2_80a6b")
+script = ExtResource("2_csqo8")
[node name="CenterContainer" type="CenterContainer" parent="."]
layout_mode = 2
@@ -45,5 +46,6 @@ mouse_filter = 2
layout_mode = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_fonts/font = SubResource("FontVariation_qfltj")
+theme_override_font_sizes/font_size = 16
theme_override_styles/normal = SubResource("StyleBoxEmpty_3rgop")
text = "Server message"
diff --git a/client/menu/hairstyle_preview.gd b/client/menu/hairstyle_preview.gd
index 5a9cce68..08b6aab9 100644
--- a/client/menu/hairstyle_preview.gd
+++ b/client/menu/hairstyle_preview.gd
@@ -19,7 +19,7 @@ extends VBoxContainer
signal selected(character: int)
func setup(character: int, group: ButtonGroup):
- $HairViewport/Node3D/Character.select_hairstyle(character)
+ $HairViewport/Node3D/Character.set_style(character)
$Select.button_group = group
$Select.text = tr("c.setup.uniform.value").format([character + 1])
$Select.pressed.connect(func(): selected.emit(character))
diff --git a/client/menu/ingame.gd b/client/menu/ingame.gd
index 7052f237..ba365f8e 100644
--- a/client/menu/ingame.gd
+++ b/client/menu/ingame.gd
@@ -26,19 +26,16 @@ extends Menu
var opened
func _ready():
opened = Time.get_ticks_msec()
- game.joined.connect(_on_game_joined)
- game.left.connect(_on_game_left)
- update_button_text()
- game.joined.connect(update_lobby_button)
- game.left.connect(update_lobby_button)
+ game.join_state_updated.connect(_on_game_join_state_changed)
+ _on_game_join_state_changed(game.join_state)
update_lobby_button()
super()
func update_lobby_button():
- lobby_button.disabled = game.in_lobby or not game.is_joined
+ lobby_button.disabled = game.in_lobby or game.join_state == Game.JoinState.SPECTATING
if game.in_lobby:
lobby_button.tooltip_text = "Cannot cancel game since no game is running."
- elif not game.is_joined:
+ elif not game.join_state == Game.JoinState.JOINED:
lobby_button.tooltip_text = "You must join in order to be able to cancel the current game."
else:
lobby_button.tooltip_text = ""
@@ -71,21 +68,15 @@ func _on_lobby_pressed():
exit()
func _on_leave_pressed():
- if game.is_joined:
- game.mp.send_leave(game.player_id)
- elif not game.join_sent:
- leave_button.disabled = true
- game.join()
+ game.toggle_join()
-func _on_game_joined():
- leave_button.disabled = false
- update_button_text()
-
-func _on_game_left():
- update_button_text()
-
-func update_button_text():
- if game.is_joined:
- leave_button.text = tr("c.menu.ingame.leave")
- else:
- leave_button.text = tr("c.menu.ingame.join")
+func _on_game_join_state_changed(state: Game.JoinState):
+ match state:
+ Game.JoinState.JOINED:
+ leave_button.disabled = false
+ leave_button.text = tr("c.menu.ingame.leave")
+ Game.JoinState.SPECTATING:
+ leave_button.disabled = false
+ leave_button.text = tr("c.menu.ingame.join")
+ Game.JoinState.WAITING:
+ leave_button.disabled = true
diff --git a/client/menu/lobby.gd b/client/menu/lobby.gd
index 0dca6f4c..d595444e 100644
--- a/client/menu/lobby.gd
+++ b/client/menu/lobby.gd
@@ -52,8 +52,8 @@ func _ready():
game.update_players.connect(update_players)
initialize()
game.data_updated.connect(initialize)
- game.joined.connect(_on_game_joined)
- game.left.connect(_on_game_left)
+ game.join_state_updated.connect(_on_game_join_state_updated)
+ _on_game_join_state_updated(game.join_state)
check_for_music()
func initialize():
@@ -145,18 +145,6 @@ func _input(_event):
elif Input.is_action_just_pressed("next") and not next_map.disabled:
next_map.emit_signal("pressed")
-func _on_game_joined():
- map_selector.show()
- map_list.show()
- bots_container.show()
- start_button.disabled = false
-
-func _on_game_left():
- map_selector.hide()
- map_list.hide()
- bots_container.hide()
- start_button.disabled = true
-
func _on_left_pressed():
selected_map = (selected_map - 1) % map_count
select_map(selected_map)
@@ -177,13 +165,27 @@ func _on_controller_button_pressed():
game.mp.send_chat(game.player_id, start_msg)
Sound.play_music("stop") # TODO: Game music enter
+func _on_game_join_state_updated(state: Game.JoinState):
+ match state:
+ Game.JoinState.JOINED:
+ map_selector.show()
+ map_list.show()
+ bots_container.show()
+ start_button.disabled = false
+ join_spectate.disabled = false
+ join_spectate.text = tr("c.menu.ingame.spectate")
+ Game.JoinState.SPECTATING:
+ map_selector.hide()
+ map_list.hide()
+ bots_container.hide()
+ start_button.disabled = true
+ join_spectate.disabled = false
+ join_spectate.text = tr("c.menu.ingame.join")
+ Game.JoinState.WAITING:
+ join_spectate.disabled = true
+
func _on_join_spectate_pressed():
- if game.is_joined:
- game.leave()
- join_spectate.text = tr("c.menu.ingame.join")
- elif not game.join_sent:
- game.join()
- join_spectate.text = tr("c.menu.ingame.spectate")
+ game.toggle_join()
func check_for_music():
if visible:
diff --git a/client/menu/menu_background.gd b/client/menu/menu_background.gd
index 33ec6e43..77fb123f 100644
--- a/client/menu/menu_background.gd
+++ b/client/menu/menu_background.gd
@@ -17,8 +17,8 @@
#
extends Node3D
-const NULLS = [null,null,null,null]
-const BUCKETS = [[], ["floor","floor","floor","floor","tomato-crate", "steak-crate"], ["table", "chair", "counter"], ["sink", "stove"]]
+const CRATES = ["tomato-crate", "steak-crate", "cheese-crate", "lettuce-crate", "flour-crate", "coconut-crate"]
+const TOOLS = ["sink", "cuttingboard", "stove", "oven", "freezer"]
@onready var environment: WorldEnvironment = $Environment
@onready var map: Map = $Map
@@ -27,12 +27,26 @@ func _ready():
if !Global.on_vulkan():
environment.environment.tonemap_exposure = 0.25
- for x in range(-10,11):
- for y in range(-10,11):
- var w = exp(-sqrt(x*x+y*y) * 0.15)
+ var tiles = {}
+ for x in range(-10, 11):
+ for y in range(-10, 11):
+ var w = exp(-sqrt(x * x + y * y) * 0.15)
var k = randf() * w
- var bucket = BUCKETS[int(floor(k * BUCKETS.size())) % BUCKETS.size()]
- if bucket.size() == 0: continue
- var tile_name = bucket[randi() % bucket.size()]
- map.set_tile(Vector2i(x,y), tile_name)
+ var tn = null
+ if k > 0.25: tn = "floor"
+ if k > 0.4: tn = choose(CRATES) if randf() > 0.3 else "counter"
+ if k > 0.6: tn = choose(TOOLS)
+ if tn != null: tiles[str(Vector2i(x,y))] = [tn,[x,y]]
+
+ var gt = func (cs):
+ var t = tiles.get(str(Vector2i(cs[0],cs[1])))
+ return null if t == null else t[0]
+ for pk in tiles.keys():
+ var x = tiles[pk][1][0]
+ var y = tiles[pk][1][1]
+ var t = gt.call([x,y])
+ if t != null: map.set_tile(Vector2i(x,y), t, [[x,y-1],[x-1,y],[x,y+1],[x+1,y]].map(gt))
+
map.flush()
+
+func choose(a): return a[floor(a.size() * randf())]
diff --git a/client/menu/play.gd b/client/menu/play.gd
index 1fe19224..b117d6a4 100644
--- a/client/menu/play.gd
+++ b/client/menu/play.gd
@@ -19,7 +19,6 @@ extends Menu
var url_regex: RegEx = RegEx.new()
-@onready var req: HTTPRequest = $HTTPRequest
@onready var server_list: VBoxContainer = $side/margin/options/second/ScrollContainerCustom/ServerList
@onready var server_list_loading: Label = $side/margin/options/second/Loading
@onready var connect_uri = $side/margin/options/second/connect/uri
diff --git a/client/player/character/character.gd b/client/player/character/character.gd
index 66a3435b..65275549 100644
--- a/client/player/character/character.gd
+++ b/client/player/character/character.gd
@@ -42,11 +42,16 @@ var current_animation := "idle"
@onready var tie = $Main/Tie
@onready var knife = $Main/HandRight/Knife
-@onready var hairstyles := {
- "Brown": $Main/HeadDefault/Hair,
- "Blond": $Main/HeadDefault/Hair2,
- "E. Parsley": $Main/HeadDefault/Hair3
-}
+const NUM_COLORS = 5;
+const NUM_HAIRS = 3;
+@onready var hairstyles := [$Main/HeadDefault/Hair, $Main/HeadDefault/Hair2, $Main/HeadDefault/Hair3]
+var colors = [
+ Color(0.204, 0.361, 0.624),
+ Color(0.568, 0.256, 0.602),
+ Color(0.575, 0.341, 0.117),
+ Color(0.3, 0.455, 0.221),
+ Color(0.101, 0.452, 0.521)
+]
@onready var head_default: MeshInstance3D = $Main/HeadDefault
@onready var head_robot: MeshInstance3D = $Main/HeadRobot
@@ -54,28 +59,41 @@ var current_animation := "idle"
@onready var step_sounds: PlayRandom = $Steps
@onready var boost_sounds: PlayRandom = $Boosts
+class ParsedStyle:
+ var color: int
+ var hair: int
+ var robot: bool
+ var customer: bool
+ func _init(n: int) -> void:
+ customer = n < 0
+ if customer: n *= -1
+ if n == 51: robot = true
+ else:
+ hair = n % NUM_HAIRS
+ color = n / NUM_HAIRS % NUM_COLORS
+ func pack() -> int:
+ if robot: return 51
+ return (hair + color * NUM_HAIRS) * (-1 if customer else 1)
+
func _ready():
play_animation("idle")
var t := 0.0
func _process(delta):
- if walking:
- t += delta
- main_height_target = default_height + sin(t * WALK_ANIM_SPEED) * WALK_ANIM_STRENGTH
- else:
- t = 0
+ t += delta
+ if walking: main_height_target = default_height + sin(t * WALK_ANIM_SPEED) * WALK_ANIM_STRENGTH
+ else: t = 0
main.position.y = main_height_target
# Update animation:
var next_animation: String
- if holding:
- next_animation = "hold"
- elif cutting:
- next_animation = "cut"
- elif walking:
- next_animation = "walk"
- else:
- next_animation = "idle"
+ if holding: next_animation = "hold"
+ elif cutting: next_animation = "cut"
+ elif walking: next_animation = "walk"
+ else: next_animation = "idle"
+
+ if current_animation != next_animation:
+ play_animation(next_animation)
walking_particles.emitting = walking
if boosting and walking and not was_boosting:
@@ -85,47 +103,31 @@ func _process(delta):
boosting_particles.emitting = false
was_boosting = boosting and walking
- if current_animation != next_animation:
- play_animation(next_animation)
-
-func select_hairstyle(id: int):
- if id == 51:
- toggle_robot(true)
- return
- if id < 0:
- to_customer()
- id *= -1
- var hairstyle_count = hairstyles.keys().size()
- id = id % hairstyle_count
- var target = hairstyles.keys()[id]
- for k in hairstyles.keys():
- if k == target:
- hairstyles[k].show()
- else:
- hairstyles[k].hide()
-
-func to_customer():
- main.mesh = CUSTOMER_MAIN_MESH
- tie.queue_free()
+func set_style(id: int):
+ var p = ParsedStyle.new(id)
+ set_customer(p.customer)
+ set_robot(p.robot)
+ for h in hairstyles: h.hide()
+ hairstyles[p.hair].show()
+ $Main.get_active_material(0).albedo_color = colors[p.color]
-func toggle_robot(b: bool):
+func set_customer(b: bool):
if b:
- head_robot.show()
- head_default.hide()
- main.mesh = ROBOT_MAIN_MESH
- else:
- head_robot.hide()
- head_default.show()
- main.mesh = DEFAULT_MAIN_MESH
+ main.mesh = CUSTOMER_MAIN_MESH
+ tie.queue_free()
+ else: pass # TODO
+
+func set_robot(b: bool):
+ head_robot.visible = b
+ head_default.visible = not b
+ main.mesh = ROBOT_MAIN_MESH if b else DEFAULT_MAIN_MESH
func play_animation(name_: String):
current_animation = name_
hand_animations.play(name_)
- if name_ == "walk":
- step_sounds.start_autoplay()
- else:
- step_sounds.stop_autoplay()
+ if name_ == "walk": step_sounds.start_autoplay()
+ else: step_sounds.stop_autoplay()
knife.visible = name_ == "cut"
diff --git a/client/player/character/character.tscn b/client/player/character/character.tscn
index a7c09c01..aca0658a 100644
--- a/client/player/character/character.tscn
+++ b/client/player/character/character.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=27 format=3 uid="uid://b3hhir2fvnunu"]
+[gd_scene load_steps=28 format=3 uid="uid://b3hhir2fvnunu"]
[ext_resource type="Script" path="res://player/character/character.gd" id="1_12lbh"]
[ext_resource type="ArrayMesh" uid="uid://bnmm01yjwultj" path="res://player/character/default/main.res" id="2_uovyg"]
@@ -18,6 +18,11 @@
[ext_resource type="AudioStream" uid="uid://1jsqpnk3igj3" path="res://player/sounds/woosh1.ogg" id="14_ikcec"]
[ext_resource type="AudioStream" uid="uid://cwme7eatip0jc" path="res://player/sounds/woosh2.ogg" id="15_iv4wu"]
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_7ojaw"]
+resource_local_to_scene = true
+resource_name = "main"
+cull_mode = 2
+
[sub_resource type="Animation" id="Animation_tdhvg"]
length = 0.001
tracks/0/type = "bezier"
@@ -729,6 +734,7 @@ script = ExtResource("1_12lbh")
transform = Transform3D(0.33, 0, 0, 0, 0.33, 0, 0, 0, 0.33, 0, 0.33, 0)
mesh = ExtResource("2_uovyg")
skeleton = NodePath("")
+surface_material_override/0 = SubResource("StandardMaterial3D_7ojaw")
[node name="HandRight" type="MeshInstance3D" parent="Main"]
transform = Transform3D(0.287144, 0.2864, -1.17785e-06, 0.402357, -0.133775, 0.337554, 0.292329, -0.0971941, -0.464603, -1.302, -0.17, 0)
diff --git a/client/player/controllable_player.gd b/client/player/controllable_player.gd
index 0cabcb64..131bc55d 100644
--- a/client/player/controllable_player.gd
+++ b/client/player/controllable_player.gd
@@ -43,7 +43,7 @@ func _ready():
add_child(timer)
timer.start()
timer.connect("timeout", func():
- if game.mp != null and game.join_sent:
+ if game.mp != null and game.join_state == Game.JoinState.JOINED:
game.mp.send_movement(game.player_id, position_, direction, boosting)
)
add_child(onscreen_controls)
@@ -60,13 +60,20 @@ func _process(delta):
update_touch_scrolls()
var moving_duration = 0
+var fps_rotation_target = 0
func _process_movement(delta):
var input = Input.get_vector("left", "right", "forwards", "backwards") if is_input_enabled() else Vector2.ZERO
if Global.get_setting("gameplay.first_person"):
- input.x *= 0.1
+ fps_rotation_target += input.x * delta * 3.
+ if abs(input.x) > 0.1: input.y -= 0.5
+ input.x = 0.
input.y = min(input.y, 0)
+ input = input.rotated(fps_rotation_target)
+ else:
+ input = input.rotated(input_rotation)
+
var boost = Input.is_action_pressed("boost") or (Global.get_setting("gameplay.latch_boost") and boosting)
- input = input.rotated(input_rotation)
+ #
if Input.is_action_pressed("interact") or Input.is_action_just_released("interact"):
input *= 0
else:
diff --git a/client/player/player.gd b/client/player/player.gd
index 31a7a337..6ff28e81 100644
--- a/client/player/player.gd
+++ b/client/player/player.gd
@@ -79,7 +79,7 @@ func _init(_id: int, new_name: String, pos: Vector2, new_character_idx: int, new
is_customer = character_idx < 0
func _ready():
- character.select_hairstyle(character_idx)
+ character.set_style(character_idx)
clear_timer.timeout.connect(clear_message)
Settings.hook_changed_init("gameplay.usernames", false, update_username_tag)
diff --git a/data/index.yaml b/data/index.yaml
index a4984d59..f1942d05 100644
--- a/data/index.yaml
+++ b/data/index.yaml
@@ -4,6 +4,7 @@
# Copyright 2024 Rusty Striker
# Copyright 2024 BigBrotherNii
# Copyright 2024 nokoe
+# Copyright 2024 tpart
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -37,6 +38,7 @@ maps:
paris: { name: "Paris", players: 2, difficulty: 1 }
line: { name: "Line", players: 2, difficulty: 1 }
bbq: { name: "BBQ", players: 2, difficulty: 1 }
+ salad: { name: "Salad Store", players: 2, difficulty: 1 }
sushibar: { name: "Sushi Bar", players: 2, difficulty: 2 }
smallest: { name: "Smallest", players: 1, difficulty: 1 }
teeny: { name: "Teeny", players: 3, difficulty: 2 }
diff --git a/data/maps/salad.yaml b/data/maps/salad.yaml
new file mode 100644
index 00000000..96bc1aca
--- /dev/null
+++ b/data/maps/salad.yaml
@@ -0,0 +1,81 @@
+# Hurry Curry! - a game about cooking
+# Copyright 2024 tpart
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, version 3 of the License only.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+score_baseline: 200
+map:
+ - "*'''''''*''''''*'*"
+ - "''''''*''''**'*'''"
+ - "'''''███▒▒███'''''"
+ - "*''''█⌷CCCC⌷█'''*'"
+ - "'''''█p....L█''''*"
+ - "*''''▒p....T▒'''''"
+ - "'''''▒p....L▒'''''"
+ - "*''''█s....T█''''*"
+ - "'''''█......█'''''"
+ - "'''''█w█dd█w█'''''"
+ - "'''''█tc..ct█'''''"
+ - "*''''▒c....c▒'''''"
+ - "'*'''█......█'''''"
+ - "'''''█c....c█''*''"
+ - "'''''▒tc.~ct▒'''''"
+ - "*''''█c....c█'''''"
+ - "'''''█▒█dd█▒█''''*"
+ - "'''''''X__''''''''"
+ - "*'*'''''!_'''**'''"
+
+tiles:
+ "⌷": counter
+ "f": counter
+ "p": counter
+ "t": table
+ "w": counter-window
+ "s": sink
+ "C": cuttingboard
+ "T": tomato-crate
+ "L": lettuce-crate
+ "X": trash
+
+ "c": chair
+ "~": floor
+ ".": floor
+ "'": grass
+ "*": tree
+ "!": path
+ "_": path
+ "d": door
+ "▒": wall-window
+ "█": wall
+
+items:
+ "w": plate
+ "p": plate
+
+entities:
+ - !customers
+
+chef_spawn: "~"
+customer_spawn: "!"
+
+walkable:
+ - door
+ - floor
+ - chair
+ - grass
+ - path
+
+collider:
+ - wall
+ - wall-window
+ - tree
diff --git a/locale/en.ini b/locale/en.ini
index 71fbd816..ea798258 100644
--- a/locale/en.ini
+++ b/locale/en.ini
@@ -180,18 +180,21 @@ s.bot.frank=Frank Miller
s.tutorial.prevent_burning=Take this before it burns
s.tutorial.take_now=Take this item quickly!
s.tutorial.active=Interact here for {0}s
+s.tutorial.active_cuttingboard=Cut the item to slices here
s.tutorial.clear_tile=Clear this tile
s.tutorial.error=Tutorial code handle this recipe yet.
s.tutorial.finished=Tutorial finished!
s.tutorial.hold_interact=Hold interact
s.tutorial.interact_empty=Interact with an empty counter
s.tutorial.interact=Interact here
+s.tutorial.interact_plate=Add the item to this plate
s.tutorial.pickup=Take this item.
s.tutorial.put_away=Put away this item for later
s.tutorial.put_on=Place on {0}
s.tutorial.take=Take {0} from here
s.tutorial.serve=Serve the meal here
s.tutorial.wait_finish=...
+s.tutorial.accept_order=Approach the customer take their order
s.replay.cannot_join=Replays cannot be joined.
s.campaign.unlock_condition=To unlock: %n%n{0}
s.campaign.list_helper=- {0}%n - {1}
diff --git a/locale/tools/Cargo.toml b/locale/tools/Cargo.toml
index e8084b23..47f9e0d1 100644
--- a/locale/tools/Cargo.toml
+++ b/locale/tools/Cargo.toml
@@ -4,6 +4,6 @@ version = "0.1.0"
edition = "2021"
[dependencies]
-clap = { version = "4.5.16", features = ["derive"] }
-anyhow = "1.0.86"
-serde_json = "1.0.127"
+clap = { version = "4.5.18", features = ["derive"] }
+anyhow = "1.0.89"
+serde_json = "1.0.128"
diff --git a/pixel-client/Cargo.toml b/pixel-client/Cargo.toml
index 8104a384..4831f485 100644
--- a/pixel-client/Cargo.toml
+++ b/pixel-client/Cargo.toml
@@ -9,18 +9,18 @@ hurrycurry-protocol = { path = "../server/protocol" }
hurrycurry-client-lib = { path = "../server/client-lib", default-features = false, features = [
"sync-network",
] }
-tungstenite = { version = "0.23.0", features = ["rustls-tls-native-roots"] }
-serde_json = "1.0.122"
+tungstenite = { version = "0.24.0", features = ["rustls-tls-native-roots"] }
+serde_json = "1.0.128"
bincode = "2.0.0-rc.3"
log = "0.4.22"
env_logger = "0.11.5"
-anyhow = "1.0.86"
-clap = { version = "4.5.15", features = ["derive"] }
-rustls = { version = "0.23.12", features = ["ring"] }
+anyhow = "1.0.89"
+clap = { version = "4.5.18", features = ["derive"] }
+rustls = { version = "0.23.13", features = ["ring"] }
rand = "0.9.0-alpha.2"
xdg = "2.5.2"
toml = "0.8.19"
-serde = { version = "1.0.207", features = ["derive"] }
+serde = { version = "1.0.210", features = ["derive"] }
users = "0.11.0"
[features]
diff --git a/pixel-client/tools/Cargo.toml b/pixel-client/tools/Cargo.toml
index 15dd0239..075ec24f 100644
--- a/pixel-client/tools/Cargo.toml
+++ b/pixel-client/tools/Cargo.toml
@@ -5,8 +5,8 @@ edition = "2021"
[dependencies]
image = "0.25.2"
-anyhow = "1.0.86"
+anyhow = "1.0.89"
log = "0.4.22"
env_logger = "0.11.5"
-clap = { version = "4.5.15", features = ["derive"] }
+clap = { version = "4.5.18", features = ["derive"] }
sdl2 = { version = "0.37.0", features = ["image"] }
diff --git a/protocol.md b/protocol.md
index 4e5ab475..9562ab6f 100644
--- a/protocol.md
+++ b/protocol.md
@@ -45,9 +45,8 @@ sending a packet to update that of the other player.
- 443: All uses with TLS
- 27032: Game Server Websocket
-- 27033: Registry API HTTP
+- 27033: Registry API HTTP / Local dicovery service
- 27034: Lobby Server Websocket
-- 27035: Local discovery service API
## Binary Protocol
diff --git a/server/Cargo.toml b/server/Cargo.toml
index 978de4c6..38db0bdd 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -7,16 +7,16 @@ default-run = "hurrycurry-server"
[dependencies]
log = "0.4.22"
env_logger = "0.11.5"
-anyhow = "1.0.86"
-serde = { version = "1.0.205", features = ["derive"] }
-tokio = { version = "1.39.2", features = ["full"] }
-serde_json = "1.0.122"
-tokio-tungstenite = "0.23.1"
+anyhow = "1.0.89"
+serde = { version = "1.0.210", features = ["derive"] }
+tokio = { version = "1.40.0", features = ["full"] }
+serde_json = "1.0.128"
+tokio-tungstenite = "0.24.0"
futures-util = "0.3.30"
-serde_yml = "0.0.11"
+serde_yml = "0.0.12"
rand = "0.9.0-alpha.2"
shlex = "1.3.0"
-clap = { version = "4.5.15", features = ["derive"] }
+clap = { version = "4.5.18", features = ["derive"] }
reqwest = { version = "0.12.7", optional = true, default-features = false, features = [
"json",
"http2",
diff --git a/server/bot/Cargo.toml b/server/bot/Cargo.toml
index 3143ab55..c8d60270 100644
--- a/server/bot/Cargo.toml
+++ b/server/bot/Cargo.toml
@@ -7,8 +7,8 @@ edition = "2021"
hurrycurry-client-lib = { path = "../client-lib", features = ["tokio-network"] }
hurrycurry-protocol = { path = "../protocol" }
log = "0.4.22"
-anyhow = "1.0.86"
+anyhow = "1.0.89"
env_logger = "0.11.5"
-rustls = { version = "0.23.12", features = ["ring"] }
-clap = { version = "4.5.15", features = ["derive"] }
+rustls = { version = "0.23.13", features = ["ring"] }
+clap = { version = "4.5.18", features = ["derive"] }
rand = "0.9.0-alpha.2"
diff --git a/server/bot/src/algos/simple.rs b/server/bot/src/algos/simple.rs
index dbe8bbfe..b275b522 100644
--- a/server/bot/src/algos/simple.rs
+++ b/server/bot/src/algos/simple.rs
@@ -145,6 +145,9 @@ impl<S> Context<'_, S> {
.iter()
.filter_map(|(_, pl)| match &pl.communicate_persist {
Some((Message::Item(item), _)) => {
+ if self.game.data.item_name(*item) == "unknown-order" {
+ return None;
+ }
let pos = pl.movement.position.as_ivec2();
[IVec2::X, IVec2::Y, -IVec2::X, -IVec2::Y]
.into_iter()
diff --git a/server/client-lib/Cargo.toml b/server/client-lib/Cargo.toml
index 291c07f4..517dbba0 100644
--- a/server/client-lib/Cargo.toml
+++ b/server/client-lib/Cargo.toml
@@ -5,17 +5,17 @@ edition = "2021"
[dependencies]
hurrycurry-protocol = { path = "../protocol" }
-tungstenite = { version = "0.23.0", optional = true, features = [
+tungstenite = { version = "0.24.0", optional = true, features = [
"rustls-tls-native-roots",
] }
-tokio-tungstenite = { version = "0.23.1", optional = true, features = [
+tokio-tungstenite = { version = "0.24.0", optional = true, features = [
"rustls-tls-native-roots",
] }
-tokio = { version = "1.39.2", features = ["net", "sync"], optional = true }
-serde_json = "1.0.122"
+tokio = { version = "1.40.0", features = ["net", "sync"], optional = true }
+serde_json = "1.0.128"
bincode = "2.0.0-rc.3"
log = "0.4.22"
-anyhow = "1.0.86"
+anyhow = "1.0.89"
futures-util = { version = "0.3.30", optional = true }
[features]
diff --git a/server/discover/src/main.rs b/server/discover/src/main.rs
index 1c23de85..f1f2bb35 100644
--- a/server/discover/src/main.rs
+++ b/server/discover/src/main.rs
@@ -26,7 +26,7 @@ use hyper::{
use hyper_util::rt::TokioIo;
use log::warn;
use mdns_sd::{ServiceDaemon, ServiceEvent};
-use std::{cmp::Reverse, collections::HashMap, sync::Arc};
+use std::{cmp::Reverse, collections::HashMap, net::SocketAddr, sync::Arc};
use tokio::{net::TcpListener, spawn, sync::RwLock};
fn main() -> Result<()> {
@@ -58,7 +58,9 @@ async fn async_main() -> Result<!> {
address: service_info
.get_addresses()
.into_iter()
- .map(|a| format!("ws://{a}:{}", service_info.get_port()))
+ .map(|a| {
+ format!("ws://{}", SocketAddr::new(*a, service_info.get_port()))
+ })
.collect(),
players_online: service_info
.get_property_val_str("players")
@@ -83,7 +85,7 @@ async fn async_main() -> Result<!> {
}
});
- let listener = TcpListener::bind("127.0.0.1:27035").await?;
+ let listener = TcpListener::bind("127.0.0.1:27033").await?;
loop {
let (stream, _) = listener.accept().await?;
let entries = entries.clone();
diff --git a/server/protocol/Cargo.toml b/server/protocol/Cargo.toml
index 9c3f26e8..2a7a989c 100644
--- a/server/protocol/Cargo.toml
+++ b/server/protocol/Cargo.toml
@@ -4,6 +4,6 @@ version = "0.1.0"
edition = "2021"
[dependencies]
-serde = { version = "1.0.205", features = ["derive"] }
-glam = { version = "0.28.0", features = ["serde"] }
+serde = { version = "1.0.210", features = ["derive"] }
+glam = { version = "0.29.0", features = ["serde"] }
bincode = { version = "2.0.0-rc.3", features = ["serde", "derive"] }
diff --git a/server/registry/Cargo.toml b/server/registry/Cargo.toml
index c616174f..49f58a46 100644
--- a/server/registry/Cargo.toml
+++ b/server/registry/Cargo.toml
@@ -6,16 +6,16 @@ edition = "2021"
[dependencies]
log = "0.4.22"
env_logger = "0.11.5"
-anyhow = "1.0.86"
+anyhow = "1.0.89"
rocket = { version = "0.5.1", features = ["json"] }
-tokio = { version = "1.39.2", features = ["full"] }
+tokio = { version = "1.40.0", features = ["full"] }
serde_json = "1.0.128"
markup = "0.15.0"
serde = { version = "1.0.210", features = ["derive"] }
-tokio-tungstenite = { version = "0.23.1", features = [
+tokio-tungstenite = { version = "0.24.0", features = [
"rustls-tls-native-roots",
] }
-rustls = { version = "0.23.12", features = ["ring"] }
+rustls = { version = "0.23.13", features = ["ring"] }
hurrycurry-protocol = { path = "../protocol" }
hurrycurry-client-lib = { path = "../client-lib" }
diff --git a/server/registry/src/list.rs b/server/registry/src/list.rs
index 1c2cd4a3..5684b473 100644
--- a/server/registry/src/list.rs
+++ b/server/registry/src/list.rs
@@ -20,9 +20,13 @@ use anyhow::Result;
use hurrycurry_protocol::registry::Entry;
use rocket::{
get,
- http::MediaType,
+ http::{Header, MediaType},
request::{self, FromRequest, Outcome},
- response::content::{RawHtml, RawJson},
+ response::{
+ self,
+ content::{RawHtml, RawJson},
+ Responder,
+ },
Either, Request, State,
};
use std::sync::Arc;
@@ -32,12 +36,12 @@ use tokio::sync::RwLock;
pub(super) async fn r_list(
registry: &State<Arc<RwLock<Registry>>>,
json: AcceptJson,
-) -> Either<RawJson<Arc<str>>, RawHtml<Arc<str>>> {
- if json.0 {
+) -> Cors<Either<RawJson<Arc<str>>, RawHtml<Arc<str>>>> {
+ Cors(if json.0 {
Either::Left(RawJson(registry.read().await.json_response.clone()))
} else {
Either::Right(RawHtml(registry.read().await.html_response.clone()))
- }
+ })
}
pub(super) fn generate_json_list(entries: &[Entry]) -> Result<Arc<str>> {
@@ -100,3 +104,13 @@ impl<'r> FromRequest<'r> for AcceptJson {
})
}
}
+
+pub struct Cors<T>(pub T);
+#[rocket::async_trait]
+impl<'r, T: Responder<'r, 'static>> Responder<'r, 'static> for Cors<T> {
+ fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
+ let mut b = self.0.respond_to(req)?;
+ b.set_header(Header::new("access-control-allow-origin", "*"));
+ Ok(b)
+ }
+}
diff --git a/server/registry/src/main.rs b/server/registry/src/main.rs
index 5bb7a0a3..30fb8d66 100644
--- a/server/registry/src/main.rs
+++ b/server/registry/src/main.rs
@@ -26,7 +26,7 @@ use list::{generate_html_list, generate_json_list, r_list};
use lobby::lobby_wrapper;
use log::{error, info};
use register::r_register;
-use rocket::{get, routes, shield::Shield, Config};
+use rocket::{fairing::AdHoc, get, http::Header, routes, shield::Shield, Config};
use std::{
cmp::Reverse,
collections::HashMap,
@@ -73,6 +73,10 @@ fn main() {
})
.attach(Shield::new())
.manage(registry)
+ .attach(AdHoc::on_response("set server header", |_req, res| {
+ res.set_header(Header::new("server", "hurrycurry-registry"));
+ Box::pin(async {})
+ }))
.mount("/", routes![r_index, r_list, r_register])
.ignite()
.await
diff --git a/server/replaytool/Cargo.toml b/server/replaytool/Cargo.toml
index fb27ed4b..9d5ac20a 100644
--- a/server/replaytool/Cargo.toml
+++ b/server/replaytool/Cargo.toml
@@ -6,17 +6,17 @@ edition = "2021"
[dependencies]
log = "0.4.22"
env_logger = "0.11.5"
-anyhow = "1.0.86"
-serde = { version = "1.0.205", features = ["derive"] }
-tokio = { version = "1.39.2", features = ["full"] }
-serde_json = "1.0.122"
-tokio-tungstenite = { version = "0.23.1", features = [
+anyhow = "1.0.89"
+serde = { version = "1.0.210", features = ["derive"] }
+tokio = { version = "1.40.0", features = ["full"] }
+serde_json = "1.0.128"
+tokio-tungstenite = { version = "0.24.0", features = [
"rustls-tls-native-roots",
] }
futures-util = "0.3.30"
rand = "0.9.0-alpha.2"
-clap = { version = "4.5.15", features = ["derive"] }
+clap = { version = "4.5.18", features = ["derive"] }
async-compression = { version = "0.4.12", features = ["zstd", "tokio"] }
-rustls = { version = "0.23.12", features = ["ring"] }
+rustls = { version = "0.23.13", features = ["ring"] }
hurrycurry-protocol = { path = "../protocol" }
diff --git a/server/src/commands.rs b/server/src/commands.rs
index 06659161..478d88e3 100644
--- a/server/src/commands.rs
+++ b/server/src/commands.rs
@@ -70,7 +70,7 @@ enum Command {
},
/// Reload the resource index
ReloadIndex,
- #[clap(alias = "summon-bot", alias = "spawn-bot")]
+ #[clap(alias = "summon", alias = "bot")]
CreateBot {
algo: String,
name: Option<String>,
diff --git a/server/src/entity/customers.rs b/server/src/entity/customers.rs
index bb423e58..a9ddb6f1 100644
--- a/server/src/entity/customers.rs
+++ b/server/src/entity/customers.rs
@@ -54,7 +54,7 @@ impl Entity for Customers {
self.spawn_cooldown = 10. + random::<f32>() * 10.;
let bot = BotDriver::new(
"".to_string(),
- random::<u16>() as i32,
+ -1 - random::<u16>() as i32,
PlayerClass::Customer,
Customer::default(),
);
diff --git a/server/src/entity/tutorial.rs b/server/src/entity/tutorial.rs
index 3189687b..1d28f13e 100644
--- a/server/src/entity/tutorial.rs
+++ b/server/src/entity/tutorial.rs
@@ -211,6 +211,13 @@ impl<'a> StepContext<'a> {
}
}
fn fulfil_demand(&mut self, item: ItemIndex) -> Result<(), (Option<IVec2>, Message)> {
+ if self.ent.game.data.item_name(item) == "unknown-order" {
+ return if let Some(pos) = self.find_demand(item) {
+ Err((Some(pos), trm!("s.tutorial.accept_order")))
+ } else {
+ Ok(())
+ };
+ }
if !*self.had_aquired_target {
self.prevent_burning()?;
self.aquire_item(item)?;
@@ -264,7 +271,16 @@ impl<'a> StepContext<'a> {
} => {
let apos = self.aquire_placed_item(*a)?;
self.aquire_item(*b)?;
- return Err((Some(apos), trm!("s.tutorial.interact")));
+ let aname = self.ent.game.data.item_name(*a);
+ let bname = self.ent.game.data.item_name(*b);
+ return Err((
+ Some(apos),
+ if aname.starts_with("plate:") || bname.starts_with("plate:") {
+ trm!("s.tutorial.interact_plate")
+ } else {
+ trm!("s.tutorial.interact")
+ },
+ ));
}
Recipe::Instant {
tile: None,
@@ -291,7 +307,11 @@ impl<'a> StepContext<'a> {
self.aquire_item(*input)?;
return Err((
Some(pos),
- trm!("s.tutorial.active", s = format!("{:.01}", 1. / speed)),
+ if self.ent.game.data.tile_name(*tile) == "cuttingboard" {
+ trm!("s.tutorial.active_cuttingboard")
+ } else {
+ trm!("s.tutorial.active", s = format!("{:.01}", 1. / speed))
+ },
));
}
}
diff --git a/server/src/network/register.rs b/server/src/network/register.rs
index 8e0464fa..f75b8639 100644
--- a/server/src/network/register.rs
+++ b/server/src/network/register.rs
@@ -48,8 +48,8 @@ impl Register {
port: u16,
register_uri: Option<String>,
state: Arc<RwLock<Server>>,
- no6: bool,
no4: bool,
+ no6: bool,
) -> Self {
Self {
name,