Init commit

This commit is contained in:
2025-02-06 09:56:39 +01:00
commit 8f61ab6c6b
48 changed files with 5511 additions and 0 deletions

View File

@ -0,0 +1 @@

2
rust/src/globals.rs Normal file
View File

@ -0,0 +1,2 @@
pub(crate) const DEFAULT_JUMP_VELOCITY: f32 = 4.5;
pub(crate) const DEFAULT_CHARACTER_SPEED: f32 = 5.0;

10
rust/src/lib.rs Normal file
View File

@ -0,0 +1,10 @@
use godot::prelude::*;
struct MyExtension;
//mod game_root;
mod player;
//mod server;
mod globals;
#[gdextension]
unsafe impl ExtensionLibrary for MyExtension {}

View File

@ -0,0 +1 @@

2
rust/src/player/mod.rs Normal file
View File

@ -0,0 +1,2 @@
mod client_node;
mod server_node;

View File

@ -0,0 +1,119 @@
use godot::classes::{CharacterBody3D, ICharacterBody3D};
use godot::obj::WithBaseField;
use godot::prelude::*;
use crate::globals;
#[derive(GodotClass)]
#[class(base=CharacterBody3D)]
struct PlayerPlaceholder {
base: Base<CharacterBody3D>,
#[export]
owner_id: i32,
jumping: bool,
input_direction: Vector2,
}
#[godot_api]
impl ICharacterBody3D for PlayerPlaceholder {
fn init(base: Base<CharacterBody3D>) -> Self {
Self {
owner_id: 0,
base,
jumping: false,
input_direction: Vector2::new(0.0, 0.0),
}
}
fn ready(&mut self) {
if let Some(mut multiplayer) = self.base().get_multiplayer() {
self.owner_id = multiplayer.get_unique_id();
}
}
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 = globals::DEFAULT_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 * globals::DEFAULT_CHARACTER_SPEED,
self.base().get_velocity().y,
direction.z * globals::DEFAULT_CHARACTER_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), globals::DEFAULT_CHARACTER_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 PlayerPlaceholder {
#[rpc(any_peer, call_local, unreliable)]
fn jump(&mut self) {
self.jumping = true
}
#[rpc(any_peer, call_local, unreliable)]
fn set_input_direction(&mut self, new_input_direction: Vector2) {
self.input_direction = new_input_direction;
}
#[rpc(any_peer, call_local, unreliable)]
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);
}
#[rpc(any_peer, call_local, unreliable)]
fn set_rotation_x(&mut self, x: f32) {
let mut camera_mount = self.base().get_node_as::<Node3D>("BulletStartingPoint");
let mut new_rotation = camera_mount.get_rotation();
new_rotation.x = x;
camera_mount.set_rotation(new_rotation);
}
#[rpc(any_peer, call_local, unreliable_ordered)]
fn shoot(&mut self) {
let bullet_starting_poing = match self.base().find_child("BulletStartingPoint") {
Some(node) => node,
None => return,
};
let casted_bullet_node = bullet_starting_poing.cast::<Node3D>();
let mut map = match self.base().find_parent("Map") {
Some(map) => map,
None => return,
};
let args = &[
casted_bullet_node.to_variant(),
200.to_variant(),
50.to_variant(),
];
map.call("spawn_bullet", args);
}
}

View File

@ -0,0 +1,80 @@
use std::collections::HashMap;
use godot::classes::{ENetMultiplayerPeer, ICharacterBody3D, INode, Node};
use godot::meta::ParamType;
use godot::obj::{NewGd, WithBaseField};
use godot::prelude::*;
use crate::globals;
use super::player_data::PlayerData;
#[derive(GodotClass)]
#[class(base=Node)]
struct GameServer {
base: Base<Node>,
#[export]
port: i32,
#[export]
player_limit: i32,
#[export]
current_map: GString,
#[export]
current_player_data: Gd<PlayerData>,
#[export]
pub(crate) players: Dictionary
}
#[godot_api]
impl INode for GameServer {
fn init(base: Base<Node>) -> Self {
let players = Dictionary::new();
Self {
base,
players,
port: 27015,
player_limit: 10,
current_map: "lowpoly_tdm_2".into(),
current_player_data: PlayerData::new_gd(),
}
}
fn ready(&mut self) {
if let Some(multiplayer) = self.base().get_multiplayer() {
let on_connected = multiplayer.callable("peer_connected");
self.base_mut().connect("on_player_connected", &on_connected);
}
}
}
#[godot_api]
impl GameServer {
// Signals
#[func]
fn on_player_connected(&mut self, id: i32) {
godot_print!("test");
}
// Main methods
#[func]
fn create_server(&mut self, server_only: bool) {
let mut peer = ENetMultiplayerPeer::new_gd();
let server = peer.create_server_ex(self.port)
.max_clients(self.player_limit)
.done();
if let Some(mut multiplayer) = self.base().get_multiplayer() {
let id = multiplayer.get_unique_id();
multiplayer.set_multiplayer_peer(&peer);
let player = PlayerData::new_gd();
self.players.set(id, player);
}
}
#[func]
fn join_server(&mut self, ip: GString, port: i32) {
let mut peer = ENetMultiplayerPeer::new_gd();
peer.create_client(&ip, port);
if let Some(mut multiplayer) = self.base().get_multiplayer() {
multiplayer.set_multiplayer_peer(&peer);
}
}
}

2
rust/src/server/mod.rs Normal file
View File

@ -0,0 +1,2 @@
mod game_server;
mod player_data;

View File

@ -0,0 +1,21 @@
use godot::{classes::{IResource, Resource}, obj::{Base, NoBase}, prelude::godot_api};
use godot::prelude::*;
#[derive(GodotClass)]
#[class(base=Resource)]
pub(crate) struct PlayerData {
base: Base<Resource>,
#[export]
pub(crate) id: i32,
#[export]
pub(crate) username: GString,
}
#[godot_api]
impl IResource for PlayerData {
fn init(base: Base<Resource>) -> Self {
let id = 0;
let username = "";
Self { base, id, username: username.into() }
}
}