diff --git a/.gdextension b/.gdextension new file mode 100644 index 0000000..e69de29 diff --git a/.gdignore b/.gdignore index 8c6a3f5..3a48128 100644 --- a/.gdignore +++ b/.gdignore @@ -1,2 +1,3 @@ Containerfile helm +rust/src diff --git a/.gitignore b/.gitignore index 4709183..0ca4e28 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ # Godot 4+ specific ignores .godot/ +rust/target diff --git a/Containerfile b/Containerfile index 9e48efc..d57449d 100644 --- a/Containerfile +++ b/Containerfile @@ -1,3 +1,10 @@ +FROM rust:1.84.1 AS lib_builder +RUN apt-get update -y && apt-get install -y gcc musl-dev build-essential pkg-config cmake +RUN rustup toolchain install stable +WORKDIR /src +COPY rust/ . +RUN cargo build + FROM ghcr.io/allanger/dumb-downloader as dudo RUN apt-get update -y && apt-get install unzip -y ENV RUST_LOG=info @@ -18,6 +25,7 @@ FROM ubuntu as builder RUN apt-get update -y && apt-get install fontconfig -y WORKDIR /src COPY --from=dudo /out/godot /usr/bin/godot +COPY --from=lib_builder /src/target/debug/libopen_strike_2.so /src/rust/target/debug/libopen_strike_2.so RUN mkdir -p /root/.local/share/godot/export_templates/4.3.stable/ COPY --from=dudo /out/templates /root/.local/share/godot/export_templates/4.3.stable COPY . . diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 0000000..08c7816 --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,265 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "gdextension-api" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af8707eca996b28193b772a4a9a28a97364bb93c97e3c313542e812f2963fb93" + +[[package]] +name = "gensym" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913dce4c5f06c2ea40fc178c06f777ac89fc6b1383e90c254fafb1abe4ba3c82" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "uuid", +] + +[[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 = "glam" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94" + +[[package]] +name = "godot" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6985eb6c22a0370c40d67db1f225f62222a2e04966f76d0beb53245e745744fa" +dependencies = [ + "godot-core", + "godot-macros", +] + +[[package]] +name = "godot-bindings" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77d85815de344b419513c9854b82c49aad45c7dd9fa4fcc10302aaf6ce6e07c7" +dependencies = [ + "gdextension-api", +] + +[[package]] +name = "godot-cell" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4750f0da2c2286f8a0f1e2b0aeb5adb2178251086119e1a96186c34cd8857ba1" + +[[package]] +name = "godot-codegen" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd9382da869c3e5f4ba9614f43157bb96f5acf3d1f8341bc25147b7aeebd49a" +dependencies = [ + "godot-bindings", + "heck", + "nanoserde", + "proc-macro2", + "quote", + "regex", +] + +[[package]] +name = "godot-core" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d014ea57227d84955d9db7bba53654e5e9040f3b5a41d6aad370707cad5b7a" +dependencies = [ + "glam", + "godot-bindings", + "godot-cell", + "godot-codegen", + "godot-ffi", +] + +[[package]] +name = "godot-ffi" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a93bc8ea912fc629cc7c6ad889f919e99b4e7f32cd912cc65b9be2a986dc6eb" +dependencies = [ + "gensym", + "godot-bindings", + "godot-codegen", + "libc", + "paste", +] + +[[package]] +name = "godot-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b16a49485735010c107030dc2e9fa8701fb3bf45194e34b14d1305ad5a8b4f" +dependencies = [ + "godot-bindings", + "proc-macro2", + "quote", + "venial", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "nanoserde" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de9cf844ab1e25a0353525bd74cb889843a6215fa4a0d156fd446f4857a1b99" +dependencies = [ + "nanoserde-derive", +] + +[[package]] +name = "nanoserde-derive" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e943b2c21337b7e3ec6678500687cdc741b7639ad457f234693352075c082204" + +[[package]] +name = "open-strike-2" +version = "0.1.0" +dependencies = [ + "godot", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "syn" +version = "2.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" + +[[package]] +name = "uuid" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" +dependencies = [ + "getrandom", +] + +[[package]] +name = "venial" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6816bc32f30bf8dd1b3adb04de8406c7bf187d2f923bd9e4c0b99365d012613f" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 0000000..f62c96c --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "open-strike-2" +version = "0.1.0" +edition = "2021" + +[dependencies] +godot = "0.2.3" + +[lib] +crate-type = ["cdylib"] diff --git a/rust/src/lib.rs b/rust/src/lib.rs new file mode 100644 index 0000000..e09e0b7 --- /dev/null +++ b/rust/src/lib.rs @@ -0,0 +1,31 @@ +use godot::prelude::*; +use godot::classes::Sprite2D; +use godot::classes::ISprite2D; +struct MyExtension; + +mod player; + +#[gdextension] +unsafe impl ExtensionLibrary for MyExtension {} + +#[derive(GodotClass)] +#[class(base=Sprite2D)] +struct Player { + speed: f64, + angular_speed: f64, + + base: Base +} + +#[godot_api] +impl ISprite2D for Player { + fn init(base: Base) -> Self { + godot_print!("Hello, world!"); // Prints to the Godot console + + Self { + speed: 400.0, + angular_speed: std::f64::consts::PI, + base, + } + } +} diff --git a/rust/src/player/client_node.rs b/rust/src/player/client_node.rs new file mode 100644 index 0000000..e69de29 diff --git a/rust/src/player/mod.rs b/rust/src/player/mod.rs new file mode 100644 index 0000000..76c508a --- /dev/null +++ b/rust/src/player/mod.rs @@ -0,0 +1,2 @@ +mod server_node; +mod client_node; diff --git a/rust/src/player/server_node.rs b/rust/src/player/server_node.rs new file mode 100644 index 0000000..160e114 --- /dev/null +++ b/rust/src/player/server_node.rs @@ -0,0 +1,94 @@ +use godot::classes::{CharacterBody3D, ICharacterBody3D}; +use godot::obj::WithBaseField; +use godot::prelude::*; + +#[derive(GodotClass)] +#[class(base=CharacterBody3D)] +struct PlayerServerNode { + base: Base, + jumping: bool, + input_direction: Vector2, + input_rotation: Vector3, +} + +const JUMP_VELOCITY: f32 = 4.5; +const SPEED: f32 = 5.0; + +#[godot_api] +impl ICharacterBody3D for PlayerServerNode{ + fn init(base: Base) -> Self { + Self { + base, + jumping: false, + input_direction: Vector2::new(0.0, 0.0), + input_rotation: Vector3::new(0.0, 0.0, 0.0), + } + } + + fn ready(&mut self) {} + + fn physics_process(&mut self, delta: f64) { + if !self.base().is_on_floor() { + let new_gravity = self.base().get_gravity() * delta as f32; + let new_velocity = self.base().get_velocity() + new_gravity; + self.base_mut().set_velocity(new_velocity); + } + + if self.base().is_on_floor() && self.jumping { + let mut new_velocity = self.base().get_velocity(); + new_velocity.y = JUMP_VELOCITY; + self.base_mut().set_velocity(new_velocity); + } + self.jumping = false; + + if self.base().is_on_floor() { + let direction = self.base().get_transform().basis * Vector3::new(self.input_direction.x, 0.0, self.input_direction.y); + if direction.length() > 0.0 { + let direction = direction.normalized(); + let new_velocity = Vector3::new( + direction.x * SPEED, + self.base().get_velocity().y, + direction.z * SPEED, + ); + self.base_mut().set_velocity(new_velocity); + } else { + let moved = self.base().get_velocity().clone().move_toward(Vector3::new(0.0, 0.0, 0.0), SPEED); + let new_velocity = Vector3::new( + moved.x, + self.base().get_velocity().y, + moved.z, + ); + self.base_mut().set_velocity(new_velocity); + } + } + + self.base_mut().move_and_slide(); + } +} + +#[godot_api] +impl PlayerServerNode { + #[rpc(any_peer, call_local, unreliable_ordered)] + fn jump(&mut self) { + self.jumping = true + } + + #[rpc(any_peer, call_local, unreliable_ordered)] + fn set_input_direction(&mut self, new_input_direction: Vector2) { + self.input_direction = new_input_direction; + } + + #[rpc(any_peer, call_local, unreliable_ordered)] + fn set_rotation_x(&mut self, x: f32) { + let mut new_rotation = self.base().get_rotation(); + new_rotation.x = x; + self.base_mut().set_rotation(new_rotation); + } + + #[rpc(any_peer, call_local, unreliable_ordered)] + fn set_rotation_y(&mut self, y: f32) { + let mut new_rotation = self.base().get_rotation(); + new_rotation.y = y; + self.base_mut().set_rotation(new_rotation); + } +} diff --git a/rust_bindings.gdextension b/rust_bindings.gdextension new file mode 100644 index 0000000..62184d8 --- /dev/null +++ b/rust_bindings.gdextension @@ -0,0 +1,14 @@ +[configuration] +entry_symbol = "gdext_rust_init" +compatibility_minimum = 4.1 +reloadable = true + +[libraries] +linux.debug.x86_64 = "res://rust/target/debug/libopen_strike_2.so" +linux.release.x86_64 = "res://rust/target/release/libopen_strike_2.so" +windows.debug.x86_64 = "res://rust/target/debug/open_strike_2.dll" +windows.release.x86_64 = "res://rust/target/release/open_strike_2.dll" +macos.debug = "res://rust/target/debug/libopen_strike_2.dylib" +macos.release = "res://rust/target/release/libopen_strike_2.dylib" +macos.debug.arm64 = "res://rust/target/debug/libopen_strike_2.dylib" +macos.release.arm64 = "res://rust/target/release/libopen_strike_2.dylib" diff --git a/scenes/player/placeholder.gd b/scenes/player/placeholder.gd index 53c0424..6a7dcb8 100644 --- a/scenes/player/placeholder.gd +++ b/scenes/player/placeholder.gd @@ -5,7 +5,7 @@ class_name PlayerPlaceholder @export var initial_position: Vector3 = Vector3(0, 0, 0) # -- Components @onready var client_node: CharacterBody3D = $PlayerControlledNode -@onready var server_node: CharacterBody3D = $ServerControlledNode +@onready var server_node: PlayerServerNode = $ServerControlledNode @export var character_speed: int = 5 @@ -16,6 +16,7 @@ func _ready() -> void: client_node.set_multiplayer_authority(owner_id) $PlayerControlledNode/CameraMount.set_multiplayer_authority(owner_id) switch_players_camera.rpc_id(owner_id) + server_node.global_position = initial_position client_node.global_position = server_node.global_position client_node.rotation.y = server_node.rotation.y client_node.rotation.x = server_node.rotation.x @@ -25,7 +26,8 @@ func _ready() -> void: if owner_id != multiplayer.get_unique_id(): client_node.queue_free() else: - client_node._add_legs_to_first_view() + pass + #client_node._add_legs_to_first_view() # Called every frame. 'delta' is the elapsed time since the previous frame. diff --git a/scenes/player/placeholder.tscn b/scenes/player/placeholder.tscn index 604adeb..00b76bf 100644 --- a/scenes/player/placeholder.tscn +++ b/scenes/player/placeholder.tscn @@ -101,7 +101,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.786919, 0) shape = SubResource("CapsuleShape3D_taqso") [node name="CameraMount" type="Node3D" parent="PlayerControlledNode"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.29568, -0.340905) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.29568, -0.412934) [node name="Camera3D" type="Camera3D" parent="PlayerControlledNode/CameraMount"] cull_mask = 524287 @@ -194,21 +194,31 @@ collide_with_areas = true [node name="Node3D" type="Node3D" parent="PlayerControlledNode"] -[node name="ServerControlledNode" type="CharacterBody3D" parent="."] +[node name="ServerControlledNodeBak" type="CharacterBody3D" parent="."] collision_layer = 4 script = ExtResource("3_f1bhn") -[node name="CollisionShape3D" type="CollisionShape3D" parent="ServerControlledNode"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.786919, 0) -shape = SubResource("CapsuleShape3D_taqso") - -[node name="Dummy" parent="ServerControlledNode" instance=ExtResource("6_e3cnh")] +[node name="Dummy" parent="ServerControlledNodeBak" instance=ExtResource("6_e3cnh")] visible = false +[node name="CollisionShape3D" type="CollisionShape3D" parent="ServerControlledNodeBak"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.57384, 0) +shape = SubResource("CapsuleShape3D_taqso") + [node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."] replication_config = SubResource("SceneReplicationConfig_7vlrn") [node name="Timer" type="Timer" parent="."] wait_time = 0.1 +[node name="ServerControlledNode" type="PlayerServerNode" parent="."] +collision_layer = 4 + +[node name="CollisionShape3D" type="CollisionShape3D" parent="ServerControlledNode"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.786919, 0) +shape = SubResource("CapsuleShape3D_taqso") + +[node name="CSGBox3D" type="CSGBox3D" parent="ServerControlledNode"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.47058, 0) + [connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"] diff --git a/scenes/player/player_input_controller.gd b/scenes/player/player_input_controller.gd index 2baa89e..9b39e57 100644 --- a/scenes/player/player_input_controller.gd +++ b/scenes/player/player_input_controller.gd @@ -54,10 +54,11 @@ func _input(event): camera_mount.rotation.x = clamp(camera_mount.rotation.x - look_dir.y * camera_sens * 1.0, -1.5, 1.5) server_node.set_rotation_y.rpc_id(1, rotation.y) server_node.set_rotation_x.rpc_id(1, rotation.x) + #server_node.set_input_direction.rpc_id(1, rotation.x, rotation.y) -@onready var server_node: ServerControlledPlayer = $"../ServerControlledNode" +@onready var server_node: PlayerServerNode = $"../ServerControlledNode" # Called every frame. 'delta' is the elapsed time since the previous frame. -func _process(delta: float) -> void: +func _physics_process(delta: float) -> void: if multiplayer.get_unique_id() == get_multiplayer_authority(): if !paused: Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) @@ -75,13 +76,14 @@ func _process(delta: float) -> void: var direction := (transform.basis * Vector3(input_direction.x, 0, input_direction.y)).normalized() if is_on_floor(): if direction: - first_view_legs_anim.play("Run Forward") + #first_view_legs_anim.play("Run Forward") gun_mount_anim.play("move") velocity.x = direction.x * placeholder.character_speed velocity.z = direction.z * placeholder.character_speed else: velocity.x = move_toward(velocity.x, 0, placeholder.character_speed) velocity.z = move_toward(velocity.z, 0, placeholder.character_speed) +func _process(delta: float) -> void: move_and_slide() diff --git a/scenes/player/server_player_controller.gd b/scenes/player/server_player_controller.gd index 4b64b43..0a41285 100644 --- a/scenes/player/server_player_controller.gd +++ b/scenes/player/server_player_controller.gd @@ -3,7 +3,8 @@ extends CharacterBody3D const JUMP_VELOCITY = 4.5 func _ready() -> void: - global_position = $"..".initial_position + pass + @export_category("ServerControlledPlayer") @onready var placeholder: Node3D = $'..' @@ -20,13 +21,14 @@ func set_rotation_y(new_rotation_y: float): @rpc("call_local", "any_peer", "unreliable_ordered") func set_rotation_x(new_rotation_x: float): - $"..".rotation.x = new_rotation_x + rotation.x = new_rotation_x + @rpc("call_local", "any_peer", "unreliable_ordered") func jump(): jumping = true var jumping := false -func _physics_process(delta: float) -> void: +func _process(delta: float) -> void: if not is_on_floor(): velocity += get_gravity() * delta if is_on_floor() && jumping: @@ -41,4 +43,6 @@ func _physics_process(delta: float) -> void: else: velocity.x = move_toward(velocity.x, 0, placeholder.character_speed) velocity.z = move_toward(velocity.z, 0, placeholder.character_speed) + +func _physics_process(delta: float) -> void: move_and_slide()