Compare commits

..

No commits in common. "d251973dd3df9430bcc4e9f865aa7161f8a97130" and "b93eded960a4f18e66aedb53af1ec1771b0c9eae" have entirely different histories.

16 changed files with 49 additions and 585 deletions

View File

@ -1,7 +0,0 @@
[gd_resource type="Map" format=3 uid="uid://b4rw48yjf7q3q"]
[ext_resource type="PackedScene" uid="uid://lahirbqfppvw" path="res://scenes/main.tscn" id="1_k5804"]
[resource]
name = "Default Map"
scene = ExtResource("1_k5804")

View File

@ -1,7 +0,0 @@
[gd_resource type="Map" format=3 uid="uid://crti664evgfmj"]
[ext_resource type="PackedScene" uid="uid://lahirbqfppvw" path="res://scenes/main.tscn" id="1_gr7ev"]
[resource]
name = "Default Map 2"
scene = ExtResource("1_gr7ev")

View File

@ -34,15 +34,6 @@ project/assembly_name="QuakeBall"
naming/node_name_casing=2
[input]
toggle_cli={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":167,"key_label":0,"unicode":167,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194332,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
[physics]
3d/physics_engine="Jolt Physics"

View File

@ -1,7 +1,6 @@
[gd_scene format=3 uid="uid://bsb6asp5o35w3"]
[node name="canvas_layer" type="CanvasLayer" unique_id=1517655401]
layer = 10
[node name="command_line_panel" type="CommandLinePanel" parent="." unique_id=2077938969 node_paths=PackedStringArray("input_field", "text_field", "scroll_container")]
input_field = NodePath("input_field")
@ -9,10 +8,7 @@ text_field = NodePath("scroll_container/text_field")
scroll_container = NodePath("scroll_container")
anchors_preset = 10
anchor_right = 1.0
offset_left = 1.0
offset_top = -344.0
offset_right = 1.0
offset_bottom = -37.0
offset_bottom = 307.0
grow_horizontal = 2
[node name="input_field" type="TextEdit" parent="command_line_panel" unique_id=2095748573]
@ -22,8 +18,6 @@ anchor_right = 1.0
offset_top = 307.0
offset_bottom = 342.0
grow_horizontal = 2
editable = false
metadata/_edit_lock_ = true
[node name="scroll_container" type="ScrollContainer" parent="command_line_panel" unique_id=1922272461]
custom_minimum_size = Vector2(-1, 0)
@ -34,7 +28,6 @@ offset_left = 1.0
offset_right = -1.0
offset_bottom = 292.0
grow_horizontal = 2
metadata/_edit_lock_ = true
[node name="text_field" type="RichTextLabel" parent="command_line_panel/scroll_container" unique_id=591332585]
custom_minimum_size = Vector2(-1, -1)
@ -44,4 +37,3 @@ fit_content = true
scroll_active = false
autowrap_mode = 0
shortcut_keys_enabled = false
metadata/_edit_lock_ = true

View File

@ -1,7 +1,3 @@
[gd_scene format=3 uid="uid://bii6018k3ip3t"]
[ext_resource type="Map" uid="uid://b4rw48yjf7q3q" path="res://maps/default_map.tres" id="1_glms7"]
[ext_resource type="Map" uid="uid://crti664evgfmj" path="res://maps/default_map_2.tres" id="2_udu3i"]
[node name="game_manager" type="GameManager" unique_id=1442044769]
maps = Array[Map]([ExtResource("1_glms7"), ExtResource("2_udu3i")])

View File

@ -1,16 +1,11 @@
[gd_scene format=3 uid="uid://bwd6bj21x310s"]
[ext_resource type="PackedScene" uid="uid://ccd0wj2usx5os" path="res://scenes/player_listing.tscn" id="1_o1atq"]
[sub_resource type="LabelSettings" id="LabelSettings_1cgct"]
font_size = 32
[node name="lobby" type="LobbyPanel" unique_id=915192272 node_paths=PackedStringArray("players_list", "name_field", "ready_button", "map_selection")]
[node name="lobby" type="LobbyPanel" unique_id=915192272 node_paths=PackedStringArray("players_list", "name_field")]
players_list = NodePath("v_box_container/players_list")
name_field = NodePath("v_box_container/h_box_container/text_edit")
player_listing_prefab = ExtResource("1_o1atq")
ready_button = NodePath("ready_button")
map_selection = NodePath("v_box_container2/option_button")
name_field = NodePath("h_box_container/text_edit")
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
@ -30,57 +25,29 @@ horizontal_alignment = 1
[node name="v_box_container" type="VBoxContainer" parent="." unique_id=336946640]
layout_mode = 0
offset_left = 129.0
offset_top = 146.0
offset_right = 334.0
offset_bottom = 200.0
[node name="h_box_container" type="HBoxContainer" parent="v_box_container" unique_id=1789302658]
layout_mode = 2
metadata/_edit_lock_ = true
[node name="label" type="Label" parent="v_box_container/h_box_container" unique_id=626633696]
layout_mode = 2
text = "Name:"
[node name="text_edit" type="TextEdit" parent="v_box_container/h_box_container" unique_id=683714912]
custom_minimum_size = Vector2(150, 0)
layout_mode = 2
offset_left = 178.0
offset_top = 189.0
offset_right = 239.0
offset_bottom = 229.0
[node name="players_label" type="Label" parent="v_box_container" unique_id=1537542117]
layout_mode = 2
text = "Players:"
metadata/_edit_lock_ = true
[node name="players_list" type="VBoxContainer" parent="v_box_container" unique_id=1834737379]
layout_mode = 2
metadata/_edit_lock_ = true
[node name="netstats" type="NetStatsLabel" parent="." unique_id=1335814511]
layout_mode = 1
anchors_preset = 12
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = -144.0
grow_horizontal = 2
grow_vertical = 0
vertical_alignment = 2
[node name="ready_button" type="Button" parent="." unique_id=311553419]
[node name="h_box_container" type="HBoxContainer" parent="." unique_id=1789302658]
layout_mode = 0
offset_left = 129.0
offset_top = 504.0
offset_right = 278.0
offset_bottom = 555.0
text = "Not Ready"
offset_left = 221.0
offset_top = 512.0
offset_right = 261.0
offset_bottom = 552.0
[node name="v_box_container2" type="VBoxContainer" parent="." unique_id=653902328]
layout_mode = 0
offset_left = 716.0
offset_top = 146.0
offset_right = 824.0
offset_bottom = 204.0
[node name="option_button" type="OptionButton" parent="v_box_container2" unique_id=426342653]
[node name="label" type="Label" parent="h_box_container" unique_id=626633696]
layout_mode = 2
text = "Name:"
[node name="text_edit" type="TextEdit" parent="h_box_container" unique_id=683714912]
custom_minimum_size = Vector2(150, 0)
layout_mode = 2

View File

@ -1,26 +0,0 @@
[gd_scene format=3 uid="uid://ccd0wj2usx5os"]
[node name="player_listing" type="PlayerListing" unique_id=772938280 node_paths=PackedStringArray("name_label", "ping_label", "ready_label")]
name_label = NodePath("name")
ping_label = NodePath("ping")
ready_label = NodePath("ready")
offset_right = 319.0
offset_bottom = 23.0
columns = 3
[node name="name" type="Label" parent="." unique_id=635700663]
custom_minimum_size = Vector2(200, 0)
custom_maximum_size = Vector2(200, -1)
layout_mode = 2
text = "Name"
[node name="ready" type="Label" parent="." unique_id=1064828735]
custom_minimum_size = Vector2(100, 0)
custom_maximum_size = Vector2(100, -1)
layout_mode = 2
text = "Ready"
[node name="ping" type="Label" parent="." unique_id=1935412601]
layout_mode = 2
text = "(200ms)"
horizontal_alignment = 2

View File

@ -3,11 +3,6 @@ use std::net::SocketAddr;
use godot::{prelude::*, tools::get_autoload_by_name};
use serde::{Deserialize, Serialize};
use crate::{
map_resource::Map,
net::network_manager::{NetworkManager, Package, PeerKind},
};
pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal";
#[derive(GodotClass)]
@ -15,9 +10,6 @@ pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal";
pub struct GameManager {
pub game: Option<Gd<Game>>,
base: Base<Node>,
#[export]
pub maps: Array<Gd<Map>>,
}
#[godot_api]
@ -28,8 +20,6 @@ impl GameManager {
pub fn on_new_player(id: u16);
#[signal]
pub fn on_player_disconnected(id: u16);
#[signal]
pub fn on_map_changed(id: u8);
pub fn singleton() -> Gd<GameManager> {
get_autoload_by_name::<GameManager>(GAME_MANAGER_GLOBAL)
@ -41,7 +31,6 @@ impl GameManager {
}
let mut game = Game::new_alloc();
game.bind_mut().is_host = is_host;
game.bind_mut().maps = self.maps.clone();
self.run_deferred(|s| {
if let Some(game) = &s.game {
@ -54,9 +43,6 @@ impl GameManager {
game.signals()
.on_players_updated()
.connect_other(s, |s| s.signals().on_players_updated().emit());
game.signals()
.on_map_changed()
.connect_other(s, |s, id| s.signals().on_map_changed().emit(id));
}
});
@ -69,15 +55,10 @@ impl GameManager {
#[derive(GodotClass)]
#[class(base=Node, init)]
pub struct Game {
pub selected_map_idx: u8,
pub selected_map: Option<Gd<Map>>,
pub maps: Array<Gd<Map>>,
is_host: bool,
player_counter: u16,
pub self_id: Option<u16>,
pub players: Vec<Player>,
game_started: bool,
base: Base<Node>,
}
@ -90,8 +71,6 @@ impl Game {
pub fn on_new_player(id: u16);
#[signal]
pub fn on_player_disconnected(id: u16);
#[signal]
pub fn on_map_changed(id: u8);
pub fn singleton() -> Option<Gd<Game>> {
GameManager::singleton()
@ -99,75 +78,34 @@ impl Game {
.map(|g| g.cast::<Game>())
}
pub fn change_map_selection(&mut self, map_idx: u8, emit: bool) {
self.selected_map_idx = map_idx;
if let Some(map) = self.maps.get(map_idx as usize) {
self.selected_map = Some(map);
if emit {
self.run_deferred(move |s| s.signals().on_map_changed().emit(map_idx));
}
}
}
pub fn start_game(&mut self) {
self.game_started = true;
if let Some(map) = &self.selected_map {
if let Some(scene) = &map.bind().scene {
self.base().get_tree().change_scene_to_packed(scene);
}
}
self.run_deferred(|_| {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
if let PeerKind::Server(peer, _) = peer {
peer.broadcast_reliable(Package::GameStarted);
peer.set_accepting_connections(false);
}
}
});
}
pub fn set_self(&mut self, id: u16) {
self.self_id = Some(id);
}
pub fn new_player(&mut self, addr: SocketAddr, name: String, id: Option<u16>) -> u16 {
let id = if let Some(id) = id {
id
} else {
let id = self.player_counter;
self.player_counter += 1;
id
};
pub fn new_player(&mut self, addr: SocketAddr, name: String) -> u16 {
let id = self.player_counter;
self.player_counter += 1;
self.players.push(Player {
id,
connection_addr: addr,
name,
ping: 0,
ready: false,
});
self.run_deferred(move |s| s.signals().on_new_player().emit(id));
self.signals().on_new_player().emit(id);
id
}
pub fn set_players(&mut self, players: Vec<Player>) {
self.players = players;
for player in self.players.clone() {
self.run_deferred(move |s| s.signals().on_new_player().emit(player.id));
}
self.signals().on_players_updated().emit();
}
pub fn find_player_by_addr(&self, addr: &SocketAddr) -> Option<&Player> {
self.players.iter().find(|p| p.connection_addr == *addr)
}
pub fn find_player(&self, player_id: u16) -> Option<&Player> {
self.players.iter().find(|p| p.id == player_id)
}
pub fn remove_player(&mut self, id: u16) {
self.signals().on_player_disconnected().emit(id);
self.players.retain(|p| p.id != id);
self.run_deferred(move |s| s.signals().on_player_disconnected().emit(id));
}
pub fn update_player_nick(&mut self, player_id: u16, nick: String) {
@ -176,20 +114,6 @@ impl Game {
}
self.run_deferred(|s| s.signals().on_players_updated().emit());
}
pub fn update_player_ping(&mut self, player_id: u16, ping: u128) {
if let Some(player) = self.players.iter_mut().find(|p| p.id == player_id) {
player.ping = ping;
}
self.run_deferred(|s| s.signals().on_players_updated().emit());
}
pub fn update_player_ready(&mut self, player_id: u16, ready: bool) {
if let Some(player) = self.players.iter_mut().find(|p| p.id == player_id) {
player.ready = ready;
}
self.run_deferred(|s| s.signals().on_players_updated().emit());
}
}
#[derive(Clone, Deserialize, Serialize, Debug)]
@ -197,6 +121,4 @@ pub struct Player {
pub id: u16,
pub connection_addr: SocketAddr,
pub name: String,
pub ping: u128,
pub ready: bool,
}

View File

@ -3,7 +3,6 @@ use std::net::SocketAddr;
use godot::prelude::*;
pub mod game_manager;
pub mod map_resource;
pub mod net;
pub mod ui;

View File

@ -1,27 +0,0 @@
use godot::prelude::*;
#[derive(GodotClass)]
#[class(base=Resource, init, tool)]
pub struct Map {
#[export]
pub name: GString,
#[export]
pub scene: Option<Gd<PackedScene>>,
base: Base<Resource>,
}
#[godot_api]
impl IResource for Map {
fn on_notification(&mut self, what: godot::classes::notify::ObjectNotification) {}
fn to_string(&self) -> GString {
"Hello there".to_gstring()
}
fn setup_local_to_scene(&mut self) {}
fn reset_state(&mut self) {}
fn set_path_cache(&self, path: GString) {}
}

View File

@ -1,12 +1,11 @@
use std::{
collections::HashMap,
net::SocketAddr,
time::{Duration, Instant},
};
use godot::{prelude::*, tools::get_autoload_by_name};
use serde::{Deserialize, Serialize};
use teanet::{Peer, PeerConfig, PeerMessage, connections::Connection};
use teanet::{Peer, PeerConfig, PeerMessage};
use crate::{
game_manager::{Game, GameManager, Player},
@ -24,7 +23,6 @@ pub struct NetworkManager {
last_hello: Instant,
last_netstat_update: Instant,
last_player_update: Instant,
base: Base<Node>,
}
@ -41,7 +39,6 @@ impl INode for NetworkManager {
last_hello: Instant::now(),
last_netstat_update: Instant::now(),
last_player_update: Instant::now(),
base,
}
@ -77,29 +74,6 @@ impl INode for NetworkManager {
self.last_netstat_update = now;
}
if now - self.last_player_update > Duration::from_millis(500) {
self.last_player_update = now;
if let PeerKind::Server(peer, _) = peer {
let mut pings = HashMap::new();
for connection in peer.connections() {
if let Some(mut game) = Game::singleton() {
let player = game
.bind()
.find_player_by_addr(&connection.address)
.cloned();
if let Some(player) = player {
game.bind_mut()
.update_player_ping(player.id, connection.ping.as_millis());
pings.insert(player.id, connection.ping.as_millis());
}
}
}
peer.broadcast_reliable(Package::UpdatePings(pings));
}
}
match peer {
PeerKind::Client(..) => {}
PeerKind::Server(peer, _) => {
@ -163,49 +137,6 @@ impl INode for NetworkManager {
}
}
}
Package::UpdatePings(pings) => {
if let Some(game) = &mut Game::singleton() {
for (player_id, ping) in pings {
game.bind_mut().update_player_ping(player_id, ping);
}
}
}
Package::NewPlayer(player) => {
if let Some(game) = &mut Game::singleton() {
if player.id != game.bind().self_id.unwrap_or(u16::MAX)
{
game.bind_mut().new_player(
SocketAddr::from(([0, 0, 0, 0], 0)),
player.name,
Some(player.id),
);
}
}
}
Package::PlayerLeft(player) => {
if let Some(game) = &mut Game::singleton() {
if player.id != game.bind().self_id.unwrap_or(u16::MAX)
{
game.bind_mut().remove_player(player.id);
}
}
}
Package::SetReady(player_id, is_ready) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut()
.update_player_ready(player_id, is_ready);
}
}
Package::SelectMap(map_id) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().change_map_selection(map_id, true);
}
}
Package::GameStarted => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().start_game();
}
}
_ => {}
},
}
@ -227,29 +158,12 @@ impl INode for NetworkManager {
);
if let Some(game) = &mut Game::singleton() {
let self_id = game.bind_mut().new_player(
connection.address,
String::new(),
None,
);
let mut sent_players = game.bind().players.clone();
for player in &mut sent_players {
player.connection_addr =
SocketAddr::from(([0, 0, 0, 0], 0))
}
let self_id = game
.bind_mut()
.new_player(connection.address, String::new());
peer.send_reliable(
&connection.address,
Package::Players(sent_players, self_id),
);
let mut sent_player =
game.bind().find_player(self_id).unwrap().clone();
sent_player.connection_addr =
SocketAddr::from(([0, 0, 0, 0], 0));
peer.broadcast_reliable(Package::NewPlayer(sent_player));
peer.send_reliable(
&connection.address,
Package::SelectMap(game.bind().selected_map_idx),
Package::Players(game.bind().players.clone(), self_id),
);
}
}
@ -270,9 +184,6 @@ impl INode for NetworkManager {
.find_player_by_addr(&connection.address)
.map(|p| p.id);
if let Some(player_id) = player_id {
peer.broadcast_reliable(Package::PlayerLeft(
game.bind().find_player(player_id).unwrap().clone(),
));
game.bind_mut().remove_player(player_id);
}
}
@ -299,21 +210,6 @@ impl INode for NetworkManager {
}
}
}
Package::SetReady(_, is_ready) => {
if let Some(game) = &mut Game::singleton() {
let player = game
.bind()
.find_player_by_addr(&conn.address)
.cloned();
if let Some(player) = player {
game.bind_mut()
.update_player_ready(player.id, is_ready);
peer.broadcast_reliable(Package::SetReady(
player.id, is_ready,
));
}
}
}
_ => {}
},
}
@ -321,7 +217,7 @@ impl INode for NetworkManager {
}
Err(err) => {
cli.bind_mut()
.publish_message(format!("Error: {}", err), CliColor::Error);
.publish_message(format!("Error: {}", err), CliColor::Info);
}
},
}
@ -350,12 +246,9 @@ impl NetworkManager {
self.swap_to_lobby(true);
if let Some(game) = &mut Game::singleton() {
let id = game.bind_mut().new_player(
SocketAddr::from(([0, 0, 0, 0], 0)),
"Host".to_owned(),
None,
);
game.bind_mut().update_player_ready(id, true);
let id = game
.bind_mut()
.new_player(SocketAddr::from(([0, 0, 0, 0], 0)), "Host".to_owned());
game.bind_mut().set_self(id);
}
}
@ -427,24 +320,9 @@ pub enum Package {
Players(Vec<Player>, u16),
SetNick(u16, String),
SetSelfNick(String),
UpdatePings(HashMap<u16, u128>),
NewPlayer(Player),
PlayerLeft(Player),
SetReady(u16, bool),
SelectMap(u8),
GameStarted,
}
pub enum PeerKind {
Client(Peer<Package>, SocketAddr),
Server(Peer<Package>, u16),
}
impl PeerKind {
pub fn is_host(&self) -> bool {
match self {
PeerKind::Client(_, _) => false,
PeerKind::Server(_, _) => true,
}
}
}

