From 740dc4b45cb59ff184e5cebc5b19f402bb9d54d2 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Wed, 4 Sep 2024 20:00:30 +0200 Subject: refactor interact function and new progress proto --- server/client-lib/src/lib.rs | 38 ++++++-- server/protocol/src/lib.rs | 8 +- server/src/entity/conveyor.rs | 10 +- server/src/entity/item_portal.rs | 10 +- server/src/interaction.rs | 203 +++++++++++++++++++++++++++++++-------- server/src/server.rs | 139 +++++++-------------------- 6 files changed, 241 insertions(+), 167 deletions(-) (limited to 'server') diff --git a/server/client-lib/src/lib.rs b/server/client-lib/src/lib.rs index 38f1070e..38b328b9 100644 --- a/server/client-lib/src/lib.rs +++ b/server/client-lib/src/lib.rs @@ -32,9 +32,9 @@ use std::{ #[derive(Debug, PartialEq)] pub struct Involvement { - pub progress: f32, + pub position: f32, + pub speed: f32, pub recipe: RecipeIndex, - pub working: usize, pub warn: bool, } @@ -135,18 +135,21 @@ impl Game { PacketC::SetItem { location, item } => { *self.get_item(location) = item.map(|kind| Item { kind, active: None }); } + PacketC::ClearProgress { item } => { + self.get_item(item).as_mut().unwrap().active = None; + } PacketC::SetProgress { item, - progress, + position, + speed, warn, } => { - self.get_item(item).as_mut().unwrap().active = - progress.map(|progress| Involvement { - working: 1, - warn, - progress, - recipe: RecipeIndex(0), - }); + self.get_item(item).as_mut().unwrap().active = Some(Involvement { + speed, + warn, + position, + recipe: RecipeIndex(0), + }); } PacketC::UpdateMap { tile, @@ -205,6 +208,21 @@ impl Game { .update_entry(pid, player.movement.position); } + for (_, player) in &mut self.players { + if let Some(item) = &mut player.item { + if let Some(active) = &mut item.active { + active.position += active.speed; + } + } + } + for (_, tile) in &mut self.tiles { + if let Some(item) = &mut tile.item { + if let Some(active) = &mut item.active { + active.position += active.speed; + } + } + } + self.players_spatial_index.all(|p1, pos1| { self.players_spatial_index.query(pos1, 2., |p2, _pos2| { if let Some([a, b]) = self.players.get_many_mut([&p1, &p2]) { diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs index a55eabe2..68af0e63 100644 --- a/server/protocol/src/lib.rs +++ b/server/protocol/src/lib.rs @@ -27,7 +27,7 @@ pub use glam; pub mod movement; -pub const VERSION: (u32, u32) = (5, 0); +pub const VERSION: (u32, u32) = (6, 0); pub const BINCODE_CONFIG: Configuration> = standard().with_limit(); @@ -185,9 +185,13 @@ pub enum PacketC { location: ItemLocation, item: Option, }, + ClearProgress { + item: ItemLocation, + }, SetProgress { item: ItemLocation, - progress: Option, + position: f32, + speed: f32, warn: bool, }, UpdateMap { diff --git a/server/src/entity/conveyor.rs b/server/src/entity/conveyor.rs index 5602e082..4efbd385 100644 --- a/server/src/entity/conveyor.rs +++ b/server/src/entity/conveyor.rs @@ -15,8 +15,8 @@ along with this program. If not, see . */ -use super::{EntityContext, Entity}; -use crate::server::interact_effect; +use super::{Entity, EntityContext}; +use crate::interaction::interact; use anyhow::{anyhow, Result}; use hurrycurry_protocol::{glam::IVec2, ItemIndex, ItemLocation}; @@ -68,18 +68,18 @@ impl Entity for Conveyor { .get_many_mut([&self.from, &self.to]) .ok_or(anyhow!("conveyor does ends in itself"))?; - interact_effect( + interact( &c.game.data, true, + Some(to.kind), &mut to.item, ItemLocation::Tile(self.to), &mut from.item, ItemLocation::Tile(self.from), - Some(to.kind), - c.packet_out, &mut c.game.score, c.score_changed, true, + c.packet_out, ); } diff --git a/server/src/entity/item_portal.rs b/server/src/entity/item_portal.rs index faaa210b..99b9d57a 100644 --- a/server/src/entity/item_portal.rs +++ b/server/src/entity/item_portal.rs @@ -15,8 +15,8 @@ along with this program. If not, see . */ -use super::{EntityContext, Entity}; -use crate::server::interact_effect; +use super::{Entity, EntityContext}; +use crate::interaction::interact; use anyhow::{anyhow, Result}; use hurrycurry_protocol::{glam::IVec2, ItemLocation}; @@ -35,18 +35,18 @@ impl Entity for ItemPortal { .ok_or(anyhow!("conveyor does ends in itself"))?; if from.item.is_some() { - interact_effect( + interact( &c.game.data, true, + Some(to.kind), &mut to.item, ItemLocation::Tile(self.to), &mut from.item, ItemLocation::Tile(self.from), - Some(to.kind), - c.packet_out, &mut c.game.score, c.score_changed, true, + c.packet_out, ); } diff --git a/server/src/interaction.rs b/server/src/interaction.rs index c0fa5731..e2e4d08b 100644 --- a/server/src/interaction.rs +++ b/server/src/interaction.rs @@ -16,24 +16,23 @@ */ use hurrycurry_client_lib::{Involvement, Item}; -use hurrycurry_protocol::{Gamedata, Recipe, Score, TileIndex}; +use hurrycurry_protocol::{Gamedata, ItemLocation, PacketC, Recipe, Score, TileIndex}; use log::info; - -pub enum InteractEffect { - Put, - Take, - Produce, -} +use std::collections::VecDeque; pub fn interact( data: &Gamedata, edge: bool, tile: Option, this: &mut Option, + this_loc: ItemLocation, other: &mut Option, + other_loc: ItemLocation, score: &mut Score, + score_changed: &mut bool, automated: bool, -) -> Option { + packet_out: &mut VecDeque, +) { let interactable = automated || tile .map(|tile| data.is_tile_interactable(tile)) @@ -43,16 +42,31 @@ pub fn interact( if let Some(active) = &mut item.active { let recipe = &data.recipe(active.recipe); if recipe.supports_tile(tile) { - if let Recipe::Active { outputs, .. } = recipe { + if let Recipe::Active { + outputs, duration, .. + } = recipe + { if edge { - active.working += 1; + active.speed += 1. / duration; } else { - active.working -= 1; - if active.progress >= 1. { - *other = outputs[0].map(|kind| Item { kind, active: None }); - *this = outputs[1].map(|kind| Item { kind, active: None }); - return Some(InteractEffect::Produce); - } + active.speed -= 1. / duration; + } + if active.position >= 1. { + let this_had_item = this.is_some(); + let other_had_item = other.is_some(); + *other = outputs[0].map(|kind| Item { kind, active: None }); + *this = outputs[1].map(|kind| Item { kind, active: None }); + produce( + this_had_item, + other_had_item, + this, + this_loc, + other, + other_loc, + score_changed, + packet_out, + ); + return; } } } @@ -60,7 +74,7 @@ pub fn interact( } } if !edge { - return None; + return; } if interactable { for (ri, recipe) in data.recipes() { @@ -68,15 +82,17 @@ pub fn interact( continue; } match recipe { - Recipe::Active { input, .. } => { + Recipe::Active { + input, duration, .. + } => { if other.is_none() { if let Some(item) = this { if item.kind == *input && item.active.is_none() { info!("start active recipe {ri:?}"); item.active = Some(Involvement { recipe: ri, - working: 1, - progress: 0., + speed: 1. / duration, + position: 0., warn: false, }); } @@ -87,19 +103,23 @@ pub fn interact( if item.kind == *input { let mut item = other.take().unwrap(); if let Some(active) = &mut item.active { - active.working += 1; + active.speed += 1. / duration; } else { info!("start active recipe {ri:?}"); item.active = Some(Involvement { recipe: ri, - working: 1, - progress: 0., + speed: 1. / duration, + position: 0., warn: false, }); } *this = Some(item); score.active_recipes += 1; - return Some(InteractEffect::Put); + packet_out.push_back(PacketC::MoveItem { + from: other_loc, + to: this_loc, + }); + return; } } } @@ -117,11 +137,24 @@ pub fn interact( if ok || ok_rev { info!("instant recipe {ri:?} reversed={ok_rev}"); let ok_rev = ok_rev as usize; + let this_had_item = this.is_some(); + let other_had_item = other.is_some(); *other = outputs[1 - ok_rev].map(|kind| Item { kind, active: None }); *this = outputs[ok_rev].map(|kind| Item { kind, active: None }); score.points += pd; score.instant_recipes += 1; - return Some(InteractEffect::Produce); + *score_changed = true; + produce( + this_had_item, + other_had_item, + this, + this_loc, + other, + other_loc, + score_changed, + packet_out, + ); + return; } } _ => (), @@ -132,21 +165,32 @@ pub fn interact( if interactable && this.is_none() { if let Some(item) = other.take() { *this = Some(item); - return Some(InteractEffect::Put); + packet_out.push_back(PacketC::MoveItem { + from: other_loc, + to: this_loc, + }); + return; } } if other.is_none() { if let Some(item) = this.take() { *other = Some(item); - return Some(InteractEffect::Take); + packet_out.push_back(PacketC::MoveItem { + from: this_loc, + to: other_loc, + }); + return; } } - - None } pub enum TickEffect { - Progress(bool), + Progress { + speed: f32, + position: f32, + warn: bool, + }, + ClearProgress, Produce, } pub fn tick_slot( @@ -159,35 +203,58 @@ pub fn tick_slot( if let Some(item) = slot { if let Some(a) = &mut item.active { let r = &data.recipe(a.recipe); - if r.supports_tile(tile) { - a.progress += a.working as f32 * dt / r.duration().unwrap(); - } else if let Some(revert_duration) = r.revert_duration() { - a.progress -= dt / revert_duration; + let prev_speed = a.speed; + + if !r.supports_tile(tile) { + if let Some(revert_duration) = r.revert_duration() { + a.speed = -1. / revert_duration + } } - if a.progress >= 1. { + + if a.position >= 1. { if let Recipe::Passive { output, .. } = &data.recipe(a.recipe) { *slot = output.map(|kind| Item { kind, active: None }); score.passive_recipes += 1; return Some(TickEffect::Produce); }; - a.progress = 1.; } - if a.progress < 0. { + if a.position < 0. { item.active = None; + return Some(TickEffect::ClearProgress); + } + + a.position += dt * a.speed; + a.position = a.position.clamp(0., 1.); + + if a.speed != prev_speed { + return Some(TickEffect::Progress { + warn: r.warn(), + position: a.position, + speed: a.speed, + }); } - return Some(TickEffect::Progress(r.warn())); } else { for (ri, recipe) in data.recipes() { if recipe.supports_tile(tile) { - if let Recipe::Passive { input, warn, .. } = recipe { + if let Recipe::Passive { + input, + warn, + duration, + .. + } = recipe + { if *input == item.kind { item.active = Some(Involvement { recipe: ri, - progress: 0., + position: 0., + warn: *warn, + speed: 1. / *duration, + }); + return Some(TickEffect::Progress { + position: 0., + speed: 1. / *duration, warn: *warn, - working: 1, }); - return Some(TickEffect::Progress(recipe.warn())); } } } @@ -196,3 +263,55 @@ pub fn tick_slot( } None } + +fn produce( + this_had_item: bool, + other_had_item: bool, + this: &Option, + this_loc: ItemLocation, + other: &Option, + other_loc: ItemLocation, + score_changed: &mut bool, + packet_out: &mut VecDeque, +) { + info!("produce {this_loc} <~ {other_loc}"); + *score_changed = true; + if this_had_item { + packet_out.push_back(PacketC::SetProgress { + item: this_loc, + position: 1., + speed: 0., + warn: false, + }); + packet_out.push_back(PacketC::SetItem { + location: this_loc, + item: None, + }); + } + if other_had_item { + packet_out.push_back(PacketC::MoveItem { + from: other_loc, + to: this_loc, + }); + packet_out.push_back(PacketC::SetItem { + location: this_loc, + item: None, + }); + } + if let Some(i) = &other { + packet_out.push_back(PacketC::SetItem { + location: this_loc, + item: Some(i.kind), + }); + packet_out.push_back(PacketC::MoveItem { + from: this_loc, + to: other_loc, + }) + } + if let Some(i) = &this { + packet_out.push_back(PacketC::SetItem { + location: this_loc, + item: Some(i.kind), + }); + } +} diff --git a/server/src/server.rs b/server/src/server.rs index 63664354..109d5561 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -18,7 +18,7 @@ use crate::{ data::{DataIndex, Serverdata}, entity::{Entities, EntityContext}, - interaction::{interact, tick_slot, InteractEffect, TickEffect}, + interaction::{interact, tick_slot, TickEffect}, scoreboard::ScoreboardStore, ConnectionID, }; @@ -444,18 +444,18 @@ impl Server { bail!("You shall not interact with customers.") } - interact_effect( + interact( &self.game.data, edge, + None, &mut this.item, ItemLocation::Player(base_pid), &mut other.item, ItemLocation::Player(pid), - None, - &mut self.packet_out, &mut self.game.score, &mut self.score_changed, false, + &mut self.packet_out, ) } else { let player = self @@ -464,18 +464,18 @@ impl Server { .get_mut(&pid) .ok_or(anyhow!("The player does not exist"))?; - interact_effect( + interact( &self.game.data, edge, + Some(tile.kind), &mut tile.item, ItemLocation::Tile(pos), &mut player.item, ItemLocation::Player(pid), - Some(tile.kind), - &mut self.packet_out, &mut self.game.score, &mut self.score_changed, false, + &mut self.packet_out, ) } } @@ -550,22 +550,27 @@ impl Server { &mut self.game.score, ) { match effect { - TickEffect::Progress(warn) => self.packet_out.push_back(PacketC::SetProgress { + TickEffect::Progress { + speed, + position, + warn, + } => self.packet_out.push_back(PacketC::SetProgress { + position, + speed, warn, item: ItemLocation::Tile(pos), - progress: tile - .item - .as_ref() - .unwrap() - .active - .as_ref() - .map(|i| i.progress), }), + TickEffect::ClearProgress => { + self.packet_out.push_back(PacketC::ClearProgress { + item: ItemLocation::Tile(pos), + }) + } TickEffect::Produce => { self.packet_out.push_back(PacketC::SetProgress { warn: false, item: ItemLocation::Tile(pos), - progress: None, + position: 1., + speed: 0., }); self.packet_out.push_back(PacketC::SetItem { location: ItemLocation::Tile(pos), @@ -611,22 +616,27 @@ impl Server { &mut self.game.score, ) { match effect { - TickEffect::Progress(warn) => self.packet_out.push_back(PacketC::SetProgress { + TickEffect::Progress { + position, + speed, warn, + } => self.packet_out.push_back(PacketC::SetProgress { + warn, + position, + speed, item: ItemLocation::Player(pid), - progress: player - .item - .as_ref() - .unwrap() - .active - .as_ref() - .map(|i| i.progress), }), + TickEffect::ClearProgress => { + self.packet_out.push_back(PacketC::ClearProgress { + item: ItemLocation::Player(pid), + }) + } TickEffect::Produce => { self.packet_out.push_back(PacketC::SetProgress { warn: false, item: ItemLocation::Player(pid), - progress: None, + position: 1., + speed: 0., }); self.packet_out.push_back(PacketC::SetItem { location: ItemLocation::Player(pid), @@ -649,7 +659,7 @@ impl Server { if let Some(tile) = self.game.tiles.get(&pos) { if let Some(item) = &tile.item { if let Some(involvement) = &item.active { - if involvement.progress >= 1. { + if involvement.position >= 1. { players_auto_release.push(*pid); } } @@ -727,80 +737,3 @@ impl Server { .sum() } } - -pub fn interact_effect( - data: &Gamedata, - edge: bool, - this: &mut Option, - this_loc: ItemLocation, - other: &mut Option, - other_loc: ItemLocation, - this_tile_kind: Option, - packet_out: &mut VecDeque, - score: &mut Score, - score_changed: &mut bool, - automated: bool, -) { - let this_had_item = this.is_some(); - let other_had_item = other.is_some(); - - if let Some(effect) = interact(data, edge, this_tile_kind, this, other, score, automated) { - match effect { - InteractEffect::Put => { - info!("put {this_loc} <- {other_loc}"); - packet_out.push_back(PacketC::MoveItem { - from: other_loc, - to: this_loc, - }) - } - InteractEffect::Take => { - info!("take {this_loc} -> {other_loc}"); - packet_out.push_back(PacketC::MoveItem { - from: this_loc, - to: other_loc, - }) - } - InteractEffect::Produce => { - info!("produce {this_loc} <~ {other_loc}"); - *score_changed = true; - if this_had_item { - packet_out.push_back(PacketC::SetProgress { - item: this_loc, - progress: None, - warn: false, - }); - packet_out.push_back(PacketC::SetItem { - location: this_loc, - item: None, - }); - } - if other_had_item { - packet_out.push_back(PacketC::MoveItem { - from: other_loc, - to: this_loc, - }); - packet_out.push_back(PacketC::SetItem { - location: this_loc, - item: None, - }); - } - if let Some(i) = &other { - packet_out.push_back(PacketC::SetItem { - location: this_loc, - item: Some(i.kind), - }); - packet_out.push_back(PacketC::MoveItem { - from: this_loc, - to: other_loc, - }) - } - if let Some(i) = &this { - packet_out.push_back(PacketC::SetItem { - location: this_loc, - item: Some(i.kind), - }); - } - } - } - } -} -- cgit v1.2.3-70-g09d2