Compare commits
8 Commits
17b5272a9e
...
949585dc5c
| Author | SHA1 | Date | |
|---|---|---|---|
| 949585dc5c | |||
| c937635efe | |||
| 034c50d6f5 | |||
| f3a5a18400 | |||
| 05bf6401e0 | |||
| 3608194e5a | |||
| ef1bb3946d | |||
| 609a803104 |
@ -1,7 +1,10 @@
|
|||||||
[gd_resource type="MapResource" format=3 uid="uid://bsjoandgu476y"]
|
[gd_resource type="MapResource" format=3 uid="uid://bsjoandgu476y"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://ylj40hkjsgjc" path="res://maps/diner/diner.tscn" id="1_yteo6"]
|
[ext_resource type="PackedScene" uid="uid://ylj40hkjsgjc" path="res://maps/diner/diner.tscn" id="1_yteo6"]
|
||||||
|
[ext_resource type="TeamResource" uid="uid://p2fqqnaejjn7" path="res://maps/teams/blue_team.tres" id="2_47vax"]
|
||||||
|
[ext_resource type="TeamResource" uid="uid://db4b3sjsftg15" path="res://maps/teams/red_ream.tres" id="3_i3gdq"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
name = "Diner"
|
name = "Diner"
|
||||||
scene = ExtResource("1_yteo6")
|
scene = ExtResource("1_yteo6")
|
||||||
|
teams = Array[TeamResource]([ExtResource("2_47vax"), ExtResource("3_i3gdq")])
|
||||||
|
|||||||
Binary file not shown.
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
name = "Blue Team"
|
name = "Blue Team"
|
||||||
color = Color(0, 0, 1, 1)
|
color = Color(0, 0.7411765, 1, 1)
|
||||||
|
|||||||
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
name = "Red Team"
|
name = "Red Team"
|
||||||
color = Color(1, 0, 0, 1)
|
color = Color(1, 0.35686275, 0.3647059, 1)
|
||||||
|
|||||||
@ -37,6 +37,8 @@ offset_bottom = 200.0
|
|||||||
|
|
||||||
[node name="h_box_container" type="HBoxContainer" parent="v_box_container" unique_id=1789302658]
|
[node name="h_box_container" type="HBoxContainer" parent="v_box_container" unique_id=1789302658]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
offset_transform_enabled = true
|
||||||
|
offset_transform_position = Vector2(100, 0)
|
||||||
metadata/_edit_lock_ = true
|
metadata/_edit_lock_ = true
|
||||||
|
|
||||||
[node name="label" type="Label" parent="v_box_container/h_box_container" unique_id=626633696]
|
[node name="label" type="Label" parent="v_box_container/h_box_container" unique_id=626633696]
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"]
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"]
|
||||||
|
|
||||||
[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh", "collider", "splorch", "spectator_camera", "ball_origin")]
|
[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh", "collider", "splorch", "spectator_camera", "ball_origin", "name_label")]
|
||||||
move_speed = 5.0
|
move_speed = 5.0
|
||||||
soldier_mesh = NodePath("soldier_m")
|
soldier_mesh = NodePath("soldier_m")
|
||||||
collider = NodePath("collision_shape_3d")
|
collider = NodePath("collision_shape_3d")
|
||||||
@ -13,6 +13,7 @@ splorch = NodePath("gpu_particles_3d")
|
|||||||
health = 100
|
health = 100
|
||||||
spectator_camera = NodePath("spectate_root/spectate_camera")
|
spectator_camera = NodePath("spectate_root/spectate_camera")
|
||||||
ball_origin = NodePath("ball_origin")
|
ball_origin = NodePath("ball_origin")
|
||||||
|
name_label = NodePath("name_label")
|
||||||
collision_layer = 2
|
collision_layer = 2
|
||||||
collision_mask = 4
|
collision_mask = 4
|
||||||
|
|
||||||
@ -34,3 +35,7 @@ transform = Transform3D(1, 0, 0, 0, 0.89379096, 0.44848388, 0, -0.44848388, 0.89
|
|||||||
|
|
||||||
[node name="ball_origin" type="Node3D" parent="." unique_id=1445680156]
|
[node name="ball_origin" type="Node3D" parent="." unique_id=1445680156]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8724979, -0.2644562)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8724979, -0.2644562)
|
||||||
|
|
||||||
|
[node name="name_label" type="Label3D" parent="." unique_id=142179925]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.3304863, 0)
|
||||||
|
billboard = 1
|
||||||
|
|||||||
@ -1,19 +1,23 @@
|
|||||||
[gd_scene format=3 uid="uid://ccd0wj2usx5os"]
|
[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")]
|
[node name="player_listing" type="PlayerListing" unique_id=772938280 node_paths=PackedStringArray("name_label", "ping_label", "ready_label", "team_dropdown")]
|
||||||
name_label = NodePath("name")
|
name_label = NodePath("name")
|
||||||
ping_label = NodePath("ping")
|
ping_label = NodePath("ping")
|
||||||
ready_label = NodePath("ready")
|
ready_label = NodePath("ready")
|
||||||
|
team_dropdown = NodePath("option_button")
|
||||||
offset_right = 319.0
|
offset_right = 319.0
|
||||||
offset_bottom = 23.0
|
offset_bottom = 23.0
|
||||||
columns = 4
|
columns = 4
|
||||||
|
|
||||||
[node name="option_button" type="OptionButton" parent="." unique_id=199328927]
|
[node name="option_button" type="OptionButton" parent="." unique_id=199328927]
|
||||||
|
custom_minimum_size = Vector2(150, 0)
|
||||||
|
custom_maximum_size = Vector2(150, -1)
|
||||||
|
clip_contents = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
||||||
[node name="name" type="Label" parent="." unique_id=635700663]
|
[node name="name" type="Label" parent="." unique_id=635700663]
|
||||||
custom_minimum_size = Vector2(400, 0)
|
custom_minimum_size = Vector2(350, 0)
|
||||||
custom_maximum_size = Vector2(400, -1)
|
custom_maximum_size = Vector2(350, -1)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Name"
|
text = "Name"
|
||||||
clip_text = true
|
clip_text = true
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use crate::{
|
|||||||
net::{
|
net::{
|
||||||
network_manager::{
|
network_manager::{
|
||||||
BallSync, NetworkManager,
|
BallSync, NetworkManager,
|
||||||
Package::{self, Kill, SelfSync, SpawnPlayer, TakeDamage},
|
Package::{self, Kill, SelfSync, SetTeam, SpawnPlayer, TakeDamage},
|
||||||
PeerKind, SyncPackage,
|
PeerKind, SyncPackage,
|
||||||
},
|
},
|
||||||
util::NetVector3,
|
util::NetVector3,
|
||||||
@ -88,6 +88,20 @@ impl GameManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct GameOptions {
|
||||||
|
/// Wether anyone is allowed to change anyone's team, or just the host and
|
||||||
|
/// the player itself.
|
||||||
|
pub allow_any_team: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GameOptions {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
allow_any_team: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(GodotClass)]
|
#[derive(GodotClass)]
|
||||||
#[class(base=Node, init)]
|
#[class(base=Node, init)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
@ -98,6 +112,8 @@ pub struct Game {
|
|||||||
pub selected_map: Option<Gd<MapResource>>,
|
pub selected_map: Option<Gd<MapResource>>,
|
||||||
pub maps: Array<Gd<MapResource>>,
|
pub maps: Array<Gd<MapResource>>,
|
||||||
|
|
||||||
|
pub opts: GameOptions,
|
||||||
|
|
||||||
is_host: bool,
|
is_host: bool,
|
||||||
player_counter: u16,
|
player_counter: u16,
|
||||||
pub self_id: Option<u16>,
|
pub self_id: Option<u16>,
|
||||||
@ -124,7 +140,7 @@ impl INode for Game {
|
|||||||
if let Some(player) = self
|
if let Some(player) = self
|
||||||
.players
|
.players
|
||||||
.iter()
|
.iter()
|
||||||
.find(|p| p.id == self.self_id.unwrap_or(0))
|
.find(|p| p.id() == self.self_id.unwrap_or(0))
|
||||||
{
|
{
|
||||||
if let Some(data) = &player.get_self_sync() {
|
if let Some(data) = &player.get_self_sync() {
|
||||||
peer.send_unreliable(socket_addr, SelfSync(data.clone()));
|
peer.send_unreliable(socket_addr, SelfSync(data.clone()));
|
||||||
@ -145,7 +161,7 @@ impl INode for Game {
|
|||||||
player.get_transform(),
|
player.get_transform(),
|
||||||
) {
|
) {
|
||||||
sync_data.insert(
|
sync_data.insert(
|
||||||
player.id,
|
player.id(),
|
||||||
SyncPackage {
|
SyncPackage {
|
||||||
movement_direction: dir,
|
movement_direction: dir,
|
||||||
look_up,
|
look_up,
|
||||||
@ -167,13 +183,14 @@ impl INode for Game {
|
|||||||
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
|
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
|
||||||
if let PeerKind::Server(peer, _) = peer {
|
if let PeerKind::Server(peer, _) = peer {
|
||||||
for player in self.players.clone() {
|
for player in self.players.clone() {
|
||||||
|
let player_id = player.id();
|
||||||
if let Some(character) = player.character {
|
if let Some(character) = player.character {
|
||||||
if character.dyn_bind().dead_for() > self.respawn_timer {
|
if character.dyn_bind().dead_for() > self.respawn_timer {
|
||||||
let character = self.spawn_player_server(player.id);
|
let character = self.spawn_player_server(player_id);
|
||||||
|
|
||||||
if let Some(character) = character {
|
if let Some(character) = character {
|
||||||
peer.broadcast_reliable(SpawnPlayer(
|
peer.broadcast_reliable(SpawnPlayer(
|
||||||
player.id,
|
player_id,
|
||||||
character.dyn_bind().get_transform(),
|
character.dyn_bind().get_transform(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -194,6 +211,8 @@ impl Game {
|
|||||||
#[signal]
|
#[signal]
|
||||||
pub fn on_player_disconnected(id: u16);
|
pub fn on_player_disconnected(id: u16);
|
||||||
#[signal]
|
#[signal]
|
||||||
|
pub fn on_player_team_changed(id: u16, team: u8);
|
||||||
|
#[signal]
|
||||||
pub fn on_map_changed(id: u8);
|
pub fn on_map_changed(id: u8);
|
||||||
|
|
||||||
pub fn singleton() -> Option<Gd<Game>> {
|
pub fn singleton() -> Option<Gd<Game>> {
|
||||||
@ -206,6 +225,21 @@ impl Game {
|
|||||||
self.selected_map_idx = map_idx;
|
self.selected_map_idx = map_idx;
|
||||||
if let Some(map) = self.maps.get(map_idx as usize) {
|
if let Some(map) = self.maps.get(map_idx as usize) {
|
||||||
self.selected_map = Some(map);
|
self.selected_map = Some(map);
|
||||||
|
|
||||||
|
let teams_max = (self.get_teams().len() - 1) as u8;
|
||||||
|
self.run_deferred(move |s| {
|
||||||
|
if NetworkManager::singleton().bind().is_host() {
|
||||||
|
for player in s.players.clone() {
|
||||||
|
s.run_deferred(move |s| {
|
||||||
|
s.try_set_player_team(
|
||||||
|
player.id(),
|
||||||
|
player.data.team.clamp(0, teams_max),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
if emit {
|
if emit {
|
||||||
self.run_deferred(move |s| s.signals().on_map_changed().emit(map_idx));
|
self.run_deferred(move |s| s.signals().on_map_changed().emit(map_idx));
|
||||||
}
|
}
|
||||||
@ -220,6 +254,40 @@ impl Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_team(&self, team: u8) -> Option<Gd<TeamResource>> {
|
||||||
|
self.get_teams().get(team as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_set_player_team(&mut self, player_id: u16, team: u8, emit: bool) {
|
||||||
|
if let Some(player) = self.find_player_mut(player_id) {
|
||||||
|
player.data.team = team;
|
||||||
|
self.run_deferred(move |_| {
|
||||||
|
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
|
||||||
|
match peer {
|
||||||
|
PeerKind::Client(peer, socket_addr) => {
|
||||||
|
peer.send_reliable(socket_addr, SetTeam(player_id, team));
|
||||||
|
}
|
||||||
|
PeerKind::Server(peer, _) => {
|
||||||
|
peer.broadcast_reliable(SetTeam(player_id, team));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if emit {
|
||||||
|
self.run_deferred(move |s| {
|
||||||
|
s.signals().on_player_team_changed().emit(player_id, team)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_player_team_change(&mut self, player_id: u16, team: u8) {
|
||||||
|
if let Some(player) = self.find_player_mut(player_id) {
|
||||||
|
player.data.team = team;
|
||||||
|
self.run_deferred(move |s| s.signals().on_player_team_changed().emit(player_id, team));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start_game(&mut self) {
|
pub fn start_game(&mut self) {
|
||||||
self.game_started = true;
|
self.game_started = true;
|
||||||
if let Some(map) = &self.selected_map {
|
if let Some(map) = &self.selected_map {
|
||||||
@ -251,21 +319,46 @@ impl Game {
|
|||||||
id
|
id
|
||||||
};
|
};
|
||||||
self.players.push(Player {
|
self.players.push(Player {
|
||||||
id,
|
|
||||||
connection_addr: addr,
|
connection_addr: addr,
|
||||||
|
data: NetPlayer {
|
||||||
|
id,
|
||||||
name,
|
name,
|
||||||
ping: 0,
|
ping: 0,
|
||||||
|
team: 0,
|
||||||
|
},
|
||||||
ready: false,
|
ready: false,
|
||||||
character: None,
|
character: None,
|
||||||
});
|
});
|
||||||
self.run_deferred(move |s| s.signals().on_new_player().emit(id));
|
self.run_deferred(move |s| s.signals().on_new_player().emit(id));
|
||||||
|
|
||||||
|
let team_with_least = self
|
||||||
|
.get_teams()
|
||||||
|
.iter_shared()
|
||||||
|
.enumerate()
|
||||||
|
.min_by(|(team_idx_a, _), (team_idx_b, _)| {
|
||||||
|
let a = self
|
||||||
|
.players
|
||||||
|
.iter()
|
||||||
|
.filter(|p| p.data.team == *team_idx_a as u8)
|
||||||
|
.count();
|
||||||
|
let b = self
|
||||||
|
.players
|
||||||
|
.iter()
|
||||||
|
.filter(|p| p.data.team == *team_idx_b as u8)
|
||||||
|
.count();
|
||||||
|
a.cmp(&b)
|
||||||
|
})
|
||||||
|
.map(|(team_idx, _)| team_idx)
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
self.try_set_player_team(id, team_with_least as u8, true);
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_players(&mut self, players: Vec<Player>) {
|
pub fn set_players(&mut self, players: Vec<Player>) {
|
||||||
self.players = players;
|
self.players = players;
|
||||||
for player in self.players.clone() {
|
for player in self.players.clone() {
|
||||||
self.run_deferred(move |s| s.signals().on_new_player().emit(player.id));
|
self.run_deferred(move |s| s.signals().on_new_player().emit(player.id()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,34 +371,34 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_player(&self, player_id: u16) -> Option<&Player> {
|
pub fn find_player(&self, player_id: u16) -> Option<&Player> {
|
||||||
self.players.iter().find(|p| p.id == player_id)
|
self.players.iter().find(|p| p.id() == player_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_player_mut(&mut self, player_id: u16) -> Option<&mut Player> {
|
pub fn find_player_mut(&mut self, player_id: u16) -> Option<&mut Player> {
|
||||||
self.players.iter_mut().find(|p| p.id == player_id)
|
self.players.iter_mut().find(|p| p.id() == player_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_player(&mut self, id: u16) {
|
pub fn remove_player(&mut self, id: u16) {
|
||||||
self.players.retain(|p| p.id != id);
|
self.players.retain(|p| p.id() != id);
|
||||||
self.run_deferred(move |s| s.signals().on_player_disconnected().emit(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) {
|
pub fn update_player_nick(&mut self, player_id: u16, nick: String) {
|
||||||
if let Some(player) = self.players.iter_mut().find(|p| p.id == player_id) {
|
if let Some(player) = self.players.iter_mut().find(|p| p.id() == player_id) {
|
||||||
player.name = nick;
|
player.data.name = nick;
|
||||||
}
|
}
|
||||||
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) {
|
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) {
|
if let Some(player) = self.players.iter_mut().find(|p| p.id() == player_id) {
|
||||||
player.ping = ping;
|
player.data.ping = ping;
|
||||||
}
|
}
|
||||||
self.run_deferred(|s| s.signals().on_players_updated().emit());
|
self.run_deferred(|s| s.signals().on_players_updated().emit());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_player_ready(&mut self, player_id: u16, ready: bool) {
|
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) {
|
if let Some(player) = self.players.iter_mut().find(|p| p.id() == player_id) {
|
||||||
player.ready = ready;
|
player.ready = ready;
|
||||||
}
|
}
|
||||||
self.run_deferred(|s| s.signals().on_players_updated().emit());
|
self.run_deferred(|s| s.signals().on_players_updated().emit());
|
||||||
@ -319,7 +412,7 @@ impl Game {
|
|||||||
} else {
|
} else {
|
||||||
self.run_deferred(|s| {
|
self.run_deferred(|s| {
|
||||||
for player in s.players.clone() {
|
for player in s.players.clone() {
|
||||||
s.spawn_player_server(player.id);
|
s.spawn_player_server(player.id());
|
||||||
}
|
}
|
||||||
s.spawn_ball(None, None, None);
|
s.spawn_ball(None, None, None);
|
||||||
});
|
});
|
||||||
@ -396,7 +489,7 @@ impl Game {
|
|||||||
&& let Some(character) = &mut player.character
|
&& let Some(character) = &mut player.character
|
||||||
{
|
{
|
||||||
character.dyn_bind_mut().swap_weapon(weapon_type);
|
character.dyn_bind_mut().swap_weapon(weapon_type);
|
||||||
let player_id = player.id;
|
let player_id = player.id();
|
||||||
self.run_deferred(move |_| {
|
self.run_deferred(move |_| {
|
||||||
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer
|
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer
|
||||||
&& let PeerKind::Server(peer, _) = peer
|
&& let PeerKind::Server(peer, _) = peer
|
||||||
@ -464,15 +557,15 @@ impl Game {
|
|||||||
// Method called on the client-side whenever a player has spawned
|
// Method called on the client-side whenever a player has spawned
|
||||||
pub fn spawn_player_client(&mut self, id: u16, transform: NetTransform) {
|
pub fn spawn_player_client(&mut self, id: u16, transform: NetTransform) {
|
||||||
if let Some(map) = &mut self.current_map {
|
if let Some(map) = &mut self.current_map {
|
||||||
if let Some(player) = self.players.iter_mut().find(|p| p.id == id) {
|
if let Some(player) = self.players.iter_mut().find(|p| p.id() == id) {
|
||||||
if let Some(character) = &mut player.character {
|
if let Some(character) = &mut player.character {
|
||||||
// This is a respawn, delete old character
|
// This is a respawn, delete old character
|
||||||
character.queue_free();
|
character.queue_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
let character = map.bind_mut().spawn_player(
|
let character = map.bind_mut().spawn_player(
|
||||||
player.id,
|
player.id(),
|
||||||
player.id == self.self_id.unwrap_or(0),
|
player.id() == self.self_id.unwrap_or(0),
|
||||||
Some(transform),
|
Some(transform),
|
||||||
);
|
);
|
||||||
player.character = character;
|
player.character = character;
|
||||||
@ -495,8 +588,8 @@ impl Game {
|
|||||||
},
|
},
|
||||||
) in sync_data
|
) in sync_data
|
||||||
{
|
{
|
||||||
if let Some(player) = self.players.iter_mut().find(|p| p.id == player_id) {
|
if let Some(player) = self.players.iter_mut().find(|p| p.id() == player_id) {
|
||||||
if player.id != self.self_id.unwrap_or(0) {
|
if player.id() != self.self_id.unwrap_or(0) {
|
||||||
// Sync remote players always
|
// Sync remote players always
|
||||||
player.set_transform(transform);
|
player.set_transform(transform);
|
||||||
player.set_move_dir(movement_direction);
|
player.set_move_dir(movement_direction);
|
||||||
@ -541,7 +634,7 @@ impl Game {
|
|||||||
) -> bool {
|
) -> bool {
|
||||||
let self_id = self.self_id.clone().unwrap_or(0);
|
let self_id = self.self_id.clone().unwrap_or(0);
|
||||||
if let Some(player) = self.find_player_mut(player_id) {
|
if let Some(player) = self.find_player_mut(player_id) {
|
||||||
if player.id != self_id {
|
if player.id() != self_id {
|
||||||
player.try_shoot(to, transform, look_up, deal_damage)
|
player.try_shoot(to, transform, look_up, deal_damage)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -590,10 +683,8 @@ impl Game {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
pub id: u16,
|
|
||||||
pub connection_addr: SocketAddr,
|
pub connection_addr: SocketAddr,
|
||||||
pub name: String,
|
pub data: NetPlayer,
|
||||||
pub ping: u128,
|
|
||||||
pub ready: bool,
|
pub ready: bool,
|
||||||
pub character: Option<DynGd<CharacterBody3D, dyn IPlayer + 'static>>,
|
pub character: Option<DynGd<CharacterBody3D, dyn IPlayer + 'static>>,
|
||||||
}
|
}
|
||||||
@ -688,6 +779,10 @@ impl Player {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> u16 {
|
||||||
|
self.data.id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
@ -695,15 +790,14 @@ pub struct NetPlayer {
|
|||||||
pub id: u16,
|
pub id: u16,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub ping: u128,
|
pub ping: u128,
|
||||||
|
pub team: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NetPlayer> for Player {
|
impl From<NetPlayer> for Player {
|
||||||
fn from(value: NetPlayer) -> Self {
|
fn from(value: NetPlayer) -> Self {
|
||||||
Player {
|
Player {
|
||||||
id: value.id,
|
|
||||||
connection_addr: SocketAddr::from(([0, 0, 0, 0], 0)),
|
connection_addr: SocketAddr::from(([0, 0, 0, 0], 0)),
|
||||||
name: value.name,
|
data: value,
|
||||||
ping: value.ping,
|
|
||||||
ready: false,
|
ready: false,
|
||||||
character: None,
|
character: None,
|
||||||
}
|
}
|
||||||
@ -712,10 +806,6 @@ impl From<NetPlayer> for Player {
|
|||||||
|
|
||||||
impl From<Player> for NetPlayer {
|
impl From<Player> for NetPlayer {
|
||||||
fn from(value: Player) -> Self {
|
fn from(value: Player) -> Self {
|
||||||
NetPlayer {
|
value.data
|
||||||
id: value.id,
|
|
||||||
name: value.name,
|
|
||||||
ping: value.ping,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -90,8 +90,8 @@ impl INode for NetworkManager {
|
|||||||
.cloned();
|
.cloned();
|
||||||
if let Some(player) = player {
|
if let Some(player) = player {
|
||||||
game.bind_mut()
|
game.bind_mut()
|
||||||
.update_player_ping(player.id, connection.ping.as_millis());
|
.update_player_ping(player.id(), connection.ping.as_millis());
|
||||||
pings.insert(player.id, connection.ping.as_millis());
|
pings.insert(player.id(), connection.ping.as_millis());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,6 +255,7 @@ pub enum Package {
|
|||||||
SetSelfNick(String),
|
SetSelfNick(String),
|
||||||
NewPlayer(NetPlayer),
|
NewPlayer(NetPlayer),
|
||||||
PlayerLeft(NetPlayer),
|
PlayerLeft(NetPlayer),
|
||||||
|
SetTeam(u16, u8),
|
||||||
|
|
||||||
// Lobby packages
|
// Lobby packages
|
||||||
SetReady(u16, bool),
|
SetReady(u16, bool),
|
||||||
|
|||||||
@ -161,6 +161,11 @@ impl NetworkManager {
|
|||||||
game.bind_mut().handle_swap_weapon(id, weapon_type, true);
|
game.bind_mut().handle_swap_weapon(id, weapon_type, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Package::SetTeam(player_id, team) => {
|
||||||
|
if let Some(game) = &mut Game::singleton() {
|
||||||
|
game.bind_mut().handle_player_team_change(player_id, team);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -212,7 +217,7 @@ impl NetworkManager {
|
|||||||
let player_id = game
|
let player_id = game
|
||||||
.bind()
|
.bind()
|
||||||
.find_player_by_addr(&connection.address)
|
.find_player_by_addr(&connection.address)
|
||||||
.map(|p| p.id);
|
.map(|p| p.id());
|
||||||
if let Some(player_id) = player_id {
|
if let Some(player_id) = player_id {
|
||||||
peer.broadcast_reliable(Package::PlayerLeft(
|
peer.broadcast_reliable(Package::PlayerLeft(
|
||||||
game.bind().find_player(player_id).unwrap().clone().into(),
|
game.bind().find_player(player_id).unwrap().clone().into(),
|
||||||
@ -234,10 +239,10 @@ impl NetworkManager {
|
|||||||
game.bind().find_player_by_addr(&conn.address).cloned();
|
game.bind().find_player_by_addr(&conn.address).cloned();
|
||||||
if let Some(player) = player {
|
if let Some(player) = player {
|
||||||
peer.broadcast_reliable(Package::SetNick(
|
peer.broadcast_reliable(Package::SetNick(
|
||||||
player.id,
|
player.id(),
|
||||||
nick.clone(),
|
nick.clone(),
|
||||||
));
|
));
|
||||||
game.bind_mut().update_player_nick(player.id, nick);
|
game.bind_mut().update_player_nick(player.id(), nick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,8 +251,11 @@ impl NetworkManager {
|
|||||||
let player =
|
let player =
|
||||||
game.bind().find_player_by_addr(&conn.address).cloned();
|
game.bind().find_player_by_addr(&conn.address).cloned();
|
||||||
if let Some(player) = player {
|
if let Some(player) = player {
|
||||||
game.bind_mut().update_player_ready(player.id, is_ready);
|
game.bind_mut().update_player_ready(player.id(), is_ready);
|
||||||
peer.broadcast_reliable(Package::SetReady(player.id, is_ready));
|
peer.broadcast_reliable(Package::SetReady(
|
||||||
|
player.id(),
|
||||||
|
is_ready,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,7 +265,7 @@ impl NetworkManager {
|
|||||||
if let Some(transform) = player.get_transform() {
|
if let Some(transform) = player.get_transform() {
|
||||||
peer.send_reliable(
|
peer.send_reliable(
|
||||||
&conn.address,
|
&conn.address,
|
||||||
Package::SpawnPlayer(player.id, transform),
|
Package::SpawnPlayer(player.id(), transform),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,8 +285,8 @@ impl NetworkManager {
|
|||||||
let player =
|
let player =
|
||||||
game.bind().find_player_by_addr(&conn.address).cloned();
|
game.bind().find_player_by_addr(&conn.address).cloned();
|
||||||
if let Some(player) = player {
|
if let Some(player) = player {
|
||||||
game.bind_mut().handle_jump(player.id);
|
game.bind_mut().handle_jump(player.id());
|
||||||
peer.broadcast_reliable(Package::Jump(player.id));
|
peer.broadcast_reliable(Package::Jump(player.id()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,19 +296,35 @@ impl NetworkManager {
|
|||||||
game.bind().find_player_by_addr(&conn.address).cloned();
|
game.bind().find_player_by_addr(&conn.address).cloned();
|
||||||
if let Some(player) = player {
|
if let Some(player) = player {
|
||||||
if game.bind_mut().handle_shoot(
|
if game.bind_mut().handle_shoot(
|
||||||
player.id,
|
player.id(),
|
||||||
to.into(),
|
to.into(),
|
||||||
transform,
|
transform,
|
||||||
look_up,
|
look_up,
|
||||||
true,
|
true,
|
||||||
) {
|
) {
|
||||||
peer.broadcast_reliable(Package::Shoot(
|
peer.broadcast_reliable(Package::Shoot(
|
||||||
player.id, to, transform, look_up,
|
player.id(),
|
||||||
|
to,
|
||||||
|
transform,
|
||||||
|
look_up,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Package::SetTeam(player_id, team) => {
|
||||||
|
if let Some(game) = &mut Game::singleton() {
|
||||||
|
let self_id = game
|
||||||
|
.bind()
|
||||||
|
.find_player_by_addr(&conn.address)
|
||||||
|
.map(|p| p.id());
|
||||||
|
if let Some(self_id) = self_id {
|
||||||
|
if game.bind().opts.allow_any_team || self_id == player_id {
|
||||||
|
game.bind_mut().try_set_player_team(player_id, team, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use std::{f32::consts::PI, ops::Neg};
|
|||||||
use godot::{
|
use godot::{
|
||||||
classes::{
|
classes::{
|
||||||
Camera3D, CharacterBody3D, CollisionShape3D, GpuParticles3D, ICharacterBody3D, Input,
|
Camera3D, CharacterBody3D, CollisionShape3D, GpuParticles3D, ICharacterBody3D, Input,
|
||||||
InputEvent, InputEventMouseMotion, Label, input::MouseMode,
|
InputEvent, InputEventMouseMotion, Label, Label3D, input::MouseMode,
|
||||||
},
|
},
|
||||||
obj::WithBaseField,
|
obj::WithBaseField,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@ -535,6 +535,8 @@ pub struct RemotePlayer {
|
|||||||
spectator_camera: Option<Gd<Camera3D>>,
|
spectator_camera: Option<Gd<Camera3D>>,
|
||||||
#[export]
|
#[export]
|
||||||
ball_origin: Option<Gd<Node3D>>,
|
ball_origin: Option<Gd<Node3D>>,
|
||||||
|
#[export]
|
||||||
|
name_label: Option<Gd<Label3D>>,
|
||||||
|
|
||||||
pub player_id: Option<u16>,
|
pub player_id: Option<u16>,
|
||||||
|
|
||||||
@ -692,6 +694,18 @@ impl IPlayer for RemotePlayer {
|
|||||||
#[godot_api]
|
#[godot_api]
|
||||||
impl ICharacterBody3D for RemotePlayer {
|
impl ICharacterBody3D for RemotePlayer {
|
||||||
fn ready(&mut self) {
|
fn ready(&mut self) {
|
||||||
|
self.run_deferred(|s| {
|
||||||
|
if let Some(player_id) = s.player_id
|
||||||
|
&& let Some(game) = Game::singleton()
|
||||||
|
&& let Some(player) = game.bind().find_player(player_id)
|
||||||
|
&& let Some(team) = game.bind().get_team(player.data.team)
|
||||||
|
&& let Some(name_label) = &mut s.name_label
|
||||||
|
{
|
||||||
|
name_label.set_text(&player.data.name);
|
||||||
|
name_label.set_modulate(team.bind().color);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
self.swap_weapon(WeaponType::Raygun);
|
self.swap_weapon(WeaponType::Raygun);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -143,7 +143,7 @@ impl LobbyPanel {
|
|||||||
for player in &game.bind().players {
|
for player in &game.bind().players {
|
||||||
if let Some(node) = prefab.instantiate() {
|
if let Some(node) = prefab.instantiate() {
|
||||||
let mut listing = node.cast::<PlayerListing>();
|
let mut listing = node.cast::<PlayerListing>();
|
||||||
listing.bind_mut().player_id = Some(player.id);
|
listing.bind_mut().player_id = Some(player.id());
|
||||||
listing.bind_mut().update_teams(game.bind().get_teams());
|
listing.bind_mut().update_teams(game.bind().get_teams());
|
||||||
listing.bind_mut().update();
|
listing.bind_mut().update();
|
||||||
list.add_child(&listing);
|
list.add_child(&listing);
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
use godot::{
|
use godot::{
|
||||||
classes::{GridContainer, Label, OptionButton},
|
classes::{GridContainer, IGridContainer, Label, OptionButton, TextEdit},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{game_manager::Game, team_resource::TeamResource};
|
use crate::{
|
||||||
|
game_manager::{Game, GameOptions},
|
||||||
|
net::network_manager::NetworkManager,
|
||||||
|
team_resource::TeamResource,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(GodotClass)]
|
#[derive(GodotClass)]
|
||||||
#[class(base=GridContainer, init)]
|
#[class(base=GridContainer, init)]
|
||||||
@ -22,14 +26,60 @@ pub struct PlayerListing {
|
|||||||
base: Base<GridContainer>,
|
base: Base<GridContainer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl IGridContainer for PlayerListing {
|
||||||
|
fn ready(&mut self) {
|
||||||
|
self.run_deferred(|s| {
|
||||||
|
if let Some(game) = &mut Game::singleton() {
|
||||||
|
game.bind_mut()
|
||||||
|
.signals()
|
||||||
|
.on_player_team_changed()
|
||||||
|
.connect_other(s, |s, id, team| {
|
||||||
|
if id == s.player_id.unwrap_or(0) {
|
||||||
|
s.on_team_update(team);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(team_dropdown) = self.team_dropdown.clone() {
|
||||||
|
team_dropdown
|
||||||
|
.signals()
|
||||||
|
.item_selected()
|
||||||
|
.connect_other(self, |s, selection| {
|
||||||
|
s.on_team_selection_changed(selection as u8);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(game) = &Game::singleton() {
|
||||||
|
self.update_game_options(&game.bind().opts, game.bind().self_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PlayerListing {
|
impl PlayerListing {
|
||||||
|
pub fn update_game_options(&mut self, opts: &GameOptions, self_id: Option<u16>) {
|
||||||
|
let is_host = NetworkManager::singleton().bind().is_host();
|
||||||
|
|
||||||
|
if let Some(dropdown) = &mut self.team_dropdown {
|
||||||
|
dropdown.set_disabled(!is_host && !opts.allow_any_team && self.player_id != self_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self) {
|
||||||
if let Some(player_id) = &self.player_id
|
if let Some(player_id) = &self.player_id
|
||||||
&& let Some(game) = Game::singleton()
|
&& let Some(game) = Game::singleton()
|
||||||
&& let Some(player) = game.bind().find_player(*player_id)
|
&& let Some(player) = game.bind().find_player(*player_id)
|
||||||
{
|
{
|
||||||
if let Some(player_label) = &mut self.name_label {
|
if let Some(player_label) = &mut self.name_label {
|
||||||
player_label.set_text(&format!("{} ({})", player.name, player.connection_addr));
|
player_label.set_text(&format!(
|
||||||
|
"{} ({})",
|
||||||
|
player.data.name, player.connection_addr
|
||||||
|
));
|
||||||
|
|
||||||
|
if let Some(team) = game.bind().get_team(player.data.team) {
|
||||||
|
player_label.add_theme_color_override("font_color", team.bind().color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ready_label) = &mut self.ready_label {
|
if let Some(ready_label) = &mut self.ready_label {
|
||||||
@ -41,17 +91,53 @@ impl PlayerListing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ping_label) = &mut self.ping_label {
|
if let Some(ping_label) = &mut self.ping_label {
|
||||||
ping_label.set_text(&format!("({}ms)", player.ping));
|
ping_label.set_text(&format!("({}ms)", player.data.ping));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(dropdown) = &mut self.team_dropdown {
|
||||||
|
dropdown.select(player.data.team as i32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_teams(&mut self, teams: Array<Gd<TeamResource>>) {
|
pub fn update_teams(&mut self, teams: Array<Gd<TeamResource>>) {
|
||||||
if let Some(dropdown) = &mut self.team_dropdown {
|
if let Some(dropdown) = &mut self.team_dropdown {
|
||||||
|
let prev_selection = dropdown.get_selected();
|
||||||
dropdown.clear();
|
dropdown.clear();
|
||||||
for team in teams.iter_shared() {
|
for team in teams.iter_shared() {
|
||||||
dropdown.add_item(&team.bind().name);
|
dropdown.add_item(&team.bind().name);
|
||||||
}
|
}
|
||||||
|
dropdown.select(prev_selection.min((teams.len() - 1) as i32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_team_selection_changed(&mut self, team: u8) {
|
||||||
|
if let Some(mut game) = Game::singleton() {
|
||||||
|
game.bind_mut()
|
||||||
|
.try_set_player_team(self.player_id.unwrap_or(0), team, false);
|
||||||
|
|
||||||
|
if let Some(player) = game.bind().find_player(self.player_id.unwrap_or(0))
|
||||||
|
&& let Some(player_label) = &mut self.name_label
|
||||||
|
&& let Some(team) = game.bind().get_team(player.data.team)
|
||||||
|
{
|
||||||
|
godot_print!("Setting color");
|
||||||
|
player_label.add_theme_color_override("font_color", team.bind().color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_team_update(&mut self, team: u8) {
|
||||||
|
if let Some(dropdown) = &mut self.team_dropdown {
|
||||||
|
dropdown.select(team as i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(game) = Game::singleton()
|
||||||
|
&& let Some(player) = game.bind().find_player(self.player_id.unwrap_or(0))
|
||||||
|
&& let Some(player_label) = &mut self.name_label
|
||||||
|
&& let Some(team) = game.bind().get_team(player.data.team)
|
||||||
|
{
|
||||||
|
godot_print!("Setting color");
|
||||||
|
player_label.add_theme_color_override("font_color", team.bind().color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user