View File

@ -4,7 +4,7 @@ use std::ops::DerefMut;
use std::rc::Rc;
use godot::classes::{
CanvasLayer, Engine, IPanel, InputEvent, Panel, RichTextLabel, ScrollContainer, TextEdit,
CanvasLayer, Engine, IPanel, Panel, RichTextLabel, ScrollContainer, TextEdit,
};
use godot::prelude::*;
use godot::tools::get_autoload_by_name;
@ -39,14 +39,9 @@ pub struct CommandLinePanel {
#[export]
pub scroll_container: Option<Gd<ScrollContainer>>,
#[export]
pub opened: bool,
scroll_next_update: bool,
commands: HashMap<String, Rc<Box<dyn Command>>>,
idle_y: f32,
base: Base<Panel>,
}
@ -66,18 +61,12 @@ impl IPanel for CommandLinePanel {
input_field: None,
text_field: None,
scroll_container: None,
opened: false,
scroll_next_update: false,
idle_y: 0.,
commands,
base,
}
}
fn ready(&mut self) {
self.idle_y = self.base().get_position().y;
}
fn process(&mut self, _delta: f64) {
if let Some(scroll) = &mut self.scroll_container
&& self.scroll_next_update
@ -94,32 +83,6 @@ impl IPanel for CommandLinePanel {
self.input_command(first.to_string());
}
}
let old_pos = self.base().get_position();
let mut target_pos = self.base().get_position();
if self.opened {
target_pos.y = 0.;
} else {
target_pos.y = self.idle_y;
}
let new_pos = old_pos.lerp(target_pos, 0.3);
self.base_mut().set_position(new_pos);
}
fn input(&mut self, event: Gd<InputEvent>) {
if event.is_action_pressed("toggle_cli") {
self.opened = !self.opened;
if let Some(input_field) = &mut self.input_field {
if self.opened {
input_field.grab_focus();
input_field.set_editable(true);
self.run_deferred(|s| s.input_field.as_mut().unwrap().clear());
} else {
input_field.release_focus();
input_field.set_editable(false);
}
}
}
}
}

