Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "jumpy"
version = "0.4.3"
version = "0.5.0-dev"
description = "A tactical 2D shooter"
authors = ["The Fish Fight Game & Spicy Lobster Developers"]
license = "MIT OR Apache-2.0"
Expand Down
38 changes: 19 additions & 19 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ use crate::{
random::RandomPlugin,
session::SessionPlugin,
ui::UiPlugin,
utils::{is_in_game_run_criteria, UtilsPlugin},
utils::{run_criteria_game_not_paused, UtilsPlugin},
workarounds::WorkaroundsPlugin,
};

Expand All @@ -94,17 +94,21 @@ pub enum GameState {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum InGameState {
Playing,
Editing,
Paused,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum GameEditorState {
Hidden,
Visible,
}

#[derive(StageLabel)]
pub enum RollbackStage {
Input,
First,
PreUpdate,
PreUpdateInGame,
Update,
UpdateInGame,
PostUpdate,
Last,
}
Expand Down Expand Up @@ -154,44 +158,40 @@ pub fn main() {

// Set initial game state
app.add_loopless_state(GameState::LoadingPlatformStorage)
.add_loopless_state(InGameState::Playing);
.add_loopless_state(InGameState::Playing)
.add_loopless_state(GameEditorState::Hidden);

// Create the GGRS rollback schedule and plugin
let mut rollback_schedule = Schedule::default();
let rollback_plugin = GGRSPlugin::<GgrsConfig>::new();

// Add fixed update stagesrefs/branchless/2fd80952e26d905aa258ebb7e6175a7cfc4cb76f
rollback_schedule
.add_stage(RollbackStage::First, SystemStage::parallel())
.add_stage(RollbackStage::Input, SystemStage::parallel())
.add_stage_after(
RollbackStage::Input,
RollbackStage::First,
RollbackStage::PreUpdate,
SystemStage::parallel(),
SystemStage::parallel().with_run_criteria(run_criteria_game_not_paused),
)
.add_stage_after(
RollbackStage::First,
RollbackStage::PreUpdate,
RollbackStage::Update,
SystemStage::parallel(),
SystemStage::parallel().with_run_criteria(run_criteria_game_not_paused),
)
.add_stage_after(
RollbackStage::PreUpdate,
RollbackStage::PreUpdateInGame,
SystemStage::parallel().with_run_criteria(is_in_game_run_criteria),
)
.add_stage_after(
RollbackStage::Update,
RollbackStage::PostUpdate,
SystemStage::parallel(),
SystemStage::parallel().with_run_criteria(run_criteria_game_not_paused),
)
.add_stage_after(
RollbackStage::Update,
RollbackStage::UpdateInGame,
SystemStage::parallel().with_run_criteria(is_in_game_run_criteria),
RollbackStage::PostUpdate,
SystemStage::parallel().with_run_criteria(run_criteria_game_not_paused),
)
.add_stage_after(
RollbackStage::PostUpdate,
RollbackStage::Last,
SystemStage::parallel(),
SystemStage::parallel().with_run_criteria(run_criteria_game_not_paused),
);

// Add the rollback schedule and plugin as resources, temporarily.
Expand Down
6 changes: 3 additions & 3 deletions src/map/elements/grenade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ impl Plugin for GrenadePlugin {
fn build(&self, app: &mut App) {
app.extend_rollback_schedule(|schedule| {
schedule
.add_system_to_stage(RollbackStage::PreUpdateInGame, pre_update_in_game)
.add_system_to_stage(RollbackStage::PreUpdate, pre_update_in_game)
.add_system_to_stage(
RollbackStage::UpdateInGame,
RollbackStage::Update,
update_lit_grenades.before(update_idle_grenades),
)
.add_system_to_stage(RollbackStage::UpdateInGame, update_idle_grenades);
.add_system_to_stage(RollbackStage::Update, update_idle_grenades);
})
.extend_rollback_plugin(|plugin| {
plugin
Expand Down
2 changes: 1 addition & 1 deletion src/map/elements/player_spawner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ impl Plugin for PlayerSpawnerPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<CurrentPlayerSpawner>()
.extend_rollback_schedule(|schedule| {
schedule.add_system_to_stage(RollbackStage::PreUpdateInGame, pre_update_in_game);
schedule.add_system_to_stage(RollbackStage::PreUpdate, pre_update_in_game);
})
.extend_rollback_plugin(|plugin| {
plugin
Expand Down
4 changes: 2 additions & 2 deletions src/map/elements/sproinger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ impl Plugin for SproingerPlugin {
fn build(&self, app: &mut App) {
app.extend_rollback_schedule(|schedule| {
schedule
.add_system_to_stage(RollbackStage::PreUpdateInGame, pre_update_in_game)
.add_system_to_stage(RollbackStage::UpdateInGame, update_in_game);
.add_system_to_stage(RollbackStage::PreUpdate, pre_update_in_game)
.add_system_to_stage(RollbackStage::Update, update_in_game);
})
.extend_rollback_plugin(|plugin| plugin.register_rollback_type::<Sproinger>());
}
Expand Down
4 changes: 2 additions & 2 deletions src/map/elements/sword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ impl Plugin for SwordPlugin {
fn build(&self, app: &mut App) {
app.extend_rollback_schedule(|schedule| {
schedule
.add_system_to_stage(RollbackStage::PreUpdateInGame, pre_update_in_game)
.add_system_to_stage(RollbackStage::UpdateInGame, update_in_game);
.add_system_to_stage(RollbackStage::PreUpdate, pre_update_in_game)
.add_system_to_stage(RollbackStage::Update, update_in_game);
})
.extend_rollback_plugin(|plugin| plugin.register_rollback_type::<SwordState>());
}
Expand Down
46 changes: 43 additions & 3 deletions src/networking.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,51 @@
use crate::prelude::*;
use bevy_ggrs::ggrs::P2PSession;

use crate::{
prelude::*, session::SessionManager, ui::main_menu::MenuPage, utils::ResetManager, GgrsConfig,
};

use self::{
client::NetClient,
proto::{match_setup::MatchSetupMessage, ReliableGameMessageKind},
};

pub mod client;
pub mod proto;
// pub mod server;

pub struct NetworkingPlugin;

impl Plugin for NetworkingPlugin {
fn build(&self, _app: &mut App) {}
fn build(&self, app: &mut App) {
app.add_system(listen_for_map_changes.run_if_resource_exists::<P2PSession<GgrsConfig>>());
}
}

// TODO: Map changes aren't working on network games for now.
fn listen_for_map_changes(
mut commands: Commands,
client: Res<NetClient>,
mut reset_manager: ResetManager,
mut session_manager: SessionManager,
mut menu_page: ResMut<MenuPage>,
mut ridp: ResMut<RollbackIdProvider>,
) {
while let Some(message) = client.recv_reliable() {
match message.kind {
ReliableGameMessageKind::MatchSetup(setup) => match setup {
MatchSetupMessage::SelectMap(map_handle) => {
info!("Other player selected map, starting game");
*menu_page = MenuPage::Home;
reset_manager.reset_world();

commands
.spawn()
.insert(map_handle)
.insert(Rollback::new(ridp.next_id()));
commands.insert_resource(NextState(GameState::InGame));
session_manager.start_session();
}
other => warn!("Unexpected message during match: {other:?}"),
},
}
}
}
12 changes: 6 additions & 6 deletions src/networking/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ pub enum ReliableGameMessageKind {
MatchSetup(match_setup::MatchSetupMessage),
}

impl From<match_setup::MatchSetupMessage> for ReliableGameMessageKind {
fn from(x: match_setup::MatchSetupMessage) -> Self {
Self::MatchSetup(x)
}
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RecvReliableGameMessage {
pub from_player_idx: usize,
Expand All @@ -30,12 +36,6 @@ pub struct RecvUnreliableGameMessage {
pub kind: UnreliableGameMessageKind,
}

impl From<match_setup::MatchSetupMessage> for ReliableGameMessageKind {
fn from(x: match_setup::MatchSetupMessage) -> Self {
Self::MatchSetup(x)
}
}

/// A resource indicating which player this game client represents, and how many players there are
/// in the match.j
#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down
55 changes: 44 additions & 11 deletions src/player/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@ impl Plugin for PlayerInputPlugin {
.add_system_to_stage(CoreStage::Last, clear_input_buffer)
.extend_rollback_plugin(|plugin| plugin.register_rollback_type::<PlayerInputs>())
.extend_rollback_schedule(|schedule| {
schedule.add_system_to_stage(RollbackStage::PreUpdate, update_user_input);
// .add_system_to_stage(FixedUpdateStage::Last, reset_input);
schedule.add_system_to_stage(RollbackStage::Input, update_user_input);
});
}
}

/// This is a resource that gets inserted every time the menu wants to modify the pause state of the
/// game.
///
/// The resource is removed every time it is read, so it will only be present in the world when
/// there is an intent to change the pause state.
pub struct WantsGamePause(pub bool);

/// A buffer holding the player inputs until they are read by the game simulation.
#[derive(Reflect, Default)]
pub struct LocalPlayerInputBuffer {
Expand Down Expand Up @@ -79,10 +85,20 @@ fn clear_input_buffer(mut buffer: ResMut<LocalPlayerInputBuffer>) {
/// The GGRS input system
pub fn input_system(
player_handle: In<PlayerHandle>,
mut commands: Commands,
mut buffer: ResMut<LocalPlayerInputBuffer>,
wants_game_pause: Option<Res<WantsGamePause>>,
) -> DensePlayerControl {
buffer.has_been_read = true;
buffer.players[player_handle.0]
let mut input = buffer.players[player_handle.0];

if let Some(wants_game_pause) = wants_game_pause {
commands.remove_resource::<WantsGamePause>();
input.set_wants_to_set_pause(true);
input.set_pause_value(wants_game_pause.0);
}

input
}

/// The control inputs that a player may make.
Expand All @@ -100,7 +116,7 @@ pub enum PlayerAction {
#[reflect(Default, Resource)]
pub struct PlayerInputs {
/// This will be `true` if _all_ of the inputs for all players for this frame have been
/// confirmed and will not be rolled back.
/// confirmed ( so presumably will not be rolled back ).
pub is_confirmed: bool,
pub players: Vec<PlayerInput>,
}
Expand Down Expand Up @@ -157,21 +173,24 @@ bitfield::bitfield! {
/// This is used when sending player inputs across the network.
#[derive(bytemuck::Pod, bytemuck::Zeroable, Copy, Clone, PartialEq, Eq, Reflect)]
#[repr(transparent)]
pub struct DensePlayerControl(u16);
pub struct DensePlayerControl(u32);
impl Debug;
jump_pressed, set_jump_pressed: 0;
shoot_pressed, set_shoot_pressed: 1;
grab_pressed, set_grab_pressed: 2;
slide_pressed, set_slide_pressed: 3;
from into DenseMoveDirection, move_direction, set_move_direction: 15, 4;
/// This bit will be set if this player wants to try and pause or un-pause the game
wants_to_set_pause, set_wants_to_set_pause: 16;
/// This value is only relevant if `wants_to_set_pause` is true, and it indicates whether the
/// player wants to pause or unpause the game.
pause_value, set_pause_value: 17;
}

impl Default for DensePlayerControl {
fn default() -> Self {
let mut control = Self(0);

control.set_move_direction(default());

control
}
}
Expand All @@ -183,10 +202,10 @@ struct DenseMoveDirection(pub Vec2);

/// This is the specific [`Quantized`] type that we use to represent movement directions in
/// [`DenseMoveDirection`].
type MoveDirQuant = Quantized<IntRange<u16, 0b111111, -1, 1>>;
type MoveDirQuant = Quantized<IntRange<u32, 0b111111, -1, 1>>;

impl From<u16> for DenseMoveDirection {
fn from(bits: u16) -> Self {
impl From<u32> for DenseMoveDirection {
fn from(bits: u32) -> Self {
// maximum movement value representable, we use 6 bits to represent each movement direction.
let max = 0b111111;
// The first six bits represent the x movement
Expand All @@ -208,7 +227,7 @@ impl From<u16> for DenseMoveDirection {
}
}

impl From<DenseMoveDirection> for u16 {
impl From<DenseMoveDirection> for u32 {
fn from(dir: DenseMoveDirection) -> Self {
let x_bits = MoveDirQuant::from_f32(dir.x).raw();
let y_bits = MoveDirQuant::from_f32(dir.y).raw();
Expand All @@ -219,6 +238,7 @@ impl From<DenseMoveDirection> for u16 {

/// Updates the [`PlayerInputs`] resource from input collected from GGRS.
fn update_user_input(
mut commands: Commands,
inputs: Res<Vec<(DensePlayerControl, InputStatus)>>,
mut player_inputs: ResMut<PlayerInputs>,
) {
Expand All @@ -227,6 +247,19 @@ fn update_user_input(
.map(|x| x.1)
.all(|x| x == InputStatus::Confirmed);

let someone_wants_to_pause = inputs
.iter()
.any(|x| x.0.wants_to_set_pause() && x.0.pause_value());
let someone_wants_to_unpause = inputs
.iter()
.any(|x| x.0.wants_to_set_pause() && !x.0.pause_value());

if someone_wants_to_pause {
commands.insert_resource(NextState(InGameState::Paused));
} else if someone_wants_to_unpause {
commands.insert_resource(NextState(InGameState::Playing));
}

for (player_idx, (input, _)) in inputs.iter().enumerate() {
let PlayerInput {
control,
Expand Down
2 changes: 1 addition & 1 deletion src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub use crate::{
audio::{EffectsChannel, MusicChannel},
schedule::RollbackScheduleAppExt,
utils::event::FixedUpdateEventAppExt,
GameState, InGameState, RollbackStage,
GameEditorState, GameState, InGameState, RollbackStage,
};
pub use bevy::prelude::*;
pub use bevy_ggrs::{Rollback, RollbackIdProvider};
Expand Down
Loading