From 06481f6a1875944b7391ac26381f42bc2ec3cf57 Mon Sep 17 00:00:00 2001 From: ghostlyzsh Date: Sat, 6 Apr 2024 14:52:44 -0500 Subject: [PATCH] some rotation in ship editor, incomplete --- server/src/component.rs | 5 +- server/src/main.rs | 55 +++++++--- server/src/packet.rs | 5 +- server/src/ws.rs | 2 +- .../src/components/Chatbox.svelte | 4 +- starkingdoms-client/src/config.ts | 5 +- starkingdoms-client/src/pages/Play.svelte | 8 +- .../src/pages/ShipEditor.svelte | 102 ++++++++++++------ starkingdoms-client/src/protocol.ts | 4 +- starkingdoms-common/src/lib.rs | 11 +- 10 files changed, 136 insertions(+), 65 deletions(-) diff --git a/server/src/component.rs b/server/src/component.rs index 2328986fe0f0c17fbb90a3e47710d9f939be4170..3afed02d96a7087164299d13d0f2fc039087e912 100644 --- a/server/src/component.rs +++ b/server/src/component.rs @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::net::SocketAddr; +use std::{collections::HashMap, net::SocketAddr}; use bevy::prelude::*; use serde::{Deserialize, Serialize}; @@ -26,7 +26,7 @@ pub enum PlanetType { Mars, } -#[derive(Component, Clone, Copy, PartialEq, Serialize, Deserialize, Debug)] +#[derive(Component, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Debug)] pub enum PartType { Placeholder, Hearty, @@ -92,6 +92,7 @@ pub struct Player { pub save_eligibility: bool, pub energy_capacity: u32, pub energy: u32, + pub save_amount: HashMap // PartType, amount of each module type } #[derive(Bundle)] diff --git a/server/src/main.rs b/server/src/main.rs index 23cb8c45b049cf64601715d645205696e2e1b938..873ccbd759a3541c5dc2a048408f7dbf2f1ed095 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -19,6 +19,7 @@ #[global_allocator] static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; +use std::collections::HashMap; use std::net::IpAddr; use crate::mathutil::rot2d; @@ -36,8 +37,7 @@ use hmac::{Hmac, Mac}; use jwt::VerifyWithKey; use packet::*; use part::{ - HEARTY_CAPACITY, HEARTY_THRUST_ENERGY, LANDING_THRUSTER_CAPACITY, LANDING_THRUSTER_ENERGY, - LANDING_THRUSTER_FORCE, + HEARTY_THRUST_ENERGY, LANDING_THRUSTER_ENERGY, }; use rand::Rng; use serde::{Deserialize, Serialize}; @@ -363,22 +363,23 @@ fn on_message( let mut transform = Transform::from_xyz(angle.cos() * 30.0, angle.sin() * 30.0, 0.0); transform.rotate_z(angle); - let mut entity_id = commands.spawn(( + let mut player_comp = Player { + addr: *from, + username: username.to_string(), + input: component::Input::default(), + selected: None, + save_eligibility: false, + energy_capacity: part::HEARTY_CAPACITY, + energy: part::HEARTY_CAPACITY, + save_amount: HashMap::new(), + }; + let mut entity_id = commands.spawn( PartBundle { part_type: PartType::Hearty, transform: TransformBundle::from(transform), flags: PartFlags { attached: false }, }, - Player { - addr: *from, - username: username.to_string(), - input: component::Input::default(), - selected: None, - save_eligibility: false, - energy_capacity: part::HEARTY_CAPACITY, - energy: part::HEARTY_CAPACITY, - }, - )); + ); entity_id .insert(Collider::cuboid(0.5, 0.5)) .insert(AdditionalMassProperties::MassProperties(MassProperties { @@ -417,6 +418,7 @@ fn on_message( &mut attached_query, &mut part_query, &mut player_query, + &mut player_comp, ); attach.children = children; } else { @@ -434,6 +436,7 @@ fn on_message( // nothing to do } let mut entity_id = commands.entity(entity); + entity_id.insert(player_comp); entity_id.insert(attach); // tell this player the planets @@ -738,13 +741,24 @@ fn on_message( } } } - Packet::RequestSave {} => { + Packet::RequestSave { old_save } => { for (_, q_player, _, _, attach, _) in &mut player_query { if q_player.addr == *from { // HEY! GHOSTLY! PLEASE FILL THIS STRUCT WITH DATA! // THANKS! + + let unused_modules = if let Some(ref old_save) = old_save { + if let Ok(old_savedata) = unpack_savefile(&app_keys.app_key, old_save.to_string()) { + old_savedata.unused_modules + } else { + Vec::new() + } + } else { + Vec::new() + }; let save = SaveData { children: construct_save_data(attach.clone(), &attached_query), + unused_modules, }; let save_string = pack_savefile(&app_keys.app_key, save); let packet = Packet::SaveData { @@ -808,6 +822,7 @@ fn load_savefile( ), Without, >, + player_comp: &mut Player, ) -> [Option; 4] { let mut ret = [None, None, None, None]; for (i, child) in children.iter().enumerate() { @@ -857,6 +872,12 @@ fn load_savefile( module.id() }; + if let Some(amount) = player_comp.save_amount.get(&part_type) { + player_comp.save_amount.insert(part_type, amount + 1); + } else { + player_comp.save_amount.insert(part_type, 1); + } + let children = if part_type != PartType::LandingThruster { load_savefile( commands, @@ -867,6 +888,7 @@ fn load_savefile( attached_query, part_query, player_query, + player_comp, ) } else { [None, None, None, None] @@ -981,8 +1003,7 @@ fn load_savefile( children: [None, None, Some(suspension_id), None], }); } - let mut player = player_query.get_mut(player_id).unwrap(); - player.1.energy_capacity += capacity!(part_type); + player_comp.energy_capacity += capacity!(part_type); } } ret @@ -1282,6 +1303,8 @@ fn attach_on_module_tree( attach.children[attachment_slot] = Some(module.0); module.5.attached = true; player_query.get_mut(player_id).unwrap().1.energy_capacity += capacity!(*module.1); + let save = player_query.get(player_id).unwrap().1.save_amount.clone(); + println!("{:?}", save); if *module.1 == PartType::LandingThruster { let loose_attach = module.4.unwrap().clone(); let mut transform = part_query diff --git a/server/src/packet.rs b/server/src/packet.rs index 8692bdb6748aa9fd203c2f16e117a63d68f252a9..736fff36043ae9e5aab992126e891cfcdefe4dca 100644 --- a/server/src/packet.rs +++ b/server/src/packet.rs @@ -16,6 +16,7 @@ use std::fmt::{Display, Formatter}; // along with this program. If not, see . use crate::component::{PartType, PlanetType}; use serde::{Deserialize, Serialize}; +use starkingdoms_common::Savefile; use tungstenite::Message; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] @@ -101,7 +102,9 @@ pub enum Packet { released: bool, button: ButtonType, }, - RequestSave {}, + RequestSave { + old_save: Option, + }, _SpecialDisconnect {}, // clientbound SpawnPlayer { diff --git a/server/src/ws.rs b/server/src/ws.rs index 346eb8e5f6d58966de6c86121c622c78946f23be..08ca88a8fc2cd8861ca00415206a7d50b3fb8e1f 100644 --- a/server/src/ws.rs +++ b/server/src/ws.rs @@ -200,7 +200,7 @@ impl StkTungsteniteServerPlugin { if let Some(client) = clients.get_mut(addr) { match client.send(event.clone()) { Ok(_) => (), - Err(e) => error!("failed to forward event: {}", e) + Err(e) => error!("failed to forward event: {}", e), } } clients.remove(addr); diff --git a/starkingdoms-client/src/components/Chatbox.svelte b/starkingdoms-client/src/components/Chatbox.svelte index 84cd1aac5ba517266aa664a8f5bff933b4b9fc35..c380ff946ea399c49eaa07219e449e62954b28fe 100644 --- a/starkingdoms-client/src/components/Chatbox.svelte +++ b/starkingdoms-client/src/components/Chatbox.svelte @@ -63,7 +63,9 @@ } let req_packet: Packet = { t: PacketType.RequestSave, - c: {}, + c: { + old_save: window.localStorage.getItem("save"), + }, }; sendPacket(global.client!, req_packet); } else { diff --git a/starkingdoms-client/src/config.ts b/starkingdoms-client/src/config.ts index 076124ff1b98533978f6646133c3cda987abc32b..f9388ffe285ff6c88eadb8853bca7bee01535448 100644 --- a/starkingdoms-client/src/config.ts +++ b/starkingdoms-client/src/config.ts @@ -35,7 +35,7 @@ async function fetchWithTimeout(resource: RequestInfo | URL, options = {}) { } export async function loadConfig(): Promise { - logger("loading configuration from " + CONFIG_URL); + /*logger("loading configuration from " + CONFIG_URL); try { const response = await fetchWithTimeout(CONFIG_URL, { timeout: 1000, @@ -45,7 +45,8 @@ export async function loadConfig(): Promise { logger(`error loading configuration: ${e}, using fallback`); // @ts-ignore strong types are unhelpful here return CONFIG; - } + }*/ + return CONFIG; } export const DEFAULT_CONFIG = CONFIG; diff --git a/starkingdoms-client/src/pages/Play.svelte b/starkingdoms-client/src/pages/Play.svelte index cc99252d89be29827a8e2cc636ca6a656a92bccc..db048c320f50eeb190f2afe3a68196e60141f1a2 100644 --- a/starkingdoms-client/src/pages/Play.svelte +++ b/starkingdoms-client/src/pages/Play.svelte @@ -48,7 +48,9 @@ } let req_packet: Packet = { t: PacketType.RequestSave, - c: {}, + c: { + old_save: window.localStorage.getItem("save"), + }, }; sendPacket(global.client!, req_packet); global.leaving = true; @@ -84,7 +86,7 @@ let server_id = params.get("srv")!; let username = params.get("username")!; - if (!Object.keys(config.servers).includes(server_id)) { + /*if (!Object.keys(config.servers).includes(server_id)) { chatbox.addMessage( "server-error", "The selected server is currently unavailable. Redirecting to main menu in 5 seconds.", @@ -93,7 +95,7 @@ window.location.href = "/"; }, 5000); return; - } + }*/ let server = config.servers[server_id]; diff --git a/starkingdoms-client/src/pages/ShipEditor.svelte b/starkingdoms-client/src/pages/ShipEditor.svelte index 100480108a5a93433d2e8ff1e2261912ecacf835..8995c7a6293f20e456855d808e27135a63455608 100644 --- a/starkingdoms-client/src/pages/ShipEditor.svelte +++ b/starkingdoms-client/src/pages/ShipEditor.svelte @@ -19,6 +19,7 @@ })(); let selected: PartType | null = null; + let rotation: number | null = null; const logger = createDebug("main"); logger( @@ -89,14 +90,14 @@ let save = unpack_save(window.localStorage.getItem("save")!); console.log(save); - let grid: Map> = new Map(); + let grid: Map> = new Map(); - function placePart(x: number, y: number, part: PartType) { + function placePart(x: number, y: number, part: PartType, rotation: number) { if (!grid.has(x)) { grid.set(x, new Map()); } - grid.get(x)?.set(y, part); + grid.get(x)?.set(y, [part, rotation]); } let textures: Map = new Map(); @@ -132,6 +133,7 @@ grid: Map>, grid_x: number, grid_y: number, + rotation: number | null, ) { if (ctx === null) { return; @@ -140,8 +142,45 @@ // clear out the canvas ctx.clearRect(0, 0, canvas.width, canvas.height); + (async () => { + if (selected !== null) { + if (!textures.has(selected!)) { + let promise = new Promise((resolve, reject) => { + let img = new Image(grid_size, grid_size); + img.onload = () => resolve(img); + img.onerror = reject; + img.src = part_texture_url(selected!, true); + }); + + let img = await promise; + + textures.set(part_type, img); + } + let canvas_x = grid_x * grid_size + x; + let canvas_y = grid_y * grid_size + y; + + let img = textures.get(selected!)!; + ctx.save(); + ctx.translate(canvas_x + grid_size/2, canvas_y + grid_size/2); + ctx.rotate(rotation*Math.PI/2); + ctx.globalAlpha = 0.2; + ctx.drawImage(img, -grid_size/2, -grid_size/2, grid_size, grid_size); + ctx.globalCompositeOperation = "source-atop"; + if (selected === null) { + ctx.fillStyle = "rgb(24, 24, 37)"; + } else if (canPlace()) { + ctx.fillStyle = "rgb(166, 227, 161)"; + } else { + ctx.fillStyle = "rgb(243, 139, 169)"; + } + ctx.globalAlpha = 0.5; + ctx.fillRect(-grid_size/2, -grid_size/2, grid_size, grid_size); + ctx.restore(); + } + })(); + grid.forEach((row, x_coord) => { - row.forEach(async (part_type, y_coord) => { + row.forEach(async ([part_type, rotation], y_coord) => { // draw the image if (!textures.has(part_type)) { let promise = new Promise((resolve, reject) => { @@ -164,29 +203,10 @@ ctx.drawImage(img, canvas_x, canvas_y, grid_size, grid_size); }); }); - - ctx.beginPath(); - - if (selected === null) { - ctx.strokeStyle = "rgb(24, 24, 37)"; - } else if (canPlace()) { - ctx.strokeStyle = "rgb(166, 227, 161)"; - } else { - ctx.strokeStyle = "rgb(243, 139, 169)"; - } - - ctx.lineWidth = 2; - ctx.strokeRect( - grid_x * grid_size + x, - grid_y * grid_size + y, - grid_size, - grid_size, - ); - ctx.stroke(); } $: { - render(context, x, y, scale, grid, grid_x, grid_y); + render(context, x, y, scale, grid, grid_x, grid_y, rotation); } onMount(() => { @@ -208,14 +228,14 @@ let part_counts: Map = new Map(); - function place(x: number, y: number, data: any) { + function place(x: number, y: number, data: any, rotation: number) { if (data === null) { return; } let [type, children] = data; - placePart(x, y, type); + placePart(x, y, type, rotation); let existing_part_count = part_counts.get(type) === undefined @@ -228,22 +248,22 @@ }); if (children[0] !== null) { - place(x, y + 1, children[0]); + place(x, y + 1, children[0], rotation); } if (children[1] !== null) { - place(x + 1, y, children[1]); + place(x + 1, y, children[1], (rotation+1)%4); } if (children[2] !== null) { - place(x, y - 1, children[2]); + place(x, y - 1, children[2], (rotation+2)%4); } if (children[3] !== null) { - place(x - 1, y, children[3]); + place(x - 1, y, children[3], (rotation+3)%4); } } function load_save_data(save: any) { grid = new Map(); - place(0, 0, [PartType.Hearty, save[0]]); + place(0, 0, [PartType.Hearty, save[0]], 0); } $: { @@ -285,9 +305,12 @@ console.log(type); if (selected == type) { selected = null; + rotation = null; } else { selected = type; + rotation = 0; } + canvas.focus(); } function mousedown(e: MouseEvent) { @@ -296,7 +319,7 @@ if (!grid.has(grid_x)) { grid.set(grid_x, new Map()); } - grid.get(grid_x)!.set(grid_y, selected!); + grid.get(grid_x)!.set(grid_y, [selected!, rotation]); part_counts.set(selected!, { used: part_counts.get(selected!)!.used + 1, available: part_counts.get(selected!)!.available, @@ -312,7 +335,7 @@ } else if (e.button == 2) { // removal if (grid.get(grid_x)?.has(grid_y)) { - let type = grid.get(grid_x)!.get(grid_y)!; + let type = grid.get(grid_x)!.get(grid_y)[0]!; if (type === PartType.Hearty) { return; } @@ -325,6 +348,17 @@ grid = grid; } } + canvas.focus() + } + + function keydown(e: KeyboardEvent) { + console.log("here"); + if (e.code == "KeyQ") { + rotation = (rotation - 1) % 4; + } + if (e.code == "KeyE") { + rotation = (rotation + 1) % 4; + } } @@ -407,10 +441,12 @@ on:mouseup|preventDefault={mouseup} on:mousemove|preventDefault={mousemove} on:wheel|preventDefault={handleWheel} + on:keydown={keydown} on:contextmenu|preventDefault={() => { return false; }} style="background-size: {grid_size}px {grid_size}px; background-position: {x}px {y}px;" + tabindex="1" bind:this={canvas} /> diff --git a/starkingdoms-client/src/protocol.ts b/starkingdoms-client/src/protocol.ts index 41834cc424b626d8351a93001dc8311cc769d788..95a376471723c1db5a1e99c0bf195adc610f7ee5 100644 --- a/starkingdoms-client/src/protocol.ts +++ b/starkingdoms-client/src/protocol.ts @@ -88,7 +88,9 @@ export interface MessagePacket { actor: string; content: string; } -export interface RequestSavePacket {} +export interface RequestSavePacket { + old_save: string | null; +} export interface SaveEligibilityPacket { eligible: boolean; } diff --git a/starkingdoms-common/src/lib.rs b/starkingdoms-common/src/lib.rs index 1ee1e6f8a4c1fe3fdf0547628f8c5ca01287aaa1..4f90136b367aa8cc862f406035d39d1ba60af649 100644 --- a/starkingdoms-common/src/lib.rs +++ b/starkingdoms-common/src/lib.rs @@ -18,9 +18,9 @@ use base64::Engine; use hmac::{Hmac, Mac}; use serde::{Deserialize, Serialize}; use sha2::Sha256; -use std::error::Error; +use std::{collections::HashMap, error::Error}; -#[derive(Clone, Serialize, Deserialize, Debug)] +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SaveData { // ---------------------------------------------------------------------- // HEY YOU @@ -30,15 +30,16 @@ pub struct SaveData { // ---------------------------------------------------------------------- // THANKS! -core pub children: Vec>, + pub unused_modules: Vec<(PartType, u32)>, } -#[derive(Clone, Serialize, Deserialize, Debug)] +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct SaveModule { pub part_type: PartType, pub children: Vec>, } -#[derive(Clone, Copy, PartialEq, Serialize, Deserialize, Debug)] +#[derive(Clone, Copy, PartialEq, Hash, Eq, Serialize, Deserialize, Debug)] pub enum PartType { Placeholder, Hearty, @@ -49,7 +50,7 @@ pub enum PartType { } // no touchy. this is the struct that savefiles are actually represented in -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] pub struct Savefile { data_msgpack: Vec, mac: Vec,