Added the ability to toggle light sources on and off

This commit is contained in:
Joshua Barretto 2024-01-21 16:20:20 +00:00
parent 5137966940
commit e0ebe6939e
13 changed files with 129 additions and 33 deletions

View File

@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Potion of Agility - Potion of Agility
- A way for servers to specify must-accept rules for players - A way for servers to specify must-accept rules for players
- A flag argument type for commands - A flag argument type for commands
- The ability to turn lamp-like sprites on and off
### Changed ### Changed

View File

@ -20,7 +20,7 @@ use common::{
comp::{ comp::{
self, self,
chat::KillSource, chat::KillSource,
controller::CraftEvent, controller::{BlockInteraction, CraftEvent},
dialogue::Subject, dialogue::Subject,
group, group,
inventory::item::{modular, tool, ItemKind}, inventory::item::{modular, tool, ItemKind},
@ -1419,6 +1419,13 @@ impl Client {
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::DisableLantern)); 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) { pub fn remove_buff(&mut self, buff_id: BuffKind) {
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::RemoveBuff( self.send_msg(ClientGeneral::ControlEvent(ControlEvent::RemoveBuff(
buff_id, buff_id,

View File

@ -134,6 +134,11 @@ pub enum UtteranceKind {
* sounds */ * sounds */
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum BlockInteraction {
ToggleLight(bool),
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ControlEvent { pub enum ControlEvent {
//ToggleLantern, //ToggleLantern,
@ -159,6 +164,7 @@ pub enum ControlEvent {
new_ability: ability::AuxiliaryAbility, new_ability: ability::AuxiliaryAbility,
}, },
ActivatePortal(Uid), ActivatePortal(Uid),
BlockInteraction(VolumePos, BlockInteraction),
} }
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]

View File

@ -4,6 +4,7 @@ use crate::{
comp::{ comp::{
self, self,
agent::Sound, agent::Sound,
controller::BlockInteraction,
dialogue::Subject, dialogue::Subject,
invite::{InviteKind, InviteResponse}, invite::{InviteKind, InviteResponse},
misc::PortalData, misc::PortalData,
@ -338,6 +339,11 @@ pub enum ServerEvent {
entity: EcsEntity, entity: EcsEntity,
portal: EcsEntity, portal: EcsEntity,
}, },
BlockInteraction {
entity: EcsEntity,
pos: VolumePos,
interaction: BlockInteraction,
},
} }
pub struct EventBus<E> { pub struct EventBus<E> {

View File

@ -1,6 +1,6 @@
use super::{sprite, SpriteKind}; use super::{sprite, SpriteKind};
use crate::{ use crate::{
comp::{fluid_dynamics::LiquidKind, tool::ToolKind}, comp::{controller::BlockInteraction, fluid_dynamics::LiquidKind, tool::ToolKind},
consts::FRIC_GROUND, consts::FRIC_GROUND,
lottery::LootSpec, lottery::LootSpec,
make_case_elim, rtsim, make_case_elim, rtsim,
@ -377,13 +377,13 @@ impl Block {
#[inline] #[inline]
pub fn get_glow(&self) -> Option<u8> { pub fn get_glow(&self) -> Option<u8> {
match self.kind() { let glow_level = match self.kind() {
BlockKind::Lava => Some(24), BlockKind::Lava => 24,
BlockKind::GlowingRock | BlockKind::GlowingWeakRock => Some(10), BlockKind::GlowingRock | BlockKind::GlowingWeakRock => 10,
BlockKind::GlowingMushroom => Some(20), BlockKind::GlowingMushroom => 20,
_ => match self.get_sprite()? { _ => match self.get_sprite()? {
SpriteKind::StreetLamp | SpriteKind::StreetLampTall => Some(24), SpriteKind::StreetLamp | SpriteKind::StreetLampTall => 24,
SpriteKind::Ember | SpriteKind::FireBlock => Some(20), SpriteKind::Ember | SpriteKind::FireBlock => 20,
SpriteKind::WallLamp SpriteKind::WallLamp
| SpriteKind::WallLampSmall | SpriteKind::WallLampSmall
| SpriteKind::WallSconce | SpriteKind::WallSconce
@ -391,8 +391,8 @@ impl Block {
| SpriteKind::ChristmasOrnament | SpriteKind::ChristmasOrnament
| SpriteKind::CliffDecorBlock | SpriteKind::CliffDecorBlock
| SpriteKind::Orb | SpriteKind::Orb
| SpriteKind::Candle => Some(16), | SpriteKind::Candle => 16,
SpriteKind::DiamondLight => Some(30), SpriteKind::DiamondLight => 30,
SpriteKind::Velorite SpriteKind::Velorite
| SpriteKind::VeloriteFrag | SpriteKind::VeloriteFrag
| SpriteKind::CavernGrassBlueShort | SpriteKind::CavernGrassBlueShort
@ -400,12 +400,12 @@ impl Block {
| SpriteKind::CavernGrassBlueLong | SpriteKind::CavernGrassBlueLong
| SpriteKind::CavernLillypadBlue | SpriteKind::CavernLillypadBlue
| SpriteKind::CavernMycelBlue | SpriteKind::CavernMycelBlue
| SpriteKind::CeilingMushroom => Some(6), | SpriteKind::CeilingMushroom => 6,
SpriteKind::CaveMushroom SpriteKind::CaveMushroom
| SpriteKind::CookingPot | SpriteKind::CookingPot
| SpriteKind::CrystalHigh | SpriteKind::CrystalHigh
| SpriteKind::CrystalLow => Some(10), | SpriteKind::CrystalLow => 10,
SpriteKind::SewerMushroom => Some(16), SpriteKind::SewerMushroom => 16,
SpriteKind::Amethyst SpriteKind::Amethyst
| SpriteKind::Ruby | SpriteKind::Ruby
| SpriteKind::Sapphire | SpriteKind::Sapphire
@ -417,14 +417,23 @@ impl Block {
| SpriteKind::DiamondSmall | SpriteKind::DiamondSmall
| SpriteKind::RubySmall | SpriteKind::RubySmall
| SpriteKind::EmeraldSmall | SpriteKind::EmeraldSmall
| SpriteKind::SapphireSmall => Some(3), | SpriteKind::SapphireSmall => 3,
SpriteKind::Lantern => Some(24), SpriteKind::Lantern => 24,
SpriteKind::SeashellLantern | SpriteKind::GlowIceCrystal => Some(16), SpriteKind::SeashellLantern | SpriteKind::GlowIceCrystal => 16,
SpriteKind::SeaDecorEmblem => Some(12), SpriteKind::SeaDecorEmblem => 12,
SpriteKind::SeaDecorBlock | SpriteKind::HaniwaKeyDoor => Some(10), SpriteKind::SeaDecorBlock | SpriteKind::HaniwaKeyDoor => 10,
SpriteKind::Mine => Some(2), SpriteKind::Mine => 2,
_ => None, _ => return None,
}, },
};
if self
.get_attr::<sprite::LightDisabled>()
.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<Self> {
match interaction {
BlockInteraction::ToggleLight(enable) => {
self.with_attr(sprite::LightDisabled(!enable)).ok()
},
}
}
#[inline] #[inline]
pub fn kind(&self) -> BlockKind { self.kind } pub fn kind(&self) -> BlockKind { self.kind }

View File

@ -120,18 +120,12 @@ sprites! {
DungeonChest4 = 0x35, DungeonChest4 = 0x35,
DungeonChest5 = 0x36, DungeonChest5 = 0x36,
CoralChest = 0x37, CoralChest = 0x37,
HaniwaUrn = 0x38, HaniwaUrn = 0x38,
CommonLockedChest = 0x39, CommonLockedChest = 0x39,
ChestBuried = 0x3A, ChestBuried = 0x3A,
Crate = 0x3B, Crate = 0x3B,
Barrel = 0x3C, Barrel = 0x3C,
CrateBlock = 0x3D, CrateBlock = 0x3D,
// Standalone lights
Lantern = 0x40,
StreetLamp = 0x41,
StreetLampTall = 0x42,
SeashellLantern = 0x43,
FireBowlGround = 0x44,
// Wall // Wall
HangingBasket = 0x50, HangingBasket = 0x50,
HangingSign = 0x51, HangingSign = 0x51,
@ -355,14 +349,23 @@ sprites! {
SeaDecorPillar = 0x1E, SeaDecorPillar = 0x1E,
MagicalSeal = 0x1F, MagicalSeal = 0x1F,
}, },
Lamp = 7 has Ori, LightDisabled {
// Standalone lights
Lantern = 0,
StreetLamp = 1,
StreetLampTall = 2,
SeashellLantern = 3,
FireBowlGround = 4,
},
} }
attributes! { attributes! {
Ori { bits: 4, err: Infallible, from: |bits| Ok(Self(bits as u8)), into: |Ori(x)| x as u16 }, 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 }, 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)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Ori(pub u8); pub struct Ori(pub u8);
@ -370,6 +373,10 @@ pub struct Ori(pub u8);
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Growth(pub u8); 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 { impl SpriteKind {
#[inline] #[inline]
pub fn solid_height(&self) -> Option<f32> { pub fn solid_height(&self) -> Option<f32> {

View File

@ -140,6 +140,13 @@ impl<'a> System<'a> for Sys {
server_emitter.emit(ServerEvent::StartTeleporting { entity, portal }); server_emitter.emit(ServerEvent::StartTeleporting { entity, portal });
} }
}, },
ControlEvent::BlockInteraction(pos, interaction) => {
server_emitter.emit(ServerEvent::BlockInteraction {
entity,
pos,
interaction,
});
},
} }
} }
} }

View File

@ -6,6 +6,7 @@ use common::{
comp::{ comp::{
self, self,
agent::{AgentEvent, Sound, SoundKind}, agent::{AgentEvent, Sound, SoundKind},
controller::BlockInteraction,
dialogue::Subject, dialogue::Subject,
inventory::slot::EquipSlot, inventory::slot::EquipSlot,
item::{flatten_counted_items, MaterialStatManifest}, item::{flatten_counted_items, MaterialStatManifest},
@ -20,7 +21,7 @@ use common::{
}, },
event::EventBus, event::EventBus,
link::Is, link::Is,
mounting::{Mount, Mounting, Rider, VolumeMounting, VolumePos, VolumeRider}, mounting::{Mount, Mounting, Rider, Volume, VolumeMounting, VolumePos, VolumeRider},
outcome::Outcome, outcome::Outcome,
rtsim::RtSimEntity, rtsim::RtSimEntity,
terrain::{Block, SpriteKind}, terrain::{Block, SpriteKind},
@ -469,3 +470,26 @@ pub fn handle_tame_pet(server: &mut Server, pet_entity: EcsEntity, owner_entity:
// showing taming success? // showing taming success?
tame_pet(server.state.ecs(), pet_entity, owner_entity); 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
}
}

View File

@ -25,8 +25,8 @@ use entity_manipulation::{
use group_manip::handle_group; use group_manip::handle_group;
use information::handle_site_info; use information::handle_site_info;
use interaction::{ use interaction::{
handle_create_sprite, handle_lantern, handle_mine_block, handle_mount, handle_npc_interaction, handle_block_interaction, handle_create_sprite, handle_lantern, handle_mine_block,
handle_set_pet_stay, handle_sound, handle_unmount, handle_mount, handle_npc_interaction, handle_set_pet_stay, handle_sound, handle_unmount,
}; };
use inventory_manip::handle_inventory; use inventory_manip::handle_inventory;
use invite::{handle_invite, handle_invite_response}; use invite::{handle_invite, handle_invite_response};
@ -305,6 +305,11 @@ impl Server {
ServerEvent::StartTeleporting { entity, portal } => { ServerEvent::StartTeleporting { entity, portal } => {
handle_start_teleporting(self, entity, portal) handle_start_teleporting(self, entity, portal)
}, },
ServerEvent::BlockInteraction {
entity,
pos,
interaction,
} => handle_block_interaction(self, entity, pos, interaction),
} }
} }

View File

@ -2161,6 +2161,11 @@ impl Hud {
Some(GameInput::Interact), Some(GameInput::Interact),
i18n.get_msg("hud-read").to_string(), 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 // This is only done once per frame, so it's not a performance issue

View File

@ -1,6 +1,6 @@
use crate::hud::CraftingTab; use crate::hud::CraftingTab;
use common::{ use common::{
terrain::{Block, BlockKind, SpriteKind}, terrain::{sprite, Block, BlockKind, SpriteKind},
vol::ReadVol, vol::ReadVol,
}; };
use common_base::span; use common_base::span;
@ -16,6 +16,7 @@ pub enum Interaction {
Craft(CraftingTab), Craft(CraftingTab),
Mount, Mount,
Read, Read,
LightToggle(bool),
} }
pub enum FireplaceType { pub enum FireplaceType {
@ -210,6 +211,11 @@ impl BlocksOfInterest {
Some(SpriteKind::Sign | SpriteKind::HangingSign) => { Some(SpriteKind::Sign | SpriteKind::HangingSign) => {
interactables.push((pos, Interaction::Read)) 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)), _ if block.is_mountable() => interactables.push((pos, Interaction::Mount)),
_ => {}, _ => {},
}, },

View File

@ -36,6 +36,7 @@ pub enum BlockInteraction {
Mine(ToolKind), Mine(ToolKind),
Mount, Mount,
Read(Content), Read(Content),
LightToggle(bool),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -105,6 +106,7 @@ impl Interactable {
}, },
Interaction::Craft(tab) => BlockInteraction::Craft(tab), Interaction::Craft(tab) => BlockInteraction::Craft(tab),
Interaction::Mount => BlockInteraction::Mount, Interaction::Mount => BlockInteraction::Mount,
Interaction::LightToggle(enable) => BlockInteraction::LightToggle(enable),
}; };
Some(Self::Block(block, volume_pos, block_interaction)) Some(Self::Block(block, volume_pos, block_interaction))
} }

View File

@ -1042,6 +1042,9 @@ impl PlayState for SessionState {
// currently supported // currently supported
common::mounting::Volume::Entity(_) => {}, common::mounting::Volume::Entity(_) => {},
}, },
BlockInteraction::LightToggle(enable) => {
client.toggle_sprite_light(*pos, *enable);
},
} }
}, },
Interactable::Entity(entity) => { Interactable::Entity(entity) => {