Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Benjamin Lee
ball-gfx-hal
Commits
ce1457fd
Commit
ce1457fd
authored
Jan 28, 2019
by
Benjamin Lee
💬
Browse files
Clients can now change game settings.
parent
2bfbf3b3
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/game/client.rs
View file @
ce1457fd
use
crate
::
game
::{
Event
,
GameSettings
,
GetPlayer
,
Input
,
InterpolatedSnapshot
,
...
...
@@ -17,6 +18,7 @@ use nalgebra::Point2;
use
parking_lot
::
Mutex
;
use
std
::
borrow
::
Cow
;
use
std
::
collections
::{
HashMap
,
VecDeque
};
use
std
::
sync
::
atomic
::{
AtomicBool
,
Ordering
};
use
std
::
sync
::
Arc
;
use
std
::
time
::
Instant
;
...
...
@@ -38,15 +40,23 @@ pub struct Game {
players
:
HashMap
<
PlayerId
,
StaticPlayerState
>
,
snapshots
:
VecDeque
<
(
Snapshot
,
Instant
)
>
,
round
:
RoundState
,
settings
:
GameSettings
,
settings_handle
:
Arc
<
SettingsHandle
>
,
cursor
:
Arc
<
Mutex
<
Point2
<
f32
>>>
,
events
:
Receiver
<
Event
>
,
/// Player id for this client.
player_id
:
PlayerId
,
}
pub
struct
SettingsHandle
{
dirty
:
AtomicBool
,
settings
:
Mutex
<
GameSettings
>
,
}
pub
struct
GameHandle
{
events
:
Sender
<
Event
>
,
cursor
:
Arc
<
Mutex
<
Point2
<
f32
>>>
,
pub
settings
:
Arc
<
SettingsHandle
>
,
}
impl
<
'a
,
'b
>
GetPlayer
for
&
'b
Player
<
'a
>
{
...
...
@@ -128,10 +138,28 @@ impl GameHandle {
}
}
impl
SettingsHandle
{
pub
fn
dirty
(
&
self
)
->
Option
<
GameSettings
>
{
if
self
.dirty
.load
(
Ordering
::
SeqCst
)
{
self
.dirty
.store
(
false
,
Ordering
::
SeqCst
);
let
settings
=
self
.settings
.lock
();
Some
(
*
settings
)
}
else
{
None
}
}
pub
fn
settings
(
&
self
)
->
GameSettings
{
let
settings
=
self
.settings
.lock
();
*
settings
}
}
impl
Game
{
pub
fn
new
(
players
:
HashMap
<
PlayerId
,
StaticPlayerState
>
,
snapshot
:
Snapshot
,
settings
:
GameSettings
,
player_id
:
PlayerId
,
cursor
:
Point2
<
f32
>
,
)
->
(
Game
,
GameHandle
)
{
...
...
@@ -139,6 +167,10 @@ impl Game {
snapshots
.push_back
((
snapshot
,
Instant
::
now
()));
let
(
events_tx
,
events_rx
)
=
channel
::
bounded
(
16
);
let
cursor
=
Arc
::
new
(
Mutex
::
new
(
cursor
));
let
settings_handle
=
Arc
::
new
(
SettingsHandle
{
dirty
:
AtomicBool
::
new
(
false
),
settings
:
Mutex
::
new
(
settings
),
});
let
game
=
Game
{
players
,
snapshots
,
...
...
@@ -146,14 +178,31 @@ impl Game {
events
:
events_rx
,
round
:
RoundState
::
default
(),
player_id
,
settings
,
settings_handle
:
Arc
::
clone
(
&
settings_handle
),
};
let
handle
=
GameHandle
{
cursor
,
events
:
events_tx
,
settings
:
settings_handle
,
};
(
game
,
handle
)
}
pub
fn
settings
(
&
self
)
->
&
GameSettings
{
&
self
.settings
}
/// Modifies the game settings and flags the change to be sent to
/// the server.
pub
fn
set_settings
(
&
mut
self
,
settings
:
GameSettings
)
{
self
.settings
=
settings
;
let
mut
shared
=
self
.settings_handle.settings
.lock
();
*
shared
=
settings
;
drop
(
shared
);
self
.settings_handle.dirty
.store
(
true
,
Ordering
::
SeqCst
);
}
/// Handles events from the server.
pub
fn
handle_events
(
&
mut
self
)
{
for
event
in
self
.events
.try_iter
()
{
...
...
@@ -162,6 +211,9 @@ impl Game {
info!
(
"transitioning to round state {:?}"
,
round
);
self
.round
=
round
;
},
Event
::
Settings
(
settings
)
=>
{
self
.settings
=
settings
;
},
Event
::
NewPlayer
{
id
,
static_state
,
...
...
@@ -208,22 +260,26 @@ impl Game {
}
}
/// Removes any old snapshots that are no longer needed for
/// interpolation.
pub
fn
clean_old_snapshots
(
&
mut
self
,
time
:
Instant
,
delay
:
f32
)
{
let
delayed_time
=
time
-
SNAPSHOT_RATE
.mul_f64
(
delay
.into
());
while
self
.snapshots
.len
()
>
1
&&
delayed_time
>
self
.snapshots
[
1
]
.1
{
// Yay for short circuiting &&
self
.snapshots
.pop_front
();
}
}
/// Interpolates snapshots with delay and returns the resulting
/// set of player states.
pub
fn
interpolated_players
(
&
mut
self
,
&
self
,
time
:
Instant
,
cursor
:
Point2
<
f32
>
,
delay
:
f32
,
)
->
Players
<
InterpolatedSnapshot
>
{
let
delayed_time
=
time
-
SNAPSHOT_RATE
.mul_f64
(
delay
.into
());
// Get rid of old snapshots.
while
self
.snapshots
.len
()
>
1
&&
delayed_time
>
self
.snapshots
[
1
]
.1
{
// Yay for short circuiting &&
self
.snapshots
.pop_front
();
}
let
(
ref
old
,
old_time
)
=
self
.snapshots
[
0
];
let
snapshot
=
match
self
.snapshots
.get
(
1
)
{
Some
(
&
(
ref
new
,
new_time
))
=>
{
...
...
src/game/mod.rs
View file @
ce1457fd
...
...
@@ -14,11 +14,6 @@ pub mod snapshot;
pub
use
self
::
snapshot
::
*
;
pub
const
BALL_RADIUS
:
f32
=
0.15
;
pub
const
CURSOR_RADIUS
:
f32
=
0.05
;
const
SPRING_CONSTANT
:
f32
=
8.0
;
const
BALL_START_DISTANCE
:
f32
=
0.3
;
const
BALL_START_SPEED
:
f32
=
1.0
;
pub
type
PlayerId
=
u16
;
/// Finite state machine for the round state.
...
...
@@ -35,9 +30,33 @@ pub enum RoundState {
PostRound
(
f32
),
}
#[derive(Copy,
Clone,
Debug,
PartialEq,
Serialize,
Deserialize)]
pub
struct
GameSettings
{
pub
ball_radius
:
f32
,
pub
cursor_radius
:
f32
,
pub
spring_constant
:
f32
,
pub
ball_start_distance
:
f32
,
pub
ball_start_speed
:
f32
,
pub
bounds_radius
:
f32
,
}
impl
Default
for
GameSettings
{
fn
default
()
->
GameSettings
{
GameSettings
{
ball_radius
:
0.15
,
cursor_radius
:
0.05
,
spring_constant
:
8.0
,
ball_start_distance
:
0.3
,
ball_start_speed
:
1.0
,
bounds_radius
:
1.0
,
}
}
}
#[derive(Debug,
Clone,
Serialize,
Deserialize)]
pub
enum
Event
{
RoundState
(
RoundState
),
Settings
(
GameSettings
),
NewPlayer
{
id
:
PlayerId
,
static_state
:
StaticPlayerState
,
...
...
@@ -75,36 +94,47 @@ pub struct PlayerState {
impl
Ball
{
/// Gets the starting state of the ball for a given starting
/// cursor position.
pub
fn
starting
(
cursor
:
Point2
<
f32
>
)
->
Ball
{
pub
fn
starting
(
cursor
:
Point2
<
f32
>
,
settings
:
&
GameSettings
)
->
Ball
{
let
cursor_dir
=
(
cursor
-
Point2
::
origin
())
.normalize
();
let
mut
position
=
cursor
+
cursor_dir
*
BALL_START_DISTANCE
;
if
nalgebra
::
distance
(
&
position
,
&
Point2
::
origin
())
>
1.0
-
BALL_RADIUS
let
mut
position
=
cursor
+
cursor_dir
*
settings
.ball_start_distance
;
let
max_dist
=
settings
.bounds_radius
-
settings
.ball_radius
;
if
nalgebra
::
distance_squared
(
&
position
,
&
Point2
::
origin
())
>
max_dist
*
max_dist
{
position
.coords
.normalize_mut
();
position
*=
1.0
-
BALL_RADIUS
;
position
*=
max_dist
;
}
Ball
{
position
,
velocity
:
cursor_dir
*
BALL_START_SPEED
,
velocity
:
cursor_dir
*
settings
.ball_start_speed
,
}
}
/// Steps the ball forward in time using a provided cursor
/// location.
pub
fn
tick
(
&
mut
self
,
dt
:
f32
,
cursor
:
Option
<
Point2
<
f32
>>
)
{
pub
fn
tick
(
&
mut
self
,
dt
:
f32
,
cursor
:
Option
<
Point2
<
f32
>>
,
settings
:
&
GameSettings
,
)
{
if
let
Some
(
cursor
)
=
cursor
{
let
displacement
=
self
.position
-
cursor
;
self
.velocity
-=
SPRING_CONSTANT
*
displacement
*
dt
;
self
.velocity
-=
settings
.spring_constant
*
displacement
*
dt
;
}
self
.position
+=
self
.velocity
*
dt
;
}
}
/// Clamps a cursor position within bounds.
pub
fn
clamp_cursor
(
cursor
:
Point2
<
f32
>
)
->
Point2
<
f32
>
{
pub
fn
clamp_cursor
(
cursor
:
Point2
<
f32
>
,
settings
:
&
GameSettings
,
)
->
Point2
<
f32
>
{
let
dist_sq
=
(
cursor
-
Point2
::
origin
())
.norm_squared
();
if
dist_sq
>
(
1.0
-
CURSOR_RADIUS
)
{
(
1.0
-
CURSOR_RADIUS
)
*
cursor
/
dist_sq
.sqrt
()
let
max_dist
=
settings
.bounds_radius
-
settings
.cursor_radius
;
if
dist_sq
>
max_dist
*
max_dist
{
max_dist
*
cursor
/
dist_sq
.sqrt
()
}
else
{
cursor
}
...
...
@@ -115,10 +145,10 @@ impl PlayerState {
///
/// The player's ball is placed a set distance further away from
/// the origin than the cursor.
pub
fn
new
(
cursor
:
Point2
<
f32
>
)
->
PlayerState
{
pub
fn
new
(
cursor
:
Point2
<
f32
>
,
settings
:
&
GameSettings
)
->
PlayerState
{
PlayerState
{
cursor
:
Some
(
cursor
),
ball
:
Ball
::
starting
(
cursor
),
ball
:
Ball
::
starting
(
cursor
,
settings
),
}
}
...
...
@@ -130,8 +160,8 @@ impl PlayerState {
}
/// Steps the player forward in time.
pub
fn
tick
(
&
mut
self
,
dt
:
f32
)
{
self
.ball
.tick
(
dt
,
self
.cursor
);
pub
fn
tick
(
&
mut
self
,
dt
:
f32
,
settings
:
&
GameSettings
)
{
self
.ball
.tick
(
dt
,
self
.cursor
,
settings
);
}
/// Returns whether the player is still alive.
...
...
@@ -150,7 +180,7 @@ pub trait GetPlayer {
fn
static_state
(
self
)
->
Self
::
StaticState
;
/// Generates a set of circles to draw this player.
fn
draw
(
self
,
scale
:
f32
)
->
SmallVec
<
[
Circle
;
2
]
>
fn
draw
(
self
,
scale
:
f32
,
settings
:
&
GameSettings
)
->
SmallVec
<
[
Circle
;
2
]
>
where
Self
:
Sized
+
Copy
,
{
...
...
@@ -160,14 +190,14 @@ pub trait GetPlayer {
// Ball
circles
.push
(
Circle
{
center
:
state
.ball.position
*
scale
,
radius
:
BALL_RADIUS
*
scale
,
radius
:
settings
.ball_radius
*
scale
,
color
,
});
if
let
Some
(
cursor
)
=
state
.cursor
{
// Cursor, if alive
circles
.push
(
Circle
{
center
:
cursor
*
scale
,
radius
:
CURSOR_RADIUS
*
scale
,
radius
:
settings
.cursor_radius
*
scale
,
color
,
});
}
...
...
src/game/physics.rs
View file @
ce1457fd
use
crate
::
game
::{
Ball
,
BALL_RADIUS
,
CURSOR_RADIUS
};
use
crate
::
game
::{
Ball
,
GameSettings
};
use
nalgebra
::{
Point2
,
Vector2
};
#[derive(Debug,
Copy,
Clone)]
...
...
@@ -45,20 +45,18 @@ impl<V> Circle<V> {
}
/// Returns the physics circle corresponding to the boundary.
pub
fn
bounds
()
->
Circle
<
Static
>
{
Circle
::
inner
(
1.0
,
Point2
::
origin
(),
Static
)
pub
fn
bounds
(
settings
:
&
GameSettings
)
->
Circle
<
Static
>
{
Circle
::
inner
(
settings
.bounds_radius
,
Point2
::
origin
(),
Static
)
}
/// Returns the physics circle corresponding to a given cursor
/// position.
pub
fn
cursor
(
cursor
:
Point2
<
f32
>
)
->
Circle
<
Static
>
{
Circle
::
outer
(
CURSOR_RADIUS
,
cursor
,
Static
)
pub
fn
cursor
(
cursor
:
Point2
<
f32
>
,
settings
:
&
GameSettings
)
->
Circle
<
Static
>
{
Circle
::
outer
(
settings
.cursor_radius
,
cursor
,
Static
)
}
impl
From
<
Ball
>
for
Circle
<
Vector2
<
f32
>>
{
fn
from
(
ball
:
Ball
)
->
Circle
<
Vector2
<
f32
>>
{
Circle
::
outer
(
BALL_RADIUS
,
ball
.position
,
ball
.velocity
)
}
pub
fn
ball
(
ball
:
Ball
,
settings
:
&
GameSettings
)
->
Circle
<
Vector2
<
f32
>>
{
Circle
::
outer
(
settings
.ball_radius
,
ball
.position
,
ball
.velocity
)
}
impl
From
<
Circle
<
Vector2
<
f32
>>>
for
Ball
{
...
...
src/game/server.rs
View file @
ce1457fd
...
...
@@ -3,6 +3,7 @@ use crate::game::{
step_dt
,
Ball
,
Event
,
GameSettings
,
GetPlayer
,
PlayerId
,
PlayerState
,
...
...
@@ -56,6 +57,7 @@ pub struct Player {
pub
struct
Game
{
pub
players
:
HashMap
<
PlayerId
,
Player
>
,
pub
round
:
RoundState
,
pub
settings
:
GameSettings
,
next_id
:
PlayerId
,
}
...
...
@@ -107,7 +109,7 @@ impl Game {
}
if
!
self
.round
.running
()
{
player
.state.ball
=
Ball
::
starting
(
cursor
);
player
.state.ball
=
Ball
::
starting
(
cursor
,
&
self
.settings
);
}
true
}
...
...
@@ -135,10 +137,13 @@ impl Game {
return
transition
.map
(
Event
::
RoundState
)
.into_iter
();
}
// To avoid borrow issues.
let
settings
=
&
self
.settings
;
for
dt
in
step_dt
(
dt
,
1.0
/
60.0
)
{
// Calculate individual ball spring physics.
for
player
in
self
.players
.values_mut
()
{
player
.state
.tick
(
dt
);
player
.state
.tick
(
dt
,
settings
);
}
// Check for collisions between balls.
...
...
@@ -148,8 +153,10 @@ impl Game {
// This ensures every unordered pair only gets checked
// once.
if
id_a
<
id_b
{
let
mut
circle_a
=
a
.state.ball
.into
();
let
mut
circle_b
=
b
.state.ball
.into
();
let
mut
circle_a
=
physics
::
ball
(
a
.state.ball
,
settings
);
let
mut
circle_b
=
physics
::
ball
(
b
.state.ball
,
settings
);
if
resolve_collision
(
&
mut
circle_a
,
&
mut
circle_b
)
{
collisions
.push
((
id_a
,
circle_a
));
collisions
.push
((
id_b
,
circle_b
));
...
...
@@ -166,8 +173,11 @@ impl Game {
// Check for collisions with walls.
for
(
&
id
,
player
)
in
self
.players
.iter_mut
()
{
let
alive
=
player
.state
.alive
();
let
mut
circle
=
player
.state.ball
.into
();
if
resolve_collision
(
&
mut
circle
,
&
mut
physics
::
bounds
())
{
let
mut
circle
=
physics
::
ball
(
player
.state.ball
,
settings
);
if
resolve_collision
(
&
mut
circle
,
&
mut
physics
::
bounds
(
settings
),
)
{
player
.state.ball
=
circle
.into
();
if
alive
{
info!
(
"{} killed {}"
,
id
,
id
);
...
...
@@ -181,7 +191,7 @@ impl Game {
// Check for collisions with cursor.
for
(
&
id
,
player
)
in
self
.players
.iter
()
{
if
let
Some
(
cursor
)
=
player
.state.cursor
{
let
circle_cursor
=
physics
::
cursor
(
cursor
);
let
circle_cursor
=
physics
::
cursor
(
cursor
,
settings
);
for
(
&
id_ball
,
player_ball
)
in
self
.players
.iter
()
{
if
id
==
id_ball
{
// Don't let players kill themselves.
...
...
@@ -189,7 +199,8 @@ impl Game {
continue
;
}
let
circle_ball
=
player_ball
.state.ball
.into
();
let
circle_ball
=
physics
::
ball
(
player_ball
.state.ball
,
settings
);
if
check_collision
(
&
circle_cursor
,
&
circle_ball
)
{
info!
(
"{} killed {}"
,
id_ball
,
id
);
deaths
.push
(
id
);
...
...
@@ -260,7 +271,7 @@ impl Game {
color
:
Lch
::
new
(
75.0
,
80.0
,
lab_hue
)
.into
(),
};
let
player
=
Player
{
state
:
PlayerState
::
new
(
cursor
),
state
:
PlayerState
::
new
(
cursor
,
&
self
.settings
),
static_state
:
static_state
.clone
(),
hue
,
};
...
...
src/networking/client.rs
View file @
ce1457fd
use
crate
::
debug
::{
NetworkStats
,
NETWORK_STATS_RATE
};
use
crate
::
game
::{
client
::{
Game
,
GameHandle
},
GameSettings
,
Input
,
};
use
crate
::
networking
::
connection
::{
Connection
,
HEADER_BYTES
};
...
...
@@ -16,13 +17,13 @@ use crate::networking::{
PING_RATE
,
};
use
crossbeam
::
channel
::{
self
,
Receiver
,
Sender
};
use
log
::{
error
,
info
,
trace
,
warn
};
use
log
::{
debug
,
error
,
info
,
trace
,
warn
};
use
mio
::
net
::
UdpSocket
;
use
mio
::{
Event
,
Poll
,
PollOpt
,
Ready
,
Registration
,
SetReadiness
,
Token
};
use
mio_extras
::
timer
::{
self
,
Timeout
,
Timer
};
use
nalgebra
::
Point2
;
use
serde
::{
Deserialize
,
Serialize
};
use
std
::
collections
::
VecDeque
;
use
std
::
collections
::
{
HashMap
,
VecDeque
}
;
use
std
::
io
::{
self
,
Cursor
};
use
std
::
net
::
SocketAddr
;
use
std
::
thread
::{
self
,
JoinHandle
};
...
...
@@ -48,6 +49,7 @@ pub enum ClientPacket {
/// Cursor position when connecting.
cursor
:
Point2
<
f32
>
,
},
Settings
(
GameSettings
),
Input
(
Input
),
Disconnect
,
Ping
,
...
...
@@ -81,6 +83,7 @@ pub struct Client {
poll
:
Poll
,
timeout
:
Timeout
,
connection
:
Connection
,
reliable
:
HashMap
<
u32
,
ClientPacket
>
,
state
:
ClientState
,
_shutdown
:
Registration
,
/// Marks after `shutdown` has been received, to shutdown when the
...
...
@@ -137,6 +140,33 @@ impl Drop for ClientHandle {
}
}
impl
ClientPacket
{
fn
reliable
(
&
self
)
->
bool
{
match
self
{
ClientPacket
::
Handshake
{
..
}
=>
true
,
ClientPacket
::
Settings
(
_
)
=>
true
,
ClientPacket
::
Input
(
_
)
=>
false
,
ClientPacket
::
Disconnect
=>
false
,
ClientPacket
::
Ping
=>
false
,
ClientPacket
::
Pong
(
_
)
=>
false
,
}
}
fn
resend
(
&
self
,
game
:
Option
<&
GameHandle
>
)
->
bool
{
match
self
{
ClientPacket
::
Handshake
{
..
}
=>
true
,
ClientPacket
::
Settings
(
settings
)
=>
{
&
game
.as_ref
()
.unwrap
()
.settings
.settings
()
==
settings
},
_
=>
self
.reliable
(),
}
}
}
impl
EventHandler
for
Client
{
fn
poll
(
&
self
)
->
&
Poll
{
&
self
.poll
...
...
@@ -270,6 +300,7 @@ impl Client {
poll
,
timeout
,
connection
:
Connection
::
default
(),
reliable
:
HashMap
::
new
(),
state
:
ClientState
::
Connecting
{
done
,
cursor
,
...
...
@@ -452,9 +483,20 @@ impl Client {
let
(
_
,
interval
)
=
tick
.next
(
now
);
self
.timer
.set_timeout
(
interval
,
TimeoutState
::
Tick
);
let
packet
=
ClientPacket
::
Input
(
game
.latest_input
());
trace!
(
"sending tick packet to server: {:?}"
,
packet
);
self
.send
(
&
packet
)
?
;
let
tick_packet
=
ClientPacket
::
Input
(
game
.latest_input
());
trace!
(
"sending tick packet to server: {:?}"
,
tick_packet
);
// If the settings have changed, send that as well.
if
let
Some
(
settings
)
=
game
.settings
.dirty
()
{
let
settings_packet
=
ClientPacket
::
Settings
(
settings
);
trace!
(
"sending settings update packet to server: {:?}"
,
settings_packet
);
self
.send
(
&
settings_packet
)
?
;
}
self
.send
(
&
tick_packet
)
?
;
},
// We shouldn't really be sending ticks in any other state.
_
=>
unreachable!
(),
...
...
@@ -472,15 +514,40 @@ impl Client {
return
Ok
(
Err
(
RecvError
::
PacketTooLarge
(
bytes_read
)));
}
let
packet
=
&
self
.recv_buffer
[
0
..
bytes_read
];
let
(
packet
,
sequence
,
_
,
lost
)
=
let
(
packet
,
sequence
,
acks
,
lost
)
=
match
self
.connection
.decode
(
Cursor
::
new
(
packet
))
{
Ok
(
result
)
=>
result
,
Err
(
err
)
=>
return
Ok
(
Err
(
err
)),
};
if
let
Some
(
ref
mut
stats
)
=
self
.stats
{
stats
.next.packets_lost
+=
lost
.len
()
as
u16
;
}
// Remove acked packets from the reliable packet buffer.
for
ack
in
acks
.iter
()
{
self
.reliable
.remove
(
&
ack
);
}
// Possibly resend any lost packets.
for
lost
in
lost
.into_iter
()
{
if
let
Some
(
packet
)
=
self
.reliable
.remove
(
&
lost
)
{
let
game
=
match
self
.state
{
ClientState
::
Connecting
{
..
}
=>
None
,
ClientState
::
Connected
{
ref
game
,
..
}
=>
Some
(
game
),
};
if
packet
.resend
(
game
)
{
debug!
(
"resending lost packet from client: {:?}"
,
packet
);
self
.send
(
&
packet
)
?
;
}
}
}
let
transition
=
match
self
.state
{
ClientState
::
Connecting
{
ref
mut
done
,
...
...
@@ -489,11 +556,12 @@ impl Client {
match
packet
{
ServerPacket
::
Handshake
{
players
,
settings
,
snapshot
,
id
,
}
=>
{
let
(
game
,
game_handle
)
=
Game
::
new
(
players
,
snapshot
,
id
,
*
cursor
);
Game
::
new
(
players
,
snapshot
,
settings
,
id
,
*
cursor
);
let
tick
=
Interval
::
new
(
TICK_RATE
);
let
ping
=
Interval
::
new
(
PING_RATE
);
// Start the timer for sending input ticks and pings.
...
...
@@ -566,6 +634,10 @@ impl Client {
self
.send_queue
.push_back
(
packet
);
self
.reregister_socket
(
true
)
?
;
if
contents
.reliable
()
{
self
.reliable
.insert
(
sequence
,
contents
.clone
());
}
Ok
(
sequence
)
}
}
src/networking/server.rs
View file @
ce1457fd
...
...
@@ -2,6 +2,7 @@ use crate::game::{
clamp_cursor
,
server
::
Game
,
Event
,
GameSettings
,
GetPlayer
,
PlayerId
,
RoundStateKind
,
...
...
@@ -57,6 +58,7 @@ pub enum ServerPacket {
Pong
(
u32
),
Handshake
{
id
:
PlayerId
,
settings
:
GameSettings
,
players
:
HashMap
<
PlayerId
,
StaticPlayerState
>
,
snapshot
:
Snapshot
,
},
...
...
@@ -135,6 +137,7 @@ impl ServerPacket {
}
=>
true
,
Event
::
RemovePlayer
(
_
)
=>
true
,
Event
::
RoundState
(
_
)
=>
true
,
Event
::
Settings
(
_
)
=>
true
,
Event
::
Snapshot
(
_
)
=>
false
,
}
},
...
...
@@ -153,6 +156,11 @@ impl ServerPacket {
// changed again since it was sent.
RoundStateKind
::
from
(
round
)
==
RoundStateKind
::
from
(
game
.round
)
},