aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/src/customer/mod.rs2
-rw-r--r--server/src/game.rs130
-rw-r--r--server/src/interaction.rs35
-rw-r--r--server/src/protocol.rs29
-rw-r--r--test-client/main.ts75
-rw-r--r--test-client/protocol.ts12
6 files changed, 155 insertions, 128 deletions
diff --git a/server/src/customer/mod.rs b/server/src/customer/mod.rs
index 9e0dd797..c29b4852 100644
--- a/server/src/customer/mod.rs
+++ b/server/src/customer/mod.rs
@@ -118,7 +118,7 @@ impl DemandState {
id,
PacketS::Join {
name: faker::name::fr_fr::Name().fake(),
- character: -1 - (random::<i16>() as i32),
+ character: -1 - (random::<u16>() as i32),
},
));
let chair = self.select_chair().ok_or(anyhow!("no free chair found"))?;
diff --git a/server/src/game.rs b/server/src/game.rs
index 54266351..711b66b5 100644
--- a/server/src/game.rs
+++ b/server/src/game.rs
@@ -18,8 +18,10 @@
use crate::{
customer::DemandState,
data::Gamedata,
- interaction::{interact, tick_tile, InteractEffect, TickEffect},
- protocol::{ItemIndex, Message, PacketC, PacketS, PlayerID, RecipeIndex, TileIndex},
+ interaction::{interact, tick_slot, InteractEffect, TickEffect},
+ protocol::{
+ ItemIndex, ItemLocation, Message, PacketC, PacketS, PlayerID, RecipeIndex, TileIndex,
+ },
};
use anyhow::{anyhow, bail, Result};
use glam::{IVec2, Vec2};
@@ -65,6 +67,7 @@ pub struct Game {
pub players: HashMap<PlayerID, Player>,
packet_out: VecDeque<PacketC>,
demand: Option<DemandState>,
+ score_changed: bool,
pub points: i64,
end: Option<Instant>,
}
@@ -78,6 +81,7 @@ impl Game {
tiles: Default::default(),
demand: None,
end: None,
+ score_changed: false,
points: 0,
}
}
@@ -166,8 +170,8 @@ impl Game {
name: player.name.clone(),
});
if let Some(item) = &player.item {
- out.push(PacketC::SetPlayerItem {
- player: id,
+ out.push(PacketC::SetItem {
+ location: ItemLocation::Player(id),
item: Some(item.kind),
})
}
@@ -191,8 +195,8 @@ impl Game {
kind: Some(tdata.kind.clone()),
});
if let Some(item) = &tdata.item {
- out.push(PacketC::SetTileItem {
- tile,
+ out.push(PacketC::SetItem {
+ location: ItemLocation::Tile(tile),
item: Some(item.kind),
})
}
@@ -250,8 +254,8 @@ impl Game {
let pos = p.position.floor().as_ivec2();
if let Some(tile) = self.tiles.get_mut(&pos) {
if tile.item.is_none() {
- self.packet_out.push_back(PacketC::SetTileItem {
- tile: pos,
+ self.packet_out.push_back(PacketC::SetItem {
+ location: ItemLocation::Tile(pos),
item: Some(item.kind),
});
tile.item = Some(item);
@@ -325,76 +329,59 @@ impl Game {
if let Some(effect) = interact(
&self.data,
edge,
- tile.kind,
+ Some(tile.kind),
&mut tile.item,
&mut player.item,
&mut self.points,
) {
match effect {
- InteractEffect::Put => self.packet_out.push_back(PacketC::PutItem {
- player: pid,
- tile: pos,
+ InteractEffect::Put => self.packet_out.push_back(PacketC::MoveItem {
+ from: ItemLocation::Player(pid),
+ to: ItemLocation::Tile(pos),
}),
- InteractEffect::Take => self.packet_out.push_back(PacketC::TakeItem {
- player: pid,
- tile: pos,
+ InteractEffect::Take => self.packet_out.push_back(PacketC::MoveItem {
+ from: ItemLocation::Tile(pos),
+ to: ItemLocation::Player(pid),
}),
InteractEffect::Produce => {
if tile_had_item {
- self.packet_out.push_back(PacketC::SetActive {
- tile: pos,
+ self.packet_out.push_back(PacketC::SetProgress {
+ item: ItemLocation::Tile(pos),
progress: None,
warn: false,
});
- self.packet_out.push_back(PacketC::SetTileItem {
- tile: pos,
+ self.packet_out.push_back(PacketC::SetItem {
+ location: ItemLocation::Tile(pos),
item: None,
});
}
if player_had_item {
- self.packet_out.push_back(PacketC::PutItem {
- player: pid,
- tile: pos,
+ self.packet_out.push_back(PacketC::MoveItem {
+ from: ItemLocation::Player(pid),
+ to: ItemLocation::Tile(pos),
});
- self.packet_out.push_back(PacketC::SetTileItem {
- tile: pos,
+ self.packet_out.push_back(PacketC::SetItem {
+ location: ItemLocation::Tile(pos),
item: None,
});
}
if let Some(i) = &player.item {
- self.packet_out.push_back(PacketC::SetTileItem {
- tile: pos,
+ self.packet_out.push_back(PacketC::SetItem {
+ location: ItemLocation::Tile(pos),
item: Some(i.kind),
});
- self.packet_out.push_back(PacketC::TakeItem {
- player: pid,
- tile: pos,
+ self.packet_out.push_back(PacketC::MoveItem {
+ from: ItemLocation::Tile(pos),
+ to: ItemLocation::Player(pid),
})
}
if let Some(i) = &tile.item {
- self.packet_out.push_back(PacketC::SetTileItem {
- tile: pos,
+ self.packet_out.push_back(PacketC::SetItem {
+ location: ItemLocation::Tile(pos),
item: Some(i.kind),
});
}
- self.packet_out.push_back({
- PacketC::Score {
- time_remaining: self
- .end
- .map(|t| (t - Instant::now()).as_secs_f32()),
- points: self.points,
- demands_failed: self
- .demand
- .as_ref()
- .map(|d| d.failed)
- .unwrap_or_default(),
- demands_completed: self
- .demand
- .as_ref()
- .map(|d| d.completed)
- .unwrap_or_default(),
- }
- })
+ self.score_changed = true
}
}
}
@@ -423,10 +410,17 @@ impl Game {
kind: i,
active: None,
});
- self.packet_out
- .push_back(PacketC::SetPlayerItem { player, item })
+ self.packet_out.push_back(PacketC::SetItem {
+ location: ItemLocation::Player(player),
+ item,
+ })
}
}
+
+ if self.score_changed {
+ self.score_changed = false;
+ self.packet_out.push_back(self.score())
+ }
Ok(())
}
@@ -455,11 +449,11 @@ impl Game {
}
for (&pos, tile) in &mut self.tiles {
- if let Some(effect) = tick_tile(dt, &self.data, tile) {
+ if let Some(effect) = tick_slot(dt, &self.data, Some(tile.kind), &mut tile.item) {
match effect {
- TickEffect::Progress(warn) => self.packet_out.push_back(PacketC::SetActive {
+ TickEffect::Progress(warn) => self.packet_out.push_back(PacketC::SetProgress {
warn,
- tile: pos,
+ item: ItemLocation::Tile(pos),
progress: tile
.item
.as_ref()
@@ -469,8 +463,8 @@ impl Game {
.map(|i| i.progress),
}),
TickEffect::Produce => {
- self.packet_out.push_back(PacketC::SetTileItem {
- tile: pos,
+ self.packet_out.push_back(PacketC::SetItem {
+ location: ItemLocation::Tile(pos),
item: tile.item.as_ref().map(|i| i.kind),
});
}
@@ -478,6 +472,30 @@ impl Game {
}
}
+ for (&pid, player) in &mut self.players {
+ if let Some(effect) = tick_slot(dt, &self.data, None, &mut player.item) {
+ match effect {
+ TickEffect::Progress(warn) => self.packet_out.push_back(PacketC::SetProgress {
+ warn,
+ item: ItemLocation::Player(pid),
+ progress: player
+ .item
+ .as_ref()
+ .unwrap()
+ .active
+ .as_ref()
+ .map(|i| i.progress),
+ }),
+ TickEffect::Produce => {
+ self.packet_out.push_back(PacketC::SetItem {
+ location: ItemLocation::Player(pid),
+ item: player.item.as_ref().map(|i| i.kind),
+ });
+ }
+ }
+ }
+ }
+
return self.end.map(|t| t < Instant::now()).unwrap_or_default();
}
}
diff --git a/server/src/interaction.rs b/server/src/interaction.rs
index 69fc9e70..85df9925 100644
--- a/server/src/interaction.rs
+++ b/server/src/interaction.rs
@@ -17,7 +17,7 @@
*/
use crate::{
data::Gamedata,
- game::{Involvement, Item, Tile},
+ game::{Involvement, Item},
protocol::{ItemIndex, TileIndex},
};
use log::info;
@@ -96,12 +96,12 @@ impl Recipe {
}
}
}
- pub fn supports_tile(&self, tile: TileIndex) -> bool {
+ pub fn supports_tile(&self, tile: Option<TileIndex>) -> bool {
if let Some(tile_constraint) = self.tile() {
- if tile != tile_constraint {
- false
+ if let Some(tile) = tile {
+ tile == tile_constraint
} else {
- true
+ false
}
} else {
true
@@ -118,17 +118,19 @@ pub enum InteractEffect {
pub fn interact(
data: &Gamedata,
edge: bool,
- tile_kind: TileIndex,
+ tile: Option<TileIndex>,
this: &mut Option<Item>,
other: &mut Option<Item>,
points: &mut i64,
) -> Option<InteractEffect> {
- let interactable = data.is_tile_interactable(tile_kind);
+ let interactable = tile
+ .map(|tile| data.is_tile_interactable(tile))
+ .unwrap_or(true);
if interactable && other.is_none() {
if let Some(item) = this {
if let Some(active) = &mut item.active {
let recipe = &data.recipe(active.recipe);
- if recipe.supports_tile(tile_kind) {
+ if recipe.supports_tile(tile) {
if let Recipe::Active { outputs, .. } = recipe {
if edge {
active.working += 1;
@@ -150,7 +152,7 @@ pub fn interact(
}
if interactable {
for (ri, recipe) in data.recipes() {
- if !recipe.supports_tile(tile_kind) {
+ if !recipe.supports_tile(tile) {
continue;
}
match recipe {
@@ -233,18 +235,23 @@ pub enum TickEffect {
Progress(bool),
Produce,
}
-pub fn tick_tile(dt: f32, data: &Gamedata, tile: &mut Tile) -> Option<TickEffect> {
- if let Some(item) = &mut tile.item {
+pub fn tick_slot(
+ dt: f32,
+ data: &Gamedata,
+ tile: Option<TileIndex>,
+ slot: &mut Option<Item>,
+) -> Option<TickEffect> {
+ if let Some(item) = slot {
if let Some(a) = &mut item.active {
let r = &data.recipe(a.recipe);
- if r.supports_tile(tile.kind) {
+ 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;
}
if a.progress >= 1. {
if let Recipe::Passive { output, .. } = &data.recipe(a.recipe) {
- tile.item = output.map(|kind| Item { kind, active: None });
+ *slot = output.map(|kind| Item { kind, active: None });
return Some(TickEffect::Produce);
};
a.progress = 1.;
@@ -255,7 +262,7 @@ pub fn tick_tile(dt: f32, data: &Gamedata, tile: &mut Tile) -> Option<TickEffect
return Some(TickEffect::Progress(r.warn()));
} else {
for (ri, recipe) in data.recipes() {
- if recipe.supports_tile(tile.kind) {
+ if recipe.supports_tile(tile) {
if let Recipe::Passive { input, .. } = recipe {
if *input == item.kind {
item.active = Some(Involvement {
diff --git a/server/src/protocol.rs b/server/src/protocol.rs
index 176eb31b..54992feb 100644
--- a/server/src/protocol.rs
+++ b/server/src/protocol.rs
@@ -99,24 +99,16 @@ pub enum PacketC {
pos: Vec2,
rot: f32,
},
- TakeItem {
- tile: IVec2,
- player: PlayerID,
- },
- PutItem {
- player: PlayerID,
- tile: IVec2,
- },
- SetTileItem {
- tile: IVec2,
- item: Option<ItemIndex>,
+ MoveItem {
+ from: ItemLocation,
+ to: ItemLocation,
},
- SetPlayerItem {
- player: PlayerID,
+ SetItem {
+ location: ItemLocation,
item: Option<ItemIndex>,
},
- SetActive {
- tile: IVec2,
+ SetProgress {
+ item: ItemLocation,
progress: Option<f32>,
warn: bool,
},
@@ -150,3 +142,10 @@ pub enum PacketC {
message: String,
},
}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "snake_case")]
+pub enum ItemLocation {
+ Tile(IVec2),
+ Player(PlayerID),
+}
diff --git a/test-client/main.ts b/test-client/main.ts
index aeca8084..70c07212 100644
--- a/test-client/main.ts
+++ b/test-client/main.ts
@@ -18,8 +18,8 @@
/// <reference lib="dom" />
import { MovementBase, update_movement } from "./movement.ts";
-import { Gamedata, ItemIndex, Message, PacketC, PacketS, PlayerID, TileIndex } from "./protocol.ts";
-import { V2, add_v2, lerp_exp_v2_mut, normalize, lerp_exp } from "./util.ts";
+import { Gamedata, ItemIndex, ItemLocation, Message, PacketC, PacketS, PlayerID, TileIndex } from "./protocol.ts";
+import { V2, lerp_exp_v2_mut, normalize, lerp_exp } from "./util.ts";
import { draw_ingame, draw_wait } from "./visual.ts";
const KEY_INTERACT = "KeyJ"
@@ -82,8 +82,8 @@ export interface PlayerData extends MovementBase {
}
export interface TileData {
- x: number
- y: number
+ x: number, y: number // tile position
+ position: V2, // center position
kind: TileIndex
item?: ItemData
}
@@ -113,9 +113,15 @@ export let interact_possible_anim: number = 0
export let interact_active_anim: number = 0
let interacting: V2 | undefined;
+function get_item_location(loc: ItemLocation): PlayerData | TileData {
+ if ("tile" in loc) return tiles.get(loc.tile.toString())!
+ if ("player" in loc) return players.get(loc.player)!
+ throw new Error("invalid item location");
+}
+
function send(p: PacketS) { ws.send(JSON.stringify(p)) }
function packet(p: PacketC) {
- if (!["position", "set_active", "update_map"].includes(p.type))
+ if (!["position", "set_progress", "update_map"].includes(p.type))
console.log(p);
switch (p.type) {
case "init":
@@ -153,45 +159,40 @@ function packet(p: PacketC) {
pl.rot = p.rot
break;
}
- case "take_item": {
- const player = players.get(p.player)!
- const tile = tiles.get(p.tile.toString())!
- player.item = tile.item;
- player.item!.tracking = player.position
- tile.item = undefined
- break;
- }
- case "put_item": {
- const player = players.get(p.player)!
- const tile = tiles.get(p.tile.toString())!
- tile.item = player.item
- tile.item!.tracking = add_v2(tile, 0.5)
- player.item = undefined
- break;
- }
- case "set_tile_item": {
- const tile = tiles.get(p.tile.toString())!
- if (tile.item !== undefined && tile.item !== null) items_removed.add(tile.item)
- tile.item = undefined
- if (p.item !== undefined && p.item !== null) tile.item = { kind: p.item, x: p.tile[0] + 0.5, y: p.tile[1] + 0.5 }
+ case "move_item": {
+ const from = get_item_location(p.from)
+ const to = get_item_location(p.to)
+
+ to.item = from.item
+ to.item!.tracking = to.position
+ from.item = undefined
+
break;
}
- case "set_player_item": {
- const player = players.get(p.player)!
- if (player.item !== undefined && player.item !== null) items_removed.add(player.item)
- player.item = undefined
- if (p.item !== undefined && p.item !== null) player.item = { kind: p.item, x: player.position.x + 0.5, y: player.position.y + 0.5 }
+ case "set_item": {
+ const slot = get_item_location(p.location)
+ if (slot.item !== undefined && slot.item !== null) items_removed.add(slot.item)
+ slot.item = undefined
+ if (p.item !== undefined && p.item !== null) slot.item = { kind: p.item, x: slot.position.x, y: slot.position.y, tracking: slot.position }
break;
}
- case "set_active": {
- const item = tiles.get(p.tile.toString())!.item!;
- item.progress = p.progress
- item.progress_warn = p.warn
+ case "set_progress": {
+ const slot = get_item_location(p.item)
+ if (!slot.item) return
+ slot.item.progress = p.progress
+ slot.item.progress_warn = p.warn
break;
}
case "update_map":
- if (p.kind !== undefined && p.kind !== null) tiles.set(p.tile.toString(), { x: p.tile[0], y: p.tile[1], kind: p.kind })
- else tiles.delete(p.tile.toString())
+ if (p.kind !== undefined && p.kind !== null)
+ tiles.set(p.tile.toString(), {
+ x: p.tile[0],
+ y: p.tile[1],
+ position: { x: p.tile[0] + 0.5, y: p.tile[1] + 0.5 },
+ kind: p.kind
+ })
+ else
+ tiles.delete(p.tile.toString())
break;
case "communicate": {
const player = players.get(p.player)!
diff --git a/test-client/protocol.ts b/test-client/protocol.ts
index 1e76700a..fd0f8d43 100644
--- a/test-client/protocol.ts
+++ b/test-client/protocol.ts
@@ -41,11 +41,9 @@ export type PacketC =
| { type: "add_player", id: PlayerID, name: string, position: Vec2, character: number } // Somebody else joined (or was already in the game)
| { type: "remove_player", id: PlayerID } // Somebody left
| { type: "position", player: PlayerID, pos: Vec2, rot: number } // Update the position of a players (your own position is included here)
- | { type: "take_item", tile: Vec2, player: PlayerID } // An item was taken from a tile
- | { type: "put_item", tile: Vec2, player: PlayerID } // An item was put on a tile
- | { type: "set_tile_item", tile: Vec2, item?: ItemIndex } // A tile changed its item
- | { type: "set_player_item", player: PlayerID, item?: ItemIndex } // A player changed their item
- | { type: "set_active", tile: Vec2, progress?: number, warn: boolean } // A tile is doing something. progress goes from 0 to 1, then null when finished
+ | { type: "move_item", from: ItemLocation, to: ItemLocation } // Item moved
+ | { type: "set_item", location: ItemLocation, item?: ItemIndex } // the item contained in a tile or player changed
+ | { type: "set_progress", item: ItemLocation, progress?: number, warn: boolean } // A tile is doing something. progress goes from 0 to 1, then null when finished
| { type: "update_map", tile: Vec2, kind: TileIndex | null, neighbors: [TileIndex | null] } // A map tile was changed
| { type: "communicate", player: PlayerID, message?: Message, persist: boolean } // A player wants to communicate something, message is null when cleared
| { type: "server_message", text: string } // Text message from the server
@@ -57,3 +55,7 @@ export type Message =
{ item: number }
| { text: string }
| { effect: string }
+
+export type ItemLocation =
+ { player: PlayerID }
+ | { tile: Vec2 }