diff --git a/godot/Scenes/Characters/player.tscn b/godot/Scenes/Characters/player.tscn index cc90c2c..3a2f9d3 100644 --- a/godot/Scenes/Characters/player.tscn +++ b/godot/Scenes/Characters/player.tscn @@ -3750,15 +3750,6 @@ skin = SubResource("Skin_l3wpu") transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.908729, 0) shape = SubResource("CapsuleShape3D_mm42w") -[node name="SpringArmPivot" type="SpringArmPivot" parent="."] - -[node name="SpringArm3D" type="SpringArm3D" parent="SpringArmPivot"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.31667, 0) -spring_length = 2.0 -margin = 0.2 - -[node name="Camera3D" type="Camera3D" parent="SpringArmPivot/SpringArm3D"] - [node name="AnimationPlayer" type="AnimationPlayer" parent="."] root_node = NodePath("../Mesh") libraries = { diff --git a/godot/Scenes/Levels/world.tscn b/godot/Scenes/Levels/world.tscn index 8413269..013e2b1 100644 --- a/godot/Scenes/Levels/world.tscn +++ b/godot/Scenes/Levels/world.tscn @@ -4,7 +4,7 @@ [ext_resource type="Texture2D" path="res://Assets/Textures/Black.png" id="2_fkwcn"] [ext_resource type="Texture2D" path="res://Assets/Textures/Orange.png" id="3_ux02w"] [ext_resource type="Texture2D" path="res://Assets/Textures/Green.png" id="4_wp15n"] -[ext_resource type="PackedScene" uid="uid://d38w4ae3qj0k4" path="res://Scenes/Characters/first_person_player.tscn" id="5_8ctht"] +[ext_resource type="PackedScene" path="res://Scenes/Characters/first_person_player.tscn" id="5_8ctht"] [sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_6c4vd"] panorama = ExtResource("1_mnexj") @@ -51,7 +51,7 @@ uv1_triplanar = true [sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_rit6o"] data = PackedVector3Array(-12.5, 2.5, 2.5, 2.5, -2.5, 2.5, -2.5, -2.5, 2.5, -12.5, 2.5, -2.5, -2.5, -2.5, -2.5, 2.5, -2.5, -2.5, -12.5, 2.5, 2.5, -12.5, 2.5, -2.5, 2.5, -2.5, 2.5, -12.5, 2.5, -2.5, 2.5, -2.5, -2.5, 2.5, -2.5, 2.5, -12.5, 2.5, -2.5, -12.5, 2.5, 2.5, -2.5, -2.5, -2.5, -12.5, 2.5, 2.5, -2.5, -2.5, 2.5, -2.5, -2.5, -2.5, -2.5, -2.5, 2.5, 2.5, -2.5, 2.5, -2.5, -2.5, -2.5, 2.5, -2.5, 2.5, 2.5, -2.5, -2.5, -2.5, -2.5, -2.5) -[node name="World" type="Node3D"] +[node name="World" type="World"] [node name="WorldEnvironment" type="WorldEnvironment" parent="."] environment = SubResource("Environment_ctwiv") diff --git a/godot/Scenes/Menus/mainmenu.tscn b/godot/Scenes/Menus/mainmenu.tscn index 3b4a107..11d3a9a 100644 --- a/godot/Scenes/Menus/mainmenu.tscn +++ b/godot/Scenes/Menus/mainmenu.tscn @@ -1,6 +1,8 @@ -[gd_scene format=3 uid="uid://bqfqg7xwwlxd8"] +[gd_scene load_steps=2 format=3 uid="uid://bqfqg7xwwlxd8"] -[node name="Main Menu" type="MainMenu"] +[ext_resource type="PackedScene" path="res://Scenes/Network/networking.tscn" id="1_vrong"] + +[node name="MainMenu" type="MainMenu"] anchors_preset = 8 anchor_left = 0.5 anchor_top = 0.5 @@ -39,3 +41,5 @@ text = "Create Game" layout_mode = 2 theme_override_font_sizes/font_size = 35 text = "Quit" + +[node name="Lobby" parent="." instance=ExtResource("1_vrong")] diff --git a/godot/Scenes/Network/networking.tscn b/godot/Scenes/Network/networking.tscn new file mode 100644 index 0000000..70df01d --- /dev/null +++ b/godot/Scenes/Network/networking.tscn @@ -0,0 +1,3 @@ +[gd_scene format=3 uid="uid://clafls1xhludi"] + +[node name="Lobby" type="Lobby"] diff --git a/godot/Scenes/main.tscn b/godot/Scenes/main.tscn new file mode 100644 index 0000000..0a6779b --- /dev/null +++ b/godot/Scenes/main.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=3 format=3 uid="uid://4jt0v2b2l4rt"] + +[ext_resource type="PackedScene" path="res://Scenes/Network/networking.tscn" id="1_06ibn"] +[ext_resource type="PackedScene" path="res://Scenes/Menus/mainmenu.tscn" id="2_lavg1"] + +[node name="Main" type="Main"] + +[node name="Lobby" parent="." instance=ExtResource("1_06ibn")] + +[node name="MainMenu" parent="." instance=ExtResource("2_lavg1")] + +[connection signal="local_player_connected" from="Lobby" to="MainMenu" method="on_connected"] +[connection signal="change_scene" from="MainMenu" to="." method="change_scene"] +[connection signal="create_game" from="MainMenu" to="Lobby" method="create_game"] +[connection signal="join_game" from="MainMenu" to="Lobby" method="join_game"] diff --git a/godot/project.godot b/godot/project.godot index c562b59..b91f2c6 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -11,7 +11,7 @@ config_version=5 [application] config/name="Blitz3" -run/main_scene="res://Scenes/Levels/world.tscn" +run/main_scene="res://Scenes/main.tscn" config/features=PackedStringArray("4.2", "Forward Plus") config/icon="res://icon.svg" diff --git a/src/Lobby.cpp b/src/Lobby.cpp new file mode 100644 index 0000000..44eb2d3 --- /dev/null +++ b/src/Lobby.cpp @@ -0,0 +1,96 @@ +#include "Lobby.h" + +#include +#include + +using namespace godot; + +namespace blitz { + +void Lobby::_bind_methods() { + godot::ClassDB::bind_method(godot::D_METHOD("create_game", "port", "dedicated"), &Lobby::CreateGame); + godot::ClassDB::bind_method(godot::D_METHOD("join_game", "address", "port"), &Lobby::JoinGame); + ADD_SIGNAL(MethodInfo("player_connected", PropertyInfo(Variant::INT, "peer_id"), PropertyInfo(Variant::STRING, "player_name"))); + ADD_SIGNAL(MethodInfo("player_disconnected", PropertyInfo(Variant::INT, "peer_id"))); + ADD_SIGNAL(MethodInfo("server_disconnected")); + ADD_SIGNAL(MethodInfo("local_player_connected")); +} + +Lobby::Lobby() {} + +Lobby::~Lobby() {} + +void Lobby::_ready() { + get_multiplayer()->connect("peer_connected", callable_mp(this, &Lobby::OnPlayerConnected)); + get_multiplayer()->connect("peer_disconnected", callable_mp(this, &Lobby::OnPlayerDisconnected)); + get_multiplayer()->connect("connected_to_server", callable_mp(this, &Lobby::OnConnectOk)); + get_multiplayer()->connect("connection_failed", callable_mp(this, &Lobby::OnConnectFail)); + get_multiplayer()->connect("server_disconnected", callable_mp(this, &Lobby::OnServerDisconnected)); +} + +Error Lobby::JoinGame(const String& a_Address, uint16_t a_Port) { + auto* peer = memnew(ENetMultiplayerPeer); + Error error = peer->create_client(a_Address, a_Port); + if (error) + return error; + + get_multiplayer()->set_multiplayer_peer(peer); + return Error::OK; +} + +Error Lobby::CreateGame(uint16_t a_Port, bool a_Dedicated) { + auto* peer = memnew(ENetMultiplayerPeer); + Error error = peer->create_server(a_Port); + if (error) + return error; + + get_multiplayer()->set_multiplayer_peer(peer); + + if (!a_Dedicated) { + emit_signal("local_player_connected"); + String playerName = "Imtheadmin"; + m_Players.insert({get_multiplayer()->get_unique_id(), {playerName}}); + emit_signal("player_connected", get_multiplayer()->get_unique_id(), playerName); + } + + return Error::OK; +} + +void Lobby::Shutdown() { + get_multiplayer()->set_multiplayer_peer(nullptr); + m_Players.clear(); +} + +void Lobby::OnPlayerConnected(int32_t a_PeerId) { + emit_signal("player_connected", a_PeerId, "anonymous"); + if (get_multiplayer()->is_server()) { + // TODO: broadcast player join + } +} + +void Lobby::OnPlayerDisconnected(int32_t a_PeerId) { + m_Players.erase(a_PeerId); + emit_signal("player_disconnected", a_PeerId); + if (get_multiplayer()->is_server()) { + // TODO: broadcast player leave + } +} + +void Lobby::OnConnectOk() { + int32_t peerId = get_multiplayer()->get_unique_id(); + PlayerInfo localPlayer{"MonPseudo"}; + m_Players.insert({peerId, localPlayer}); + emit_signal("player_connected", peerId, localPlayer.m_Name); + emit_signal("local_player_connected"); +} + +void Lobby::OnConnectFail() { + Shutdown(); +} + +void Lobby::OnServerDisconnected() { + Shutdown(); + emit_signal("server_disconnected"); +} + +} // namespace blitz \ No newline at end of file diff --git a/src/Lobby.h b/src/Lobby.h new file mode 100644 index 0000000..4d97307 --- /dev/null +++ b/src/Lobby.h @@ -0,0 +1,35 @@ +#pragma once + +#include "PlayerInfo.h" +#include +#include + +namespace blitz { + +class Lobby : public godot::Node { + GDCLASS(Lobby, godot::Node) + protected: + static void _bind_methods(); + + public: + Lobby(); + ~Lobby(); + + void _ready() override; + + godot::Error JoinGame(const godot::String& a_Address, uint16_t a_Port); + godot::Error CreateGame(uint16_t a_Port, bool a_Dedicated = false); + + void Shutdown(); + + private: + std::map m_Players; + + void OnPlayerConnected(int32_t a_PeerId); + void OnPlayerDisconnected(int32_t a_PeerId); + void OnConnectOk(); + void OnConnectFail(); + void OnServerDisconnected(); +}; + +} // namespace blitz \ No newline at end of file diff --git a/src/Main.cpp b/src/Main.cpp new file mode 100644 index 0000000..1538425 --- /dev/null +++ b/src/Main.cpp @@ -0,0 +1,40 @@ +#include "Main.h" + +#include +#include +#include +#include +#include +#include + +#include "Lobby.h" +#include "World.h" + +using namespace godot; + +namespace blitz { + +static constexpr char MainScenePath[] = "res://Scenes/Levels/world.tscn"; + +void Main::_bind_methods() { + godot::ClassDB::bind_method(godot::D_METHOD("change_scene"), &Main::ChangeScene); +} + +Main::Main() {} + +Main::~Main() {} + +void Main::ChangeScene() { + Ref sceneData = ResourceLoader::get_singleton()->load(MainScenePath); + World* world = Object::cast_to(sceneData->instantiate()); + get_parent()->add_child(world); + + Lobby* lobby = Object::cast_to(find_child("Lobby")); + DEV_ASSERT(lobby); + + // connect signals + lobby->connect("player_connected", callable_mp(world, &World::AddPlayer)); + lobby->connect("player_disconnected", callable_mp(world, &World::RemovePlayer)); +} + +} // namespace blitz \ No newline at end of file diff --git a/src/Main.h b/src/Main.h new file mode 100644 index 0000000..6e6bfca --- /dev/null +++ b/src/Main.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace blitz { + +class Main : public godot::Node { + GDCLASS(Main, godot::Node) + protected: + static void _bind_methods(); + + public: + Main(); + ~Main(); + + void ChangeScene(); +}; + +} // namespace blitz \ No newline at end of file diff --git a/src/MainMenu.cpp b/src/MainMenu.cpp index 20e7fc5..f1538ad 100644 --- a/src/MainMenu.cpp +++ b/src/MainMenu.cpp @@ -5,11 +5,14 @@ using namespace godot; -static constexpr char MainScenePath[] = "res://Scenes/Levels/world.tscn"; - namespace blitz { -void MainMenu::_bind_methods() {} +void MainMenu::_bind_methods() { + godot::ClassDB::bind_method(godot::D_METHOD("on_connected"), &MainMenu::OnConnected); + ADD_SIGNAL(MethodInfo("create_game", PropertyInfo(Variant::INT, "port"), PropertyInfo(Variant::BOOL, "dedicated"))); + ADD_SIGNAL(MethodInfo("join_game", PropertyInfo(Variant::STRING, "address"), PropertyInfo(Variant::INT, "port"))); + ADD_SIGNAL(MethodInfo("change_scene")); +} MainMenu::MainMenu() {} @@ -32,12 +35,17 @@ void MainMenu::_ready() { m_QuitButton->connect("pressed", callable_mp(this, &MainMenu::OnQuitPressed)); } +void MainMenu::OnConnected() { + emit_signal("change_scene"); + queue_free(); +} + void MainMenu::OnJoinPressed() { - get_tree()->change_scene_to_file(MainScenePath); + emit_signal("join_game", "localhost", 25565); } void MainMenu::OnCreatePressed() { - get_tree()->change_scene_to_file(MainScenePath); + emit_signal("create_game", 25565, false); } void MainMenu::OnQuitPressed() { diff --git a/src/MainMenu.h b/src/MainMenu.h index b6d3961..488861a 100644 --- a/src/MainMenu.h +++ b/src/MainMenu.h @@ -19,12 +19,14 @@ class MainMenu : public godot::Control { private: godot::Button* m_JoinButton; - godot::Button* m_CreateButton; - godot::Button* m_QuitButton; + godot::Button* m_CreateButton; + godot::Button* m_QuitButton; - void OnJoinPressed(); - void OnCreatePressed(); - void OnQuitPressed(); + void OnConnected(); + + void OnJoinPressed(); + void OnCreatePressed(); + void OnQuitPressed(); }; } // namespace blitz \ No newline at end of file diff --git a/src/Player.cpp b/src/Player.cpp index 1d48266..4803b58 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -23,11 +23,9 @@ Player::~Player() {} void Player::_ready() { godot::InputMap::get_singleton()->load_from_project_settings(); - m_PlayerMesh = Object::cast_to(get_child(0)); - m_SpringArmPivot = Object::cast_to(get_child(2)); - m_AnimationTree = Object::cast_to(get_child(4)); + m_PlayerMesh = Object::cast_to(find_child("Mesh")); + m_AnimationTree = Object::cast_to(find_child("AnimationTree")); DEV_ASSERT(m_PlayerMesh); - DEV_ASSERT(m_SpringArmPivot); DEV_ASSERT(m_AnimationTree); apply_floor_snap(); @@ -39,47 +37,6 @@ void Player::_physics_process(float delta) { return; - auto* Input = godot::Input::get_singleton(); - godot::Vector3 move_direction{0, 0, 0}; - move_direction.x = Input->get_action_strength("move_right") - Input->get_action_strength("move_left"); - move_direction.z = Input->get_action_strength("move_backwards") - Input->get_action_strength("move_forwards"); - move_direction = move_direction.rotated({0, 1, 0}, m_SpringArmPivot->get_rotation().y); - - godot::Vector3 newVelocity = get_velocity(); - newVelocity.y -= Gravity * delta; - set_velocity(newVelocity); - - - - if (Input->is_action_pressed("run")) - m_Speed = RunSpeed; - else - m_Speed = WalkSpeed; - - newVelocity = get_velocity(); - newVelocity.x = move_direction.x * m_Speed; - newVelocity.z = move_direction.z * m_Speed; - set_velocity(newVelocity); - - if (move_direction != godot::Vector3{0, 0, 0}) { - godot::Vector3 newRotation = m_PlayerMesh->get_rotation(); - newRotation.y = godot::UtilityFunctions::lerp_angle( - newRotation.y, godot::UtilityFunctions::atan2(get_velocity().x, get_velocity().z), LerpValue); - m_PlayerMesh->set_rotation(newRotation); - } - - bool justLanded = is_on_floor() && m_SnapVector == godot::Vector3{0, 0, 0}; - bool isJumping = is_on_floor() && Input->is_action_just_pressed("jump"); - - if (isJumping) { - newVelocity = get_velocity(); - newVelocity.y = JumpStrength; - set_velocity(newVelocity); - m_SnapVector.zero(); - } else if (justLanded) { - m_SnapVector = {0, -1, 0}; - } - apply_floor_snap(); move_and_slide(); animate(delta); diff --git a/src/Player.h b/src/Player.h index 5fdea94..d01a093 100644 --- a/src/Player.h +++ b/src/Player.h @@ -22,16 +22,9 @@ class Player : public godot::CharacterBody3D { private: godot::Node3D* m_PlayerMesh; - godot::Node3D* m_SpringArmPivot; godot::AnimationTree* m_AnimationTree; godot::Vector3 m_SnapVector; float m_Speed; - /* - @onready var player_mesh : Node3D = $Mesh -@onready var spring_arm_pivot : Node3D = $SpringArmPivot -@onready var animator : AnimationTree = $AnimationTree - - */ }; } // namespace blitz diff --git a/src/PlayerInfo.h b/src/PlayerInfo.h new file mode 100644 index 0000000..19e644f --- /dev/null +++ b/src/PlayerInfo.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace blitz { + +struct PlayerInfo { + godot::String m_Name; +}; + +} // namespace blitz diff --git a/src/World.cpp b/src/World.cpp new file mode 100644 index 0000000..a39d27e --- /dev/null +++ b/src/World.cpp @@ -0,0 +1,28 @@ +#include "World.h" + +#include + +using namespace godot; + +namespace blitz { + +void World::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_player", "id", "name"), &World::AddPlayer); + ClassDB::bind_method(D_METHOD("remove_player", "id"), &World::RemovePlayer); +} + +World::World() {} + +World::~World() {} + +void World::_process(float delta) { + // do update here +} + +void World::AddPlayer(int32_t a_PlayerId, String a_PlayerName) { + UtilityFunctions::print_rich("New player joined ! Id : ", a_PlayerId, ", Name : ", a_PlayerName); +} + +void World::RemovePlayer(int32_t a_PlayerId) {} + +} // namespace blitz \ No newline at end of file diff --git a/src/World.h b/src/World.h new file mode 100644 index 0000000..705d505 --- /dev/null +++ b/src/World.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace blitz { +class World : public godot::Node3D { + GDCLASS(World, godot::Node3D) + protected: + static void _bind_methods(); + + public: + World(); + ~World(); + + void _process(float delta); + + void AddPlayer(int32_t a_PlayerId, godot::String a_PlayerName); + void RemovePlayer(int32_t a_PlayerId); +}; +} // namespace blitz \ No newline at end of file diff --git a/src/register_types.cpp b/src/register_types.cpp index f852032..acb18e6 100644 --- a/src/register_types.cpp +++ b/src/register_types.cpp @@ -1,9 +1,12 @@ #include "register_types.h" #include "FirstPersonPlayer.h" +#include "Lobby.h" +#include "Main.h" +#include "MainMenu.h" #include "Player.h" #include "SpringArmPivot.h" -#include "MainMenu.h" +#include "World.h" #include #include @@ -16,6 +19,9 @@ static void RegisterClasses() { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); } void initialize_example_module(ModuleInitializationLevel p_level) {