View File

@ -1,13 +1,11 @@
use godot::{
classes::{Button, IPanel, Label, OptionButton, Panel, TextEdit, VBoxContainer},
classes::{IPanel, Label, Panel, TextEdit, VBoxContainer},
prelude::*,
};
use crate::{
game_manager::{Game, GameManager},
map_resource::Map,
net::network_manager::{NetworkManager, Package, PeerKind},
ui::player_listing::PlayerListing,
net::network_manager::NetworkManager,
};
#[derive(GodotClass)]
@ -17,14 +15,6 @@ pub struct LobbyPanel {
players_list: Option<Gd<VBoxContainer>>,
#[export]
name_field: Option<Gd<TextEdit>>,
#[export]
player_listing_prefab: Option<Gd<PackedScene>>,
#[export]
ready_button: Option<Gd<Button>>,
#[export]
map_selection: Option<Gd<OptionButton>>,
is_ready: bool,
base: Base<Panel>,
}
@ -35,50 +25,15 @@ impl IPanel for LobbyPanel {
GameManager::singleton()
.signals()
.on_new_player()
.connect_other(self, |s, _| s.update_players(true));
.connect_other(self, |s, _| s.update_players_list());
GameManager::singleton()
.signals()
.on_player_disconnected()
.connect_other(self, |s, _| s.update_players(true));
.connect_other(self, |s, _| s.update_players_list());
GameManager::singleton()
.signals()
.on_players_updated()
.connect_other(self, |s| s.update_players(false));
GameManager::singleton()
.signals()
.on_map_changed()
.connect_other(self, |s, id| s.update_map_selection(id));
if let Some(ready_button) = &self.ready_button {
ready_button
.signals()
.pressed()
.connect_other(self, |s| s.on_ready());
}
if let Some(map_selection) = &self.map_selection {
map_selection
.signals()
.item_selected()
.connect_other(self, |s, id| {
s.update_map_selection(id as u8);
});
}
if let Some(game) = Game::singleton() {
if let Some(map_selection) = &mut self.map_selection {
for map in game.bind().maps.iter_shared() {
map_selection.add_item(&map.bind().name);
}
let is_host = if let Some(peer) = &NetworkManager::singleton().bind().peer {
peer.is_host()
} else {
false
};
map_selection.set_disabled(!is_host);
map_selection.select(0);
}
}
self.update_map_selection(0);
.connect_other(self, |s| s.update_players_list());
if let Some(name_field) = &self.name_field {
name_field
@ -103,103 +58,21 @@ impl IPanel for LobbyPanel {
});
}
self.update_players(true);
if let Some(peer) = &NetworkManager::singleton().bind().peer
&& peer.is_host()
{
if let Some(button) = &mut self.ready_button {
button.set_text("Start Game");
button.set_disabled(true);
}
}
self.update_ready_button();
self.update_players_list();
}
}
impl LobbyPanel {
fn update_ready_button(&mut self) {
if let Some(game) = Game::singleton()
&& let Some(peer) = &NetworkManager::singleton().bind().peer
{
if let PeerKind::Server(_, _) = peer
&& let Some(button) = &mut self.ready_button
{
let all_ready = game.bind().players.iter().all(|p| p.ready);
button.set_disabled(!all_ready);
}
}
}
pub fn update_players(&mut self, replace: bool) {
self.update_ready_button();
pub fn update_players_list(&mut self) {
if let Some(list) = &mut self.players_list {
if replace {
for child in list.get_children().iter_shared() {
list.remove_child(&child);
}
if let Some(game) = &GameManager::singleton().bind().game {
if let Some(prefab) = &self.player_listing_prefab {
for player in &game.bind().players {
if let Some(node) = prefab.instantiate() {
let mut listing = node.cast::<PlayerListing>();
listing.bind_mut().player_id = Some(player.id);
listing.bind_mut().update();
list.add_child(&listing);
}
}
}
}
} else {
for child in list.get_children().iter_shared() {
child.cast::<PlayerListing>().bind_mut().update();
}
for child in list.get_children().iter_shared() {
list.remove_child(&child);
}
}
}
pub fn on_ready(&mut self) {
let is_host = if let Some(peer) = &NetworkManager::singleton().bind().peer {
peer.is_host()
} else {
false
};
if !is_host {
self.is_ready = !self.is_ready;
if let Some(button) = &mut self.ready_button {
if self.is_ready {
button.set_text("Ready");
} else {
button.set_text("Not Ready");
}
}
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
if let PeerKind::Client(peer, socket_addr) = peer {
peer.send_reliable(&socket_addr, Package::SetReady(0, self.is_ready));
}
}
} else {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().start_game();
}
}
}
pub fn update_map_selection(&mut self, idx: u8) {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
match peer {
PeerKind::Client(..) => {
if let Some(map_selection) = &mut self.map_selection {
map_selection.select(idx as i32);
}
}
PeerKind::Server(peer, _) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().change_map_selection(idx, false);
}
peer.broadcast_reliable(Package::SelectMap(idx));
if let Some(game) = &GameManager::singleton().bind().game {
for player in &game.bind().players {
let mut label = Label::new_alloc();
label.set_text(&format!("{} ({})", player.name, player.connection_addr));
list.add_child(&label);
}
}
}

View File

@ -1,4 +1,3 @@
pub mod cli;
pub mod lobby;
pub mod net_stats;
pub mod player_listing;

View File

@ -1,49 +0,0 @@
use godot::{
classes::{GridContainer, IGridContainer, Label, Panel, TextEdit, VBoxContainer},
prelude::*,
};
use crate::{
game_manager::{Game, Player},
net::network_manager::NetworkManager,
};
#[derive(GodotClass)]
#[class(base=GridContainer, init)]
pub struct PlayerListing {
#[export]
pub name_label: Option<Gd<Label>>,
#[export]
pub ping_label: Option<Gd<Label>>,
#[export]
pub ready_label: Option<Gd<Label>>,
pub player_id: Option<u16>,
base: Base<GridContainer>,
}
impl PlayerListing {
pub fn update(&mut self) {
if let Some(player_id) = &self.player_id
&& let Some(game) = Game::singleton()
&& let Some(player) = game.bind().find_player(*player_id)
{
if let Some(player_label) = &mut self.name_label {
player_label.set_text(&format!("{} ({})", player.name, player.connection_addr));
}
if let Some(ready_label) = &mut self.ready_label {
if player.ready {
ready_label.set_text("Ready");
} else {
ready_label.set_text("Not Ready");
}
}
if let Some(ping_label) = &mut self.ping_label {
ping_label.set_text(&format!("({}ms)", player.ping));
}
}
}
}

@ -1 +1 @@
Subproject commit a947f3a8cbad03b939dedfc1486de75226d90c0a
Subproject commit 2721021f7b20831388d9ea7b3ea0797e3efdfdac