aboutsummaryrefslogtreecommitdiff
path: root/light-client/src
diff options
context:
space:
mode:
Diffstat (limited to 'light-client/src')
-rw-r--r--light-client/src/game.rs344
-rw-r--r--light-client/src/helper.rs11
-rw-r--r--light-client/src/main.rs105
-rw-r--r--light-client/src/network.rs123
-rw-r--r--light-client/src/render/misc.rs17
-rw-r--r--light-client/src/render/mod.rs158
-rw-r--r--light-client/src/render/sprite.rs76
-rw-r--r--light-client/src/tilemap.rs117
8 files changed, 0 insertions, 951 deletions
diff --git a/light-client/src/game.rs b/light-client/src/game.rs
deleted file mode 100644
index 7d8e466a..00000000
--- a/light-client/src/game.rs
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- Hurry Curry! - a game about cooking
- Copyright 2024 metamuffin
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, version 3 of the License only.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-*/
-use crate::{
- helper::Vec2InterpolateExt,
- render::{
- misc::MiscTextures,
- sprite::{Sprite, SpriteDraw},
- AtlasLayout, SpriteRenderer,
- },
- tilemap::Tilemap,
-};
-use hurrycurry_protocol::{
- glam::{IVec2, Vec2},
- movement::MovementBase,
- ClientGamedata, ItemIndex, ItemLocation, PacketC, PacketS, PlayerID, TileIndex,
-};
-use log::{info, warn};
-use sdl2::{
- keyboard::{KeyboardState, Scancode},
- rect::Rect,
-};
-use std::collections::{HashMap, HashSet, VecDeque};
-
-pub struct Game {
- data: ClientGamedata,
- tiles: HashMap<IVec2, Tile>,
- tilemap: Tilemap,
- collision_map: HashSet<IVec2>,
- players: HashMap<PlayerID, Player>,
- my_id: PlayerID,
-
- camera_center: Vec2,
- misc_textures: MiscTextures,
- item_sprites: Vec<Sprite>,
- movement_send_cooldown: f32,
- interacting: bool,
- score: Score,
-}
-
-#[derive(Debug, Default)]
-pub struct Score {
- points: i64,
- demands_failed: usize,
- demands_completed: usize,
- time_remaining: f32,
-}
-
-pub struct Tile {
- _kind: TileIndex,
- item: Option<Item>,
-}
-
-pub struct Player {
- movement: MovementBase,
- item: Option<Item>,
- _name: String,
- _character: i32,
-}
-
-pub struct Item {
- position: Vec2,
- kind: ItemIndex,
- progress: Option<(f32, bool)>,
-}
-
-impl Game {
- pub fn new(layout: &AtlasLayout) -> Self {
- Self {
- tiles: HashMap::new(),
- players: HashMap::new(),
- tilemap: Tilemap::default(),
- my_id: PlayerID(0),
- data: ClientGamedata::default(),
- collision_map: HashSet::new(),
- movement_send_cooldown: 0.,
- misc_textures: MiscTextures::init(layout),
- item_sprites: Vec::new(),
- interacting: false,
- score: Score::default(),
- camera_center: Vec2::ZERO,
- }
- }
-
- pub fn packet_in(&mut self, packet: PacketC, renderer: &mut SpriteRenderer) {
- match packet {
- PacketC::Init { id } => self.my_id = id,
- PacketC::Data { data } => {
- self.tilemap.init(&data.tile_names, renderer.atlas_layout());
- self.item_sprites = data
- .item_names
- .iter()
- .map(|name| {
- Sprite::new(
- renderer
- .atlas_layout()
- .get(&format!("{name}+a"))
- .copied()
- .unwrap_or_else(|| {
- warn!("no sprite for item {name:?}");
- Rect::new(0, 0, 32, 24)
- }),
- Vec2::new(0., 0.0),
- 0.1,
- )
- })
- .collect();
- self.data = data;
- }
- PacketC::UpdateMap {
- tile,
- kind,
- neighbors,
- } => {
- if let Some(kind) = kind {
- self.tiles.insert(
- tile,
- Tile {
- _kind: kind,
- item: None,
- },
- );
- if self.data.tile_collide[kind.0] {
- self.collision_map.remove(&tile);
- } else {
- self.collision_map.insert(tile);
- }
- } else {
- self.tiles.remove(&tile);
- self.collision_map.remove(&tile);
- }
- self.tilemap.set(tile, kind, neighbors);
- }
- PacketC::AddPlayer {
- id,
- position,
- character,
- name,
- } => {
- info!("add player {} {name:?}", id.0);
- self.players.insert(
- id,
- Player {
- _character: character,
- _name: name,
- item: None,
- movement: MovementBase {
- position,
- facing: Vec2::X,
- rotation: 0.,
- velocity: Vec2::ZERO,
- boosting: false,
- stamina: 0.,
- },
- },
- );
- }
- PacketC::RemovePlayer { id } => {
- info!("remove player {}", id.0);
- self.players.remove(&id);
- }
- PacketC::Position {
- player,
- pos,
- rot,
- boosting,
- } => {
- if player != self.my_id {
- if let Some(p) = self.players.get_mut(&player) {
- p.movement.position = pos;
- p.movement.rotation = rot;
- p.movement.boosting = boosting;
- }
- }
- }
- PacketC::MoveItem { from, to } => *self.get_item(to) = self.get_item(from).take(),
- PacketC::SetItem { location, item } => {
- *self.get_item(location) = item.map(|kind| Item {
- kind,
- position: Vec2::ZERO,
- progress: None,
- })
- }
- PacketC::SetProgress {
- item,
- progress,
- warn,
- } => {
- self.get_item(item).as_mut().unwrap().progress = progress.map(|s| (s, warn));
- }
- PacketC::Collide {
- player: _,
- force: _,
- } => (),
- PacketC::Communicate { .. } => {
- // TODO
- }
- PacketC::ServerMessage { text: _ } => {
- // TODO
- }
- PacketC::Score {
- points,
- demands_failed,
- demands_completed,
- time_remaining,
- } => {
- self.score.points = points;
- self.score.demands_completed = demands_completed;
- self.score.demands_failed = demands_failed;
- self.score.time_remaining = time_remaining.unwrap_or(-1.);
- }
- PacketC::SetIngame { state: _, lobby: _ } => {
- // TODO
- }
- PacketC::Error { message } => {
- warn!("server error: {message:?}")
- }
- _ => (),
- }
- }
-
- pub fn get_item(&mut self, location: ItemLocation) -> &mut Option<Item> {
- match location {
- ItemLocation::Tile(pos) => &mut self.tiles.get_mut(&pos).unwrap().item,
- ItemLocation::Player(pid) => &mut self.players.get_mut(&pid).unwrap().item,
- }
- }
-
- pub fn tick(&mut self, dt: f32, keyboard: &KeyboardState, packet_out: &mut VecDeque<PacketS>) {
- let mut direction = IVec2::new(
- keyboard.is_scancode_pressed(Scancode::D) as i32
- - keyboard.is_scancode_pressed(Scancode::A) as i32,
- keyboard.is_scancode_pressed(Scancode::S) as i32
- - keyboard.is_scancode_pressed(Scancode::W) as i32,
- )
- .as_vec2();
- let boost = keyboard.is_scancode_pressed(Scancode::K);
- let interact = keyboard.is_scancode_pressed(Scancode::Space)
- | keyboard.is_scancode_pressed(Scancode::J);
-
- if interact {
- direction *= 0.;
- }
-
- self.movement_send_cooldown -= dt;
- let send_movement = self.movement_send_cooldown < 0.;
- if send_movement {
- self.movement_send_cooldown += 0.04
- }
-
- self.score.time_remaining -= dt;
- self.score.time_remaining -= self.score.time_remaining.max(0.);
-
- if interact != self.interacting {
- if interact {
- packet_out.push_back(PacketS::Interact {
- pos: Some(self.players[&self.my_id].movement.get_interact_target()),
- });
- } else {
- packet_out.push_back(PacketS::Interact { pos: None });
- }
- self.interacting = interact;
- }
-
- if let Some(player) = self.players.get_mut(&self.my_id) {
- let movement_packet = player
- .movement
- .update(&self.collision_map, direction, boost, dt);
- if send_movement {
- packet_out.push_back(movement_packet);
- }
-
- self.camera_center.exp_to(player.movement.position, dt * 5.);
- }
-
- for (_pid, player) in &mut self.players {
- if let Some(item) = &mut player.item {
- item.position = player.movement.position
- }
- }
- for (pos, tile) in &mut self.tiles {
- if let Some(item) = &mut tile.item {
- item.position = pos.as_vec2() + 0.5
- }
- }
- }
-
- pub fn draw(&self, ctx: &mut SpriteRenderer) {
- ctx.set_view(-self.camera_center + (ctx.size / ctx.get_scale() / 2.), 1.);
-
- self.tilemap.draw(ctx);
-
- for p in self.players.values() {
- ctx.draw_world(self.misc_textures.player.at(p.movement.position));
- if let Some(item) = &p.item {
- item.draw(ctx, &self.item_sprites, &self.misc_textures)
- }
- }
- for tile in self.tiles.values() {
- if let Some(item) = &tile.item {
- item.draw(ctx, &self.item_sprites, &self.misc_textures)
- }
- }
- }
-}
-
-impl Item {
- pub fn draw(&self, ctx: &mut SpriteRenderer, item_sprites: &[Sprite], misc: &MiscTextures) {
- ctx.draw_world(item_sprites[self.kind.0].at(self.position));
- if let Some((progress, warn)) = self.progress {
- let (bg, fg) = if warn {
- ([100, 0, 0, 200], [255, 0, 0, 200])
- } else {
- ([0, 100, 0, 200], [0, 255, 0, 200])
- };
- ctx.draw_world(SpriteDraw::overlay(
- misc.solid,
- self.position + Vec2::new(-0.5, -1.3),
- Vec2::new(1., 0.2),
- Some(bg),
- ));
- ctx.draw_world(SpriteDraw::overlay(
- misc.solid,
- self.position + Vec2::new(-0.5, -1.3),
- Vec2::new(progress, 0.2),
- Some(fg),
- ))
- }
- }
-}
diff --git a/light-client/src/helper.rs b/light-client/src/helper.rs
deleted file mode 100644
index 9654f519..00000000
--- a/light-client/src/helper.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use hurrycurry_protocol::glam::Vec2;
-
-pub trait Vec2InterpolateExt {
- fn exp_to(&mut self, target: Vec2, dt: f32);
-}
-impl Vec2InterpolateExt for Vec2 {
- fn exp_to(&mut self, target: Vec2, dt: f32) {
- self.x = target.x + (self.x - target.x) * (-dt).exp();
- self.y = target.y + (self.y - target.y) * (-dt).exp();
- }
-}
diff --git a/light-client/src/main.rs b/light-client/src/main.rs
deleted file mode 100644
index e3aaa5cc..00000000
--- a/light-client/src/main.rs
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- Hurry Curry! - a game about cooking
- Copyright 2024 metamuffin
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, version 3 of the License only.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-*/
-use game::Game;
-use hurrycurry_protocol::glam::Vec2;
-use network::Network;
-use render::SpriteRenderer;
-use sdl2::{
- event::Event,
- keyboard::{KeyboardState, Keycode},
- pixels::Color,
-};
-use std::time::{Duration, Instant};
-
-pub mod game;
-pub mod helper;
-pub mod network;
-pub mod render;
-pub mod tilemap;
-
-fn main() {
- env_logger::init_from_env("LOG");
-
- let sdl_context = sdl2::init().unwrap();
-
- let video_subsystem = sdl_context.video().unwrap();
- let window = video_subsystem
- .window("Hurry Curry! Light Client", 1280, 720)
- .position_centered()
- .resizable()
- .build()
- .map_err(|e| e.to_string())
- .unwrap();
-
- let mut canvas = window
- .into_canvas()
- .accelerated()
- .build()
- .map_err(|e| e.to_string())
- .unwrap();
- let texture_creator = canvas.texture_creator();
-
- let mut net = Network::connect("ws://127.0.0.1/").unwrap();
- let mut renderer = SpriteRenderer::init(&texture_creator);
- let mut game = Game::new(&renderer.atlas_layout());
-
- net.queue_out.push_back(hurrycurry_protocol::PacketS::Join {
- name: "light".to_string(),
- character: 0,
- });
-
- let mut events = sdl_context.event_pump().unwrap();
-
- let mut last_tick = Instant::now();
-
- canvas.set_logical_size(320, 240).unwrap();
-
- 'mainloop: loop {
- net.poll();
-
- let (width, height) = canvas.logical_size();
- renderer.size = Vec2::new(width as f32, height as f32);
-
- for packet in net.queue_in.drain(..) {
- game.packet_in(packet, &mut renderer);
- }
-
- let keyboard = KeyboardState::new(&events);
- let dt = last_tick.elapsed().min(Duration::from_secs_f32(1. / 30.));
- game.tick(dt.as_secs_f32(), &keyboard, &mut net.queue_out);
- last_tick += dt;
-
- game.draw(&mut renderer);
-
- canvas.set_draw_color(Color::BLACK);
- canvas.clear();
- renderer.submit(&mut canvas);
- canvas.present();
-
- for event in events.poll_iter() {
- match event {
- Event::Quit { .. }
- | Event::KeyDown {
- keycode: Option::Some(Keycode::Escape),
- ..
- } => break 'mainloop,
- _ => {}
- }
- }
- }
-}
diff --git a/light-client/src/network.rs b/light-client/src/network.rs
deleted file mode 100644
index ed160773..00000000
--- a/light-client/src/network.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- Hurry Curry! - a game about cooking
- Copyright 2024 metamuffin
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, version 3 of the License only.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-*/
-use anyhow::Result;
-use hurrycurry_protocol::{PacketC, PacketS, BINCODE_CONFIG};
-use log::{debug, warn};
-use std::{collections::VecDeque, net::TcpStream};
-use tungstenite::{
- client::{uri_mode, IntoClientRequest},
- client_tls_with_config,
- handshake::client::Request,
- stream::{MaybeTlsStream, Mode},
- util::NonBlockingError,
- Message, WebSocket,
-};
-
-pub struct Network {
- sock: WebSocket<MaybeTlsStream<TcpStream>>,
- pub queue_in: VecDeque<PacketC>,
- pub queue_out: VecDeque<PacketS>,
-}
-
-impl Network {
- pub fn connect(addr: &str) -> Result<Self> {
- let (parts, _) = addr.into_client_request().unwrap().into_parts();
- let mut builder = Request::builder()
- .uri(parts.uri.clone().clone())
- .method(parts.method.clone())
- .version(parts.version);
- *builder.headers_mut().unwrap() = parts.headers.clone();
- let request = builder.body(()).unwrap();
-
- let host = request.uri().host().unwrap();
- let host = if host.starts_with('[') {
- &host[1..host.len() - 1]
- } else {
- host
- };
- let port = request
- .uri()
- .port_u16()
- .unwrap_or(match uri_mode(request.uri())? {
- Mode::Plain => 27032,
- Mode::Tls => 443,
- });
- let stream = TcpStream::connect((host, port))?;
- stream.set_nodelay(true).unwrap();
-
- let (mut sock, _) = client_tls_with_config(request, stream, None, None).unwrap();
-
- match sock.get_mut() {
- MaybeTlsStream::Plain(s) => s.set_nonblocking(true).unwrap(),
- MaybeTlsStream::Rustls(s) => s.sock.set_nonblocking(true).unwrap(),
- _ => todo!(),
- };
-
- Ok(Self {
- sock,
- queue_in: VecDeque::new(),
- queue_out: VecDeque::new(),
- })
- }
- pub fn poll(&mut self) {
- loop {
- self.queue_in.extend(match self.sock.read() {
- Ok(Message::Text(packet)) => match serde_json::from_str(&packet) {
- Ok(packet) => {
- debug!("<- {packet:?}");
- Some(packet)
- }
- Err(e) => {
- warn!("invalid json packet: {e:?}");
- None
- }
- },
- Ok(Message::Binary(packet)) => {
- match bincode::decode_from_slice(&packet, BINCODE_CONFIG) {
- Ok((packet, _)) => {
- debug!("<- {packet:?}");
- Some(packet)
- }
- Err(e) => {
- warn!("invalid bincode packet: {e:?}");
- None
- }
- }
- }
- Ok(_) => None,
- Err(e) => {
- if let Some(e) = e.into_non_blocking() {
- warn!("{e:?}");
- None
- } else {
- break;
- }
- }
- });
- }
-
- for packet in self.queue_out.drain(..) {
- debug!("-> {packet:?}");
- self.sock
- .write(Message::Text(serde_json::to_string(&packet).unwrap()))
- .unwrap();
- }
-
- self.sock.flush().unwrap();
- }
-}
diff --git a/light-client/src/render/misc.rs b/light-client/src/render/misc.rs
deleted file mode 100644
index 9f866568..00000000
--- a/light-client/src/render/misc.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-use super::{sprite::Sprite, AtlasLayout};
-use hurrycurry_protocol::glam::Vec2;
-use sdl2::rect::Rect;
-
-pub struct MiscTextures {
- pub player: Sprite,
- pub solid: Rect,
-}
-
-impl MiscTextures {
- pub fn init(layout: &AtlasLayout) -> Self {
- MiscTextures {
- player: Sprite::new(*layout.get("player+a").unwrap(), Vec2::Y * 0.3, 0.5 + 0.3),
- solid: *layout.get("solid+a").unwrap(),
- }
- }
-}
diff --git a/light-client/src/render/mod.rs b/light-client/src/render/mod.rs
deleted file mode 100644
index a2aea365..00000000
--- a/light-client/src/render/mod.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- Hurry Curry! - a game about cooking
- Copyright 2024 metamuffin
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, version 3 of the License only.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-*/
-pub mod misc;
-pub mod sprite;
-
-use hurrycurry_protocol::glam::Vec2;
-use sdl2::{
- pixels::PixelFormatEnum,
- rect::{FRect, Rect},
- render::{BlendMode, Canvas, Texture, TextureAccess, TextureCreator},
- video::{Window, WindowContext},
-};
-use sprite::SpriteDraw;
-use std::collections::HashMap;
-
-pub struct SpriteRenderer<'a> {
- metadata: AtlasLayout,
-
- pub size: Vec2,
- texture: Texture<'a>,
-
- view_scale: Vec2,
- view_offset: Vec2,
-
- sprites: Vec<SpriteDraw>,
-}
-
-pub type AtlasLayout = HashMap<String, Rect>;
-
-impl<'a> SpriteRenderer<'a> {
- pub fn init(texture_creator: &'a TextureCreator<WindowContext>) -> Self {
- let palette = include_str!("../../assets/palette.csv")
- .split('\n')
- .filter(|l| !l.is_empty())
- .map(|s| {
- let mut toks = s.split(",");
- (
- toks.next().unwrap().chars().next().unwrap(),
- [
- toks.next().unwrap().parse::<u8>().unwrap(),
- toks.next().unwrap().parse::<u8>().unwrap(),
- toks.next().unwrap().parse::<u8>().unwrap(),
- toks.next().unwrap().parse::<u8>().unwrap(),
- ],
- )
- })
- .collect::<HashMap<_, _>>();
-
- let mut texels = vec![255; 1024 * 1024 * 4];
-
- for (y, line) in include_str!("../../assets/atlas.ta").lines().enumerate() {
- if line.is_empty() {
- continue;
- }
- for (x, char) in line.chars().enumerate() {
- let color = palette.get(&char).unwrap();
- texels[(y * 1024 + x) * 4 + 0] = color[3];
- texels[(y * 1024 + x) * 4 + 1] = color[2];
- texels[(y * 1024 + x) * 4 + 2] = color[1];
- texels[(y * 1024 + x) * 4 + 3] = color[0];
- }
- }
-
- let mut texture = texture_creator
- .create_texture(
- Some(PixelFormatEnum::RGBA8888),
- TextureAccess::Streaming,
- 1024,
- 1024,
- )
- .unwrap();
-
- texture.update(None, &texels, 1024 * 4).unwrap();
- texture.set_blend_mode(BlendMode::Blend);
-
- let metadata = include_str!("../../assets/atlas.meta.csv")
- .lines()
- .filter(|l| !l.is_empty())
- .map(|l| {
- let mut toks = l.split(",");
- let x: i32 = toks.next().unwrap().parse().unwrap();
- let y: i32 = toks.next().unwrap().parse().unwrap();
- let w: u32 = toks.next().unwrap().parse().unwrap();
- let h: u32 = toks.next().unwrap().parse().unwrap();
- let name = toks.next().unwrap().to_string();
- (name, Rect::new(x, y, w, h))
- })
- .collect::<HashMap<_, _>>();
-
- Self {
- texture,
- size: Vec2::ONE,
- metadata,
- sprites: vec![],
- view_offset: Vec2::ZERO,
- view_scale: Vec2::ZERO,
- }
- }
-
- pub fn set_view(&mut self, offset: Vec2, scale: f32) {
- self.view_offset = offset;
- self.view_scale = Vec2::new(32., 24.) * scale;
- }
- pub fn get_scale(&self) -> Vec2 {
- self.view_scale
- }
-
- #[inline]
- pub fn atlas_layout(&self) -> &HashMap<String, Rect> {
- &self.metadata
- }
-
- pub fn set_modulation(&mut self, r: u8, g: u8, b: u8, a: u8) {
- self.texture.set_alpha_mod(a);
- self.texture.set_color_mod(r, g, b);
- }
- pub fn reset_modulation(&mut self) {
- self.set_modulation(255, 255, 255, 255)
- }
-
- pub fn draw_world(&mut self, sprite: SpriteDraw) {
- self.sprites.push(SpriteDraw {
- tint: sprite.tint,
- z_order: sprite.z_order,
- src: sprite.src,
- dst: FRect::new(
- ((sprite.dst.x + self.view_offset.x) * self.view_scale.x).round(),
- ((sprite.dst.y + self.view_offset.y) * self.view_scale.y).round(),
- (sprite.dst.w * self.view_scale.x).round(),
- (sprite.dst.h * self.view_scale.y).round(),
- ),
- })
- }
-
- pub fn submit(&mut self, canvas: &mut Canvas<Window>) {
- self.sprites.sort();
- for SpriteDraw { src, dst, tint, .. } in self.sprites.drain(..) {
- self.texture.set_color_mod(tint[0], tint[1], tint[2]);
- self.texture.set_alpha_mod(tint[3]);
- canvas.copy_f(&self.texture, src, dst).unwrap();
- }
- }
-}
diff --git a/light-client/src/render/sprite.rs b/light-client/src/render/sprite.rs
deleted file mode 100644
index 711f45bf..00000000
--- a/light-client/src/render/sprite.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-use hurrycurry_protocol::glam::Vec2;
-use sdl2::rect::{FRect, Rect};
-
-pub struct Sprite {
- z_offset: f32,
- src: Rect,
- relative_dst: FRect,
-}
-
-impl Sprite {
- pub fn new(src: Rect, anchor: Vec2, elevation: f32) -> Self {
- let relative_dst = FRect::new(
- anchor.x - (src.w as f32) / 32. / 2.,
- anchor.y - (src.h as f32) / 24.,
- (src.w as f32) / 32.,
- (src.h as f32) / 24.,
- );
- Self {
- z_offset: elevation,
- src,
- relative_dst,
- }
- }
- pub fn new_tile(src: Rect) -> Self {
- Self::new(src, Vec2::new(0.5, 1.0), 0.5)
- }
- pub fn at(&self, pos: Vec2) -> SpriteDraw {
- SpriteDraw {
- z_order: ((self.z_offset + pos.y) * 24.) as i32,
- src: self.src,
- dst: FRect::new(
- self.relative_dst.x + pos.x,
- self.relative_dst.y + pos.y,
- self.relative_dst.w,
- self.relative_dst.h,
- ),
- tint: [0xff; 4],
- }
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct SpriteDraw {
- pub tint: [u8; 4],
- pub z_order: i32,
- pub src: Rect,
- pub dst: FRect,
-}
-
-impl SpriteDraw {
- pub fn overlay(src: Rect, pos: Vec2, size: Vec2, tint: Option<[u8; 4]>) -> Self {
- Self {
- dst: FRect::new(pos.x, pos.y, size.x, size.y),
- src,
- tint: tint.unwrap_or([0xff; 4]),
- z_order: i32::MAX,
- }
- }
-}
-
-impl Ord for SpriteDraw {
- fn cmp(&self, other: &Self) -> std::cmp::Ordering {
- self.z_order.cmp(&other.z_order)
- }
-}
-impl PartialOrd for SpriteDraw {
- fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
- Some(self.cmp(&other))
- }
-}
-impl Eq for SpriteDraw {}
-impl PartialEq for SpriteDraw {
- fn eq(&self, other: &Self) -> bool {
- self.z_order == other.z_order && self.src == other.src && self.dst == other.dst
- }
-}
diff --git a/light-client/src/tilemap.rs b/light-client/src/tilemap.rs
deleted file mode 100644
index 768f79ba..00000000
--- a/light-client/src/tilemap.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- Hurry Curry! - a game about cooking
- Copyright 2024 metamuffin
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, version 3 of the License only.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-*/
-use hurrycurry_protocol::{glam::IVec2, TileIndex};
-use log::warn;
-use sdl2::rect::Rect;
-use std::collections::{HashMap, HashSet};
-
-use crate::render::{
- sprite::{Sprite, SpriteDraw},
- SpriteRenderer,
-};
-
-#[derive(Default)]
-pub struct Tilemap {
- connect_group_by_tile: Vec<Option<usize>>,
- connect_members_by_group: Vec<HashSet<Option<TileIndex>>>,
- tile_srcs: Vec<[Rect; 16]>,
- tiles: HashMap<IVec2, SpriteDraw>,
-}
-
-impl Tilemap {
- pub fn init(&mut self, tile_names: &[String], sprite_rects: &HashMap<String, Rect>) {
- let tile_index = tile_names
- .iter()
- .enumerate()
- .map(|(t, i)| (i.to_string(), t))
- .collect::<HashMap<_, _>>();
- self.connect_group_by_tile = vec![None; tile_names.len()];
- self.connect_members_by_group = include_str!("../assets/connect.csv")
- .lines()
- .enumerate()
- .map(|(gid, line)| {
- line.split(",")
- .flat_map(|tile| tile_index.get(tile).copied())
- .map(|ti| {
- self.connect_group_by_tile[ti] = Some(gid);
- Some(TileIndex(ti))
- })
- .collect::<HashSet<_>>()
- })
- .collect::<Vec<_>>();
-
- self.tile_srcs = tile_names
- .iter()
- .map(|name| {
- let fallback = sprite_rects
- .get(&format!("{name}+a"))
- .copied()
- .unwrap_or_else(|| {
- warn!("no sprite for tile {name:?}");
- Rect::new(0, 0, 0, 0)
- });
-
- [
- sprite_rects.get(&format!("{name}+")),
- sprite_rects.get(&format!("{name}+w")),
- sprite_rects.get(&format!("{name}+e")),
- sprite_rects.get(&format!("{name}+we")),
- sprite_rects.get(&format!("{name}+n")),
- sprite_rects.get(&format!("{name}+wn")),
- sprite_rects.get(&format!("{name}+en")),
- sprite_rects.get(&format!("{name}+wen")),
- sprite_rects.get(&format!("{name}+s")),
- sprite_rects.get(&format!("{name}+ws")),
- sprite_rects.get(&format!("{name}+es")),
- sprite_rects.get(&format!("{name}+wes")),
- sprite_rects.get(&format!("{name}+ns")),
- sprite_rects.get(&format!("{name}+wns")),
- sprite_rects.get(&format!("{name}+ens")),
- sprite_rects.get(&format!("{name}+wens")),
- ]
- .map(|e| e.copied().unwrap_or(fallback))
- })
- .collect();
- }
-
- pub fn set(&mut self, pos: IVec2, tile: Option<TileIndex>, neighbors: [Option<TileIndex>; 4]) {
- let Some(tile) = tile else {
- self.tiles.remove(&pos);
- return;
- };
-
- let mut idx = 0;
- if let Some(gid) = self.connect_group_by_tile[tile.0] {
- let cgroup = &self.connect_members_by_group[gid];
- idx |= 0b0100 * (cgroup.contains(&neighbors[0])) as usize;
- idx |= 0b0001 * (cgroup.contains(&neighbors[1])) as usize;
- idx |= 0b1000 * (cgroup.contains(&neighbors[2])) as usize;
- idx |= 0b0010 * (cgroup.contains(&neighbors[3])) as usize;
- }
-
- let src = self.tile_srcs[tile.0][idx];
- self.tiles
- .insert(pos, Sprite::new_tile(src).at(pos.as_vec2()));
- }
-
- pub fn draw(&self, ctx: &mut SpriteRenderer) {
- for &sprite in self.tiles.values() {
- ctx.draw_world(sprite);
- }
- }
-}