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"]
|
||||
|
||||
[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")]
|
||||
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
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
@ -25,29 +28,28 @@ horizontal_alignment = 1
|
||||
|
||||
[node name="v_box_container" type="VBoxContainer" parent="." unique_id=336946640]
|
||||
layout_mode = 0
|
||||
offset_left = 178.0
|
||||
offset_top = 189.0
|
||||
offset_right = 239.0
|
||||
offset_bottom = 229.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
|
||||
|
||||
[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
|
||||
|
||||
[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
|
||||
metadata/_edit_lock_ = true
|
||||
|
||||
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,
|
||||
connection_addr: addr,
|
||||
name,
|
||||
ping: 0,
|
||||
});
|
||||
self.signals().on_new_player().emit(id);
|
||||
id
|
||||
@ -96,13 +97,19 @@ impl Game {
|
||||
|
||||
pub fn set_players(&mut self, players: Vec<Player>) {
|
||||
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> {
|
||||
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) {
|
||||
self.signals().on_player_disconnected().emit(id);
|
||||
self.players.retain(|p| p.id != id);
|
||||
@ -114,6 +121,13 @@ 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());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize, Debug)]
|
||||
@ -121,4 +135,5 @@ pub struct Player {
|
||||
pub id: u16,
|
||||
pub connection_addr: SocketAddr,
|
||||
pub name: String,
|
||||
pub ping: u128,
|
||||
}
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
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};
|
||||
use teanet::{Peer, PeerConfig, PeerMessage, connections::Connection};
|
||||
|
||||
use crate::{
|
||||
game_manager::{Game, GameManager, Player},
|
||||
@ -23,6 +24,7 @@ pub struct NetworkManager {
|
||||
|
||||
last_hello: Instant,
|
||||
last_netstat_update: Instant,
|
||||
last_player_update: Instant,
|
||||
|
||||
base: Base<Node>,
|
||||
}
|
||||
@ -39,6 +41,7 @@ impl INode for NetworkManager {
|
||||
|
||||
last_hello: Instant::now(),
|
||||
last_netstat_update: Instant::now(),
|
||||
last_player_update: Instant::now(),
|
||||
|
||||
base,
|
||||
}
|
||||
@ -74,6 +77,29 @@ 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, _) => {
|
||||
@ -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),
|
||||
SetNick(u16, String),
|
||||
SetSelfNick(String),
|
||||
UpdatePings(HashMap<u16, u128>),
|
||||
}
|
||||
|
||||
pub enum PeerKind {
|
||||
|
||||
@ -108,7 +108,6 @@ impl IPanel for CommandLinePanel {
|
||||
|
||||
fn input(&mut self, event: Gd<InputEvent>) {
|
||||
if event.is_action_pressed("toggle_cli") {
|
||||
godot_print!("hello?");
|
||||
self.opened = !self.opened;
|
||||
if let Some(input_field) = &mut self.input_field {
|
||||
if self.opened {
|
||||
|
||||
@ -6,6 +6,7 @@ use godot::{
|
||||
use crate::{
|
||||
game_manager::{Game, GameManager},
|
||||
net::network_manager::NetworkManager,
|
||||
ui::player_listing::PlayerListing,
|
||||
};
|
||||
|
||||
#[derive(GodotClass)]
|
||||
@ -15,6 +16,8 @@ pub struct LobbyPanel {
|
||||
players_list: Option<Gd<VBoxContainer>>,
|
||||
#[export]
|
||||
name_field: Option<Gd<TextEdit>>,
|
||||
#[export]
|
||||
player_listing_prefab: Option<Gd<PackedScene>>,
|
||||
|
||||
base: Base<Panel>,
|
||||
}
|
||||
@ -25,15 +28,15 @@ impl IPanel for LobbyPanel {
|
||||
GameManager::singleton()
|
||||
.signals()
|
||||
.on_new_player()
|
||||
.connect_other(self, |s, _| s.update_players_list());
|
||||
.connect_other(self, |s, _| s.update_players_list(true));
|
||||
GameManager::singleton()
|
||||
.signals()
|
||||
.on_player_disconnected()
|
||||
.connect_other(self, |s, _| s.update_players_list());
|
||||
.connect_other(self, |s, _| s.update_players_list(true));
|
||||
GameManager::singleton()
|
||||
.signals()
|
||||
.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 {
|
||||
name_field
|
||||
@ -58,21 +61,32 @@ impl IPanel for LobbyPanel {
|
||||
});
|
||||
}
|
||||
|
||||
self.update_players_list();
|
||||
self.update_players_list(true);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
for child in list.get_children().iter_shared() {
|
||||
list.remove_child(&child);
|
||||
}
|
||||
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);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
pub mod cli;
|
||||
pub mod lobby;
|
||||
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