use plaza_client_utils::{
input_buffer::ClientInputBuffer,
prediction::PredictedEntity,
types::SequenceNumber,
};
use tracing::Level;
use tracing_subscriber::FmtSubscriber;
#[derive(Debug, Clone, PartialEq)]
struct PlayerState {
x: i32,
tick_at_state: u64,
}
impl PlayerState {
fn new(x: i32, tick: u64) -> Self {
Self { x, tick_at_state: tick }
}
}
#[derive(Debug, Clone, PartialEq)]
enum PlayerOp {
Move(i32), }
fn apply_op_to_state(state: &mut PlayerState, op: &PlayerOp) {
match op {
PlayerOp::Move(dx) => {
state.x += dx;
}
}
state.tick_at_state += 1; }
fn main() {
let subscriber = FmtSubscriber::builder()
.with_max_level(Level::INFO) .finish();
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");
let initial_state = PlayerState::new(0, 0);
let mut predicted_entity = PredictedEntity::<PlayerState, PlayerOp>::new(initial_state.clone());
let mut input_buffer = ClientInputBuffer::<PlayerOp, PlayerState>::new(64); let mut client_input_seq: SequenceNumber = 0;
let mut client_current_tick: u64 = 0;
tracing::info!(state = ?predicted_entity.current_predicted_state, "Client: Initialized.");
let inputs_to_send: Vec<PlayerOp> = vec![
PlayerOp::Move(10), PlayerOp::Move(5), PlayerOp::Move(-3), PlayerOp::Move(8), ];
for (i, op_to_send) in inputs_to_send.iter().enumerate() {
client_current_tick += 1; client_input_seq += 1;
tracing::info!(tick = client_current_tick, seq = client_input_seq, op = ?op_to_send, "Client: Generating input.");
predicted_entity.apply_local_input_and_predict(op_to_send, client_input_seq, &mut input_buffer, &apply_op_to_state);
tracing::info!(state = ?predicted_entity.current_predicted_state, "Client: Predicted state after input {}.", client_input_seq);
if i < inputs_to_send.len() - 2 {
client_current_tick += 1; tracing::info!(tick = client_current_tick, "Client: Tick passed (waiting for server).");
}
}
tracing::info!("--------------------------------------------------");
tracing::info!(
"Client: All inputs sent. Final predicted state: {:?}",
predicted_entity.current_predicted_state
);
tracing::info!("Client: Input buffer content ({} items):", input_buffer.len());
for buffered_input in input_buffer.get_unacknowledged_inputs(0) {
tracing::info!(
" - Seq: {}, Op: {:?}, StateBeforeOp: {:?}",
buffered_input.sequence_number,
buffered_input.op,
buffered_input.state_before_op_predicted
);
}
tracing::info!("--------------------------------------------------");
let server_ack_seq: SequenceNumber = 2;
let authoritative_state_from_server = PlayerState::new(12, 2);
tracing::info!(
ack_seq = server_ack_seq,
auth_state = ?authoritative_state_from_server,
"Server: Processed inputs up to seq {}. Sending authoritative state.", server_ack_seq
);
tracing::info!("--------------------------------------------------");
tracing::info!("Client: Received server update. Reconciling...");
tracing::info!(
"Client: State BEFORE reconciliation: {:?}",
predicted_entity.current_predicted_state
);
predicted_entity.reconcile_with_server_state(
authoritative_state_from_server,
server_ack_seq,
&mut input_buffer,
&apply_op_to_state,
);
tracing::info!("--------------------------------------------------");
tracing::info!(
"Client: State AFTER reconciliation: {:?}",
predicted_entity.current_predicted_state
);
tracing::info!(
"Client: Last authoritative state: {:?}",
predicted_entity.last_authoritative_state
);
tracing::info!(
ack_seq = predicted_entity.last_server_acknowledged_input_seq,
"Client: Last server acknowledged input seq."
);
tracing::info!("Client: Input buffer content after ack ({} items):", input_buffer.len());
for buffered_input in input_buffer.get_unacknowledged_inputs(server_ack_seq) {
tracing::info!(
" - Seq: {}, Op: {:?}, StateBeforeOp: {:?}",
buffered_input.sequence_number,
buffered_input.op,
buffered_input.state_before_op_predicted
);
}
assert_eq!(predicted_entity.current_predicted_state, PlayerState::new(17, 4));
assert_eq!(predicted_entity.last_authoritative_state, PlayerState::new(12, 2));
assert_eq!(predicted_entity.last_server_acknowledged_input_seq, 2);
assert_eq!(input_buffer.len(), 2);
tracing::info!("--------------------------------------------------");
tracing::info!("Basic CSP example finished successfully!");
}