From e0ebe6939e65a8f99a06894a45c51fdc14a9977c Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 21 Jan 2024 16:20:20 +0000 Subject: [PATCH] Added the ability to toggle light sources on and off --- CHANGELOG.md | 1 + client/src/lib.rs | 9 ++++- common/src/comp/controller.rs | 6 +++ common/src/event.rs | 6 +++ common/src/terrain/block.rs | 55 ++++++++++++++++++---------- common/src/terrain/sprite.rs | 23 ++++++++---- common/systems/src/controller.rs | 7 ++++ server/src/events/interaction.rs | 28 +++++++++++++- server/src/events/mod.rs | 9 ++++- voxygen/src/hud/mod.rs | 5 +++ voxygen/src/scene/terrain/watcher.rs | 8 +++- voxygen/src/session/interactable.rs | 2 + voxygen/src/session/mod.rs | 3 ++ 13 files changed, 129 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e8e8612d9..b7e3ed8ddb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Potion of Agility - A way for servers to specify must-accept rules for players - A flag argument type for commands +- The ability to turn lamp-like sprites on and off ### Changed diff --git a/client/src/lib.rs b/client/src/lib.rs index 383a3f537e..b0170f6130 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -20,7 +20,7 @@ use common::{ comp::{ self, chat::KillSource, - controller::CraftEvent, + controller::{BlockInteraction, CraftEvent}, dialogue::Subject, group, inventory::item::{modular, tool, ItemKind}, @@ -1419,6 +1419,13 @@ impl Client { self.send_msg(ClientGeneral::ControlEvent(ControlEvent::DisableLantern)); } + pub fn toggle_sprite_light(&mut self, pos: VolumePos, enable: bool) { + self.send_msg(ClientGeneral::ControlEvent(ControlEvent::BlockInteraction( + pos, + BlockInteraction::ToggleLight(enable), + ))); + } + pub fn remove_buff(&mut self, buff_id: BuffKind) { self.send_msg(ClientGeneral::ControlEvent(ControlEvent::RemoveBuff( buff_id, diff --git a/common/src/comp/controller.rs b/common/src/comp/controller.rs index fe84c1f642..373fd29399 100644 --- a/common/src/comp/controller.rs +++ b/common/src/comp/controller.rs @@ -134,6 +134,11 @@ pub enum UtteranceKind { * sounds */ } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum BlockInteraction { + ToggleLight(bool), +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum ControlEvent { //ToggleLantern, @@ -159,6 +164,7 @@ pub enum ControlEvent { new_ability: ability::AuxiliaryAbility, }, ActivatePortal(Uid), + BlockInteraction(VolumePos, BlockInteraction), } #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] diff --git a/common/src/event.rs b/common/src/event.rs index 3280d41a55..369db4adf9 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -4,6 +4,7 @@ use crate::{ comp::{ self, agent::Sound, + controller::BlockInteraction, dialogue::Subject, invite::{InviteKind, InviteResponse}, misc::PortalData, @@ -338,6 +339,11 @@ pub enum ServerEvent { entity: EcsEntity, portal: EcsEntity, }, + BlockInteraction { + entity: EcsEntity, + pos: VolumePos, + interaction: BlockInteraction, + }, } pub struct EventBus { diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index 154510a4bb..f64de562df 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -1,6 +1,6 @@ use super::{sprite, SpriteKind}; use crate::{ - comp::{fluid_dynamics::LiquidKind, tool::ToolKind}, + comp::{controller::BlockInteraction, fluid_dynamics::LiquidKind, tool::ToolKind}, consts::FRIC_GROUND, lottery::LootSpec, make_case_elim, rtsim, @@ -377,13 +377,13 @@ impl Block { #[inline] pub fn get_glow(&self) -> Option { - match self.kind() { - BlockKind::Lava => Some(24), - BlockKind::GlowingRock | BlockKind::GlowingWeakRock => Some(10), - BlockKind::GlowingMushroom => Some(20), + let glow_level = match self.kind() { + BlockKind::Lava => 24, + BlockKind::GlowingRock | BlockKind::GlowingWeakRock => 10, + BlockKind::GlowingMushroom => 20, _ => match self.get_sprite()? { - SpriteKind::StreetLamp | SpriteKind::StreetLampTall => Some(24), - SpriteKind::Ember | SpriteKind::FireBlock => Some(20), + SpriteKind::StreetLamp | SpriteKind::StreetLampTall => 24, + SpriteKind::Ember | SpriteKind::FireBlock => 20, SpriteKind::WallLamp | SpriteKind::WallLampSmall | SpriteKind::WallSconce @@ -391,8 +391,8 @@ impl Block { | SpriteKind::ChristmasOrnament | SpriteKind::CliffDecorBlock | SpriteKind::Orb - | SpriteKind::Candle => Some(16), - SpriteKind::DiamondLight => Some(30), + | SpriteKind::Candle => 16, + SpriteKind::DiamondLight => 30, SpriteKind::Velorite | SpriteKind::VeloriteFrag | SpriteKind::CavernGrassBlueShort @@ -400,12 +400,12 @@ impl Block { | SpriteKind::CavernGrassBlueLong | SpriteKind::CavernLillypadBlue | SpriteKind::CavernMycelBlue - | SpriteKind::CeilingMushroom => Some(6), + | SpriteKind::CeilingMushroom => 6, SpriteKind::CaveMushroom | SpriteKind::CookingPot | SpriteKind::CrystalHigh - | SpriteKind::CrystalLow => Some(10), - SpriteKind::SewerMushroom => Some(16), + | SpriteKind::CrystalLow => 10, + SpriteKind::SewerMushroom => 16, SpriteKind::Amethyst | SpriteKind::Ruby | SpriteKind::Sapphire @@ -417,14 +417,23 @@ impl Block { | SpriteKind::DiamondSmall | SpriteKind::RubySmall | SpriteKind::EmeraldSmall - | SpriteKind::SapphireSmall => Some(3), - SpriteKind::Lantern => Some(24), - SpriteKind::SeashellLantern | SpriteKind::GlowIceCrystal => Some(16), - SpriteKind::SeaDecorEmblem => Some(12), - SpriteKind::SeaDecorBlock | SpriteKind::HaniwaKeyDoor => Some(10), - SpriteKind::Mine => Some(2), - _ => None, + | SpriteKind::SapphireSmall => 3, + SpriteKind::Lantern => 24, + SpriteKind::SeashellLantern | SpriteKind::GlowIceCrystal => 16, + SpriteKind::SeaDecorEmblem => 12, + SpriteKind::SeaDecorBlock | SpriteKind::HaniwaKeyDoor => 10, + SpriteKind::Mine => 2, + _ => return None, }, + }; + + if self + .get_attr::() + .map_or(false, |l| l.0) + { + None + } else { + Some(glow_level) } } @@ -625,6 +634,14 @@ impl Block { } } + pub fn apply_interaction(&self, interaction: BlockInteraction) -> Option { + match interaction { + BlockInteraction::ToggleLight(enable) => { + self.with_attr(sprite::LightDisabled(!enable)).ok() + }, + } + } + #[inline] pub fn kind(&self) -> BlockKind { self.kind } diff --git a/common/src/terrain/sprite.rs b/common/src/terrain/sprite.rs index 337f82ea97..5b5f265444 100644 --- a/common/src/terrain/sprite.rs +++ b/common/src/terrain/sprite.rs @@ -120,18 +120,12 @@ sprites! { DungeonChest4 = 0x35, DungeonChest5 = 0x36, CoralChest = 0x37, - HaniwaUrn = 0x38, + HaniwaUrn = 0x38, CommonLockedChest = 0x39, ChestBuried = 0x3A, Crate = 0x3B, Barrel = 0x3C, CrateBlock = 0x3D, - // Standalone lights - Lantern = 0x40, - StreetLamp = 0x41, - StreetLampTall = 0x42, - SeashellLantern = 0x43, - FireBowlGround = 0x44, // Wall HangingBasket = 0x50, HangingSign = 0x51, @@ -355,14 +349,23 @@ sprites! { SeaDecorPillar = 0x1E, MagicalSeal = 0x1F, }, + Lamp = 7 has Ori, LightDisabled { + // Standalone lights + Lantern = 0, + StreetLamp = 1, + StreetLampTall = 2, + SeashellLantern = 3, + FireBowlGround = 4, + }, } attributes! { Ori { bits: 4, err: Infallible, from: |bits| Ok(Self(bits as u8)), into: |Ori(x)| x as u16 }, Growth { bits: 4, err: Infallible, from: |bits| Ok(Self(bits as u8)), into: |Growth(x)| x as u16 }, + LightDisabled { bits: 1, err: Infallible, from: |bits| Ok(Self(bits == 1)), into: |LightDisabled(x)| x as u16 }, } -// The orientation of the sprite, 0..8 +// The orientation of the sprite, 0..16 #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Ori(pub u8); @@ -370,6 +373,10 @@ pub struct Ori(pub u8); #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Growth(pub u8); +// Whether a light has been toggled off. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct LightDisabled(pub bool); + impl SpriteKind { #[inline] pub fn solid_height(&self) -> Option { diff --git a/common/systems/src/controller.rs b/common/systems/src/controller.rs index 9b6dec9ab2..33397ba180 100644 --- a/common/systems/src/controller.rs +++ b/common/systems/src/controller.rs @@ -140,6 +140,13 @@ impl<'a> System<'a> for Sys { server_emitter.emit(ServerEvent::StartTeleporting { entity, portal }); } }, + ControlEvent::BlockInteraction(pos, interaction) => { + server_emitter.emit(ServerEvent::BlockInteraction { + entity, + pos, + interaction, + }); + }, } } } diff --git a/server/src/events/interaction.rs b/server/src/events/interaction.rs index d843534409..f5c5ef3bff 100755 --- a/server/src/events/interaction.rs +++ b/server/src/events/interaction.rs @@ -6,6 +6,7 @@ use common::{ comp::{ self, agent::{AgentEvent, Sound, SoundKind}, + controller::BlockInteraction, dialogue::Subject, inventory::slot::EquipSlot, item::{flatten_counted_items, MaterialStatManifest}, @@ -20,7 +21,7 @@ use common::{ }, event::EventBus, link::Is, - mounting::{Mount, Mounting, Rider, VolumeMounting, VolumePos, VolumeRider}, + mounting::{Mount, Mounting, Rider, Volume, VolumeMounting, VolumePos, VolumeRider}, outcome::Outcome, rtsim::RtSimEntity, terrain::{Block, SpriteKind}, @@ -194,7 +195,7 @@ pub fn handle_mount_volume(server: &mut Server, rider: EcsEntity, volume_pos: Vo block, rider, }).is_ok(); - #[cfg(feature = "worldgen")] + #[cfg(feature = "worldgen")] if _link_successful { let uid_allocator = state.ecs().read_resource::(); if let Some(rider_entity) = uid_allocator.uid_entity(rider) @@ -469,3 +470,26 @@ pub fn handle_tame_pet(server: &mut Server, pet_entity: EcsEntity, owner_entity: // showing taming success? tame_pet(server.state.ecs(), pet_entity, owner_entity); } + +pub fn handle_block_interaction( + server: &mut Server, + _entity: EcsEntity, + pos: VolumePos, + interaction: BlockInteraction, +) { + let state = server.state_mut(); + if matches!(&pos.kind, Volume::Terrain) { + if state.can_set_block(pos.pos) { + if let Some(new_block) = state + .terrain() + .get(pos.pos) + .ok() + .and_then(|block| block.apply_interaction(interaction)) + { + state.set_block(pos.pos, new_block); + } + } + } else { + // TODO: Handle toggling lights on entities + } +} diff --git a/server/src/events/mod.rs b/server/src/events/mod.rs index 1aa20f50b1..170410fafe 100644 --- a/server/src/events/mod.rs +++ b/server/src/events/mod.rs @@ -25,8 +25,8 @@ use entity_manipulation::{ use group_manip::handle_group; use information::handle_site_info; use interaction::{ - handle_create_sprite, handle_lantern, handle_mine_block, handle_mount, handle_npc_interaction, - handle_set_pet_stay, handle_sound, handle_unmount, + handle_block_interaction, handle_create_sprite, handle_lantern, handle_mine_block, + handle_mount, handle_npc_interaction, handle_set_pet_stay, handle_sound, handle_unmount, }; use inventory_manip::handle_inventory; use invite::{handle_invite, handle_invite_response}; @@ -305,6 +305,11 @@ impl Server { ServerEvent::StartTeleporting { entity, portal } => { handle_start_teleporting(self, entity, portal) }, + ServerEvent::BlockInteraction { + entity, + pos, + interaction, + } => handle_block_interaction(self, entity, pos, interaction), } } diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 893e3e4700..3ba340f078 100755 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -2161,6 +2161,11 @@ impl Hud { Some(GameInput::Interact), i18n.get_msg("hud-read").to_string(), )], + // TODO: change to turn on/turn off? + BlockInteraction::LightToggle(_) => vec![( + Some(GameInput::Interact), + i18n.get_msg("hud-activate").to_string(), + )], }; // This is only done once per frame, so it's not a performance issue diff --git a/voxygen/src/scene/terrain/watcher.rs b/voxygen/src/scene/terrain/watcher.rs index 0109c06715..5d1a21b415 100644 --- a/voxygen/src/scene/terrain/watcher.rs +++ b/voxygen/src/scene/terrain/watcher.rs @@ -1,6 +1,6 @@ use crate::hud::CraftingTab; use common::{ - terrain::{Block, BlockKind, SpriteKind}, + terrain::{sprite, Block, BlockKind, SpriteKind}, vol::ReadVol, }; use common_base::span; @@ -16,6 +16,7 @@ pub enum Interaction { Craft(CraftingTab), Mount, Read, + LightToggle(bool), } pub enum FireplaceType { @@ -210,6 +211,11 @@ impl BlocksOfInterest { Some(SpriteKind::Sign | SpriteKind::HangingSign) => { interactables.push((pos, Interaction::Read)) }, + Some(sprite) if sprite.category() == sprite::Category::Lamp => { + if let Ok(sprite::LightDisabled(disabled)) = block.get_attr() { + interactables.push((pos, Interaction::LightToggle(disabled))); + } + }, _ if block.is_mountable() => interactables.push((pos, Interaction::Mount)), _ => {}, }, diff --git a/voxygen/src/session/interactable.rs b/voxygen/src/session/interactable.rs index 76e639e982..05061d7c27 100644 --- a/voxygen/src/session/interactable.rs +++ b/voxygen/src/session/interactable.rs @@ -36,6 +36,7 @@ pub enum BlockInteraction { Mine(ToolKind), Mount, Read(Content), + LightToggle(bool), } #[derive(Clone, Debug)] @@ -105,6 +106,7 @@ impl Interactable { }, Interaction::Craft(tab) => BlockInteraction::Craft(tab), Interaction::Mount => BlockInteraction::Mount, + Interaction::LightToggle(enable) => BlockInteraction::LightToggle(enable), }; Some(Self::Block(block, volume_pos, block_interaction)) } diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index ee23990583..1ec6afb16e 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -1042,6 +1042,9 @@ impl PlayState for SessionState { // currently supported common::mounting::Volume::Entity(_) => {}, }, + BlockInteraction::LightToggle(enable) => { + client.toggle_sprite_light(*pos, *enable); + }, } }, Interactable::Entity(entity) => {