Add more proper player listings
This commit is contained in:
parent
8893a2370d
commit
4c58824840
@ -1,11 +1,14 @@
|
|||||||
[gd_scene format=3 uid="uid://bwd6bj21x310s"]
|
[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"]
|
[sub_resource type="LabelSettings" id="LabelSettings_1cgct"]
|
||||||
font_size = 32
|
font_size = 32
|
||||||
|
|
||||||
[node name="lobby" type="LobbyPanel" unique_id=915192272 node_paths=PackedStringArray("players_list", "name_field")]
|
[node name="lobby" type="LobbyPanel" unique_id=915192272 node_paths=PackedStringArray("players_list", "name_field")]
|
||||||
players_list = NodePath("v_box_container/players_list")
|
players_list = NodePath("v_box_container/players_list")
|
||||||
name_field = NodePath("h_box_container/text_edit")
|
name_field = NodePath("v_box_container/h_box_container/text_edit")
|
||||||
|
player_listing_prefab = ExtResource("1_o1atq")
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
@ -25,29 +28,28 @@ horizontal_alignment = 1
|
|||||||
|
|
||||||
[node name="v_box_container" type="VBoxContainer" parent="." unique_id=336946640]
|
[node name="v_box_container" type="VBoxContainer" parent="." unique_id=336946640]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 178.0
|
offset_left = 129.0
|
||||||
offset_top = 189.0
|
offset_top = 146.0
|
||||||
offset_right = 239.0
|
offset_right = 334.0
|
||||||
offset_bottom = 229.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
|
||||||
|
|
||||||
[node name="players_label" type="Label" parent="v_box_container" unique_id=1537542117]
|
[node name="players_label" type="Label" parent="v_box_container" unique_id=1537542117]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Players:"
|
text = "Players:"
|
||||||
|
metadata/_edit_lock_ = true
|
||||||
|
|
||||||
[node name="players_list" type="VBoxContainer" parent="v_box_container" unique_id=1834737379]
|
[node name="players_list" type="VBoxContainer" parent="v_box_container" unique_id=1834737379]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
metadata/_edit_lock_ = true
|
||||||
[node name="h_box_container" type="HBoxContainer" parent="." unique_id=1789302658]
|
|
||||||
layout_mode = 0
|
|
||||||
offset_left = 221.0
|
|
||||||
offset_top = 512.0
|
|
||||||
offset_right = 261.0
|
|
||||||
offset_bottom = 552.0
|
|
||||||
|
|
||||||
[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
|
|
||||||
|
|||||||
19
godot/scenes/player_listing.tscn
Normal file
19
godot/scenes/player_listing.tscn
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_scene format=3 uid="uid://ccd0wj2usx5os"]
|
||||||
|
|
||||||
|
[node name="player_listing" type="PlayerListing" unique_id=772938280 node_paths=PackedStringArray("name_label", "ping_label")]
|
||||||
|
name_label = NodePath("name")
|
||||||
|
ping_label = NodePath("ping")
|
||||||
|
offset_right = 265.0
|
||||||
|
offset_bottom = 23.0
|
||||||
|
columns = 2
|
||||||
|
|
||||||
|
[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="ping" type="Label" parent="." unique_id=1935412601]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "(200ms)"
|
||||||
|
horizontal_alignment = 2
|
||||||
@ -89,6 +89,7 @@ impl Game {
|
|||||||
id,
|
id,
|
||||||
connection_addr: addr,
|
connection_addr: addr,
|
||||||
name,
|
name,
|
||||||
|
ping: 0,
|
||||||
});
|
});
|
||||||
self.signals().on_new_player().emit(id);
|
self.signals().on_new_player().emit(id);
|
||||||
id
|
id
|
||||||
@ -96,13 +97,19 @@ impl Game {
|
|||||||
|
|
||||||
pub fn set_players(&mut self, players: Vec<Player>) {
|
pub fn set_players(&mut self, players: Vec<Player>) {
|
||||||
self.players = players;
|
self.players = players;
|
||||||
self.signals().on_players_updated().emit();
|
for player in self.players.clone() {
|
||||||
|
self.signals().on_new_player().emit(player.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_player_by_addr(&self, addr: &SocketAddr) -> Option<&Player> {
|
pub fn find_player_by_addr(&self, addr: &SocketAddr) -> Option<&Player> {
|
||||||
self.players.iter().find(|p| p.connection_addr == *addr)
|
self.players.iter().find(|p| p.connection_addr == *addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_player(&self, player_id: u16) -> Option<&Player> {
|
||||||
|
self.players.iter().find(|p| p.id == player_id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_player(&mut self, id: u16) {
|
pub fn remove_player(&mut self, id: u16) {
|
||||||
self.signals().on_player_disconnected().emit(id);
|
self.signals().on_player_disconnected().emit(id);
|
||||||
self.players.retain(|p| p.id != id);
|
self.players.retain(|p| p.id != id);
|
||||||
@ -114,6 +121,13 @@ impl Game {
|
|||||||
}
|
}
|
||||||
self.run_deferred(|s| s.signals().on_players_updated().emit());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize, Debug)]
|
#[derive(Clone, Deserialize, Serialize, Debug)]
|
||||||
@ -121,4 +135,5 @@ pub struct Player {
|
|||||||
pub id: u16,
|
pub id: u16,
|
||||||
pub connection_addr: SocketAddr,
|
pub connection_addr: SocketAddr,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub ping: u128,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use godot::{prelude::*, tools::get_autoload_by_name};
|
use godot::{prelude::*, tools::get_autoload_by_name};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use teanet::{Peer, PeerConfig, PeerMessage};
|
use teanet::{Peer, PeerConfig, PeerMessage, connections::Connection};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
game_manager::{Game, GameManager, Player},
|
game_manager::{Game, GameManager, Player},
|
||||||
@ -23,6 +24,7 @@ pub struct NetworkManager {
|
|||||||
|
|
||||||
last_hello: Instant,
|
last_hello: Instant,
|
||||||
last_netstat_update: Instant,
|
last_netstat_update: Instant,
|
||||||
|
last_player_update: Instant,
|
||||||
|
|
||||||
base: Base<Node>,
|
base: Base<Node>,
|
||||||
}
|
}
|
||||||
@ -39,6 +41,7 @@ impl INode for NetworkManager {
|
|||||||
|
|
||||||
last_hello: Instant::now(),
|
last_hello: Instant::now(),
|
||||||
last_netstat_update: Instant::now(),
|
last_netstat_update: Instant::now(),
|
||||||
|
last_player_update: Instant::now(),
|
||||||
|
|
||||||
base,
|
base,
|
||||||
}
|
}
|
||||||
@ -74,6 +77,29 @@ impl INode for NetworkManager {
|
|||||||
self.last_netstat_update = now;
|
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 {
|
match peer {
|
||||||
PeerKind::Client(..) => {}
|
PeerKind::Client(..) => {}
|
||||||
PeerKind::Server(peer, _) => {
|
PeerKind::Server(peer, _) => {
|
||||||
@ -137,6 +163,13 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -320,6 +353,7 @@ pub enum Package {
|
|||||||
Players(Vec<Player>, u16),
|
Players(Vec<Player>, u16),
|
||||||
SetNick(u16, String),
|
SetNick(u16, String),
|
||||||
SetSelfNick(String),
|
SetSelfNick(String),
|
||||||
|
UpdatePings(HashMap<u16, u128>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum PeerKind {
|
pub enum PeerKind {
|
||||||
|
|||||||
@ -108,7 +108,6 @@ impl IPanel for CommandLinePanel {
|
|||||||
|
|
||||||
fn input(&mut self, event: Gd<InputEvent>) {
|
fn input(&mut self, event: Gd<InputEvent>) {
|
||||||
if event.is_action_pressed("toggle_cli") {
|
if event.is_action_pressed("toggle_cli") {
|
||||||
godot_print!("hello?");
|
|
||||||
self.opened = !self.opened;
|
self.opened = !self.opened;
|
||||||
if let Some(input_field) = &mut self.input_field {
|
if let Some(input_field) = &mut self.input_field {
|
||||||
if self.opened {
|
if self.opened {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ use godot::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
game_manager::{Game, GameManager},
|
game_manager::{Game, GameManager},
|
||||||
net::network_manager::NetworkManager,
|
net::network_manager::NetworkManager,
|
||||||
|
ui::player_listing::PlayerListing,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(GodotClass)]
|
#[derive(GodotClass)]
|
||||||
@ -15,6 +16,8 @@ pub struct LobbyPanel {
|
|||||||
players_list: Option<Gd<VBoxContainer>>,
|
players_list: Option<Gd<VBoxContainer>>,
|
||||||
#[export]
|
#[export]
|
||||||
name_field: Option<Gd<TextEdit>>,
|
name_field: Option<Gd<TextEdit>>,
|
||||||
|
#[export]
|
||||||
|
player_listing_prefab: Option<Gd<PackedScene>>,
|
||||||
|
|
||||||
base: Base<Panel>,
|
base: Base<Panel>,
|
||||||
}
|
}
|
||||||
@ -25,15 +28,15 @@ impl IPanel for LobbyPanel {
|
|||||||
GameManager::singleton()
|
GameManager::singleton()
|
||||||
.signals()
|
.signals()
|
||||||
.on_new_player()
|
.on_new_player()
|
||||||
.connect_other(self, |s, _| s.update_players_list());
|
.connect_other(self, |s, _| s.update_players_list(true));
|
||||||
GameManager::singleton()
|
GameManager::singleton()
|
||||||
.signals()
|
.signals()
|
||||||
.on_player_disconnected()
|
.on_player_disconnected()
|
||||||
.connect_other(self, |s, _| s.update_players_list());
|
.connect_other(self, |s, _| s.update_players_list(true));
|
||||||
GameManager::singleton()
|
GameManager::singleton()
|
||||||
.signals()
|
.signals()
|
||||||
.on_players_updated()
|
.on_players_updated()
|
||||||
.connect_other(self, |s| s.update_players_list());
|
.connect_other(self, |s| s.update_players_list(false));
|
||||||
|
|
||||||
if let Some(name_field) = &self.name_field {
|
if let Some(name_field) = &self.name_field {
|
||||||
name_field
|
name_field
|
||||||
@ -58,21 +61,32 @@ impl IPanel for LobbyPanel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_players_list();
|
self.update_players_list(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LobbyPanel {
|
impl LobbyPanel {
|
||||||
pub fn update_players_list(&mut self) {
|
pub fn update_players_list(&mut self, replace: bool) {
|
||||||
if let Some(list) = &mut self.players_list {
|
if let Some(list) = &mut self.players_list {
|
||||||
|
if replace {
|
||||||
for child in list.get_children().iter_shared() {
|
for child in list.get_children().iter_shared() {
|
||||||
list.remove_child(&child);
|
list.remove_child(&child);
|
||||||
}
|
}
|
||||||
if let Some(game) = &GameManager::singleton().bind().game {
|
if let Some(game) = &GameManager::singleton().bind().game {
|
||||||
|
if let Some(prefab) = &self.player_listing_prefab {
|
||||||
for player in &game.bind().players {
|
for player in &game.bind().players {
|
||||||
let mut label = Label::new_alloc();
|
if let Some(node) = prefab.instantiate() {
|
||||||
label.set_text(&format!("{} ({})", player.name, player.connection_addr));
|
let mut listing = node.cast::<PlayerListing>();
|
||||||
list.add_child(&label);
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
pub mod cli;
|
pub mod cli;
|
||||||
pub mod lobby;
|
pub mod lobby;
|
||||||
pub mod net_stats;
|
pub mod net_stats;
|
||||||
|
pub mod player_listing;
|
||||||
|
|||||||
39
rust/src/ui/player_listing.rs
Normal file
39
rust/src/ui/player_listing.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
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>>,
|
||||||
|
|
||||||
|
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().get_player(*player_id)
|
||||||
|
{
|
||||||
|
if let Some(player_label) = &mut self.name_label {
|
||||||
|
player_label.set_text(&player.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ping_label) = &mut self.ping_label {
|
||||||
|
ping_label.set_text(&format!("({}ms)", player.ping));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user