diff --git a/feather/base/src/anvil/level.rs b/feather/base/src/anvil/level.rs index b312e5de3..5411093a4 100644 --- a/feather/base/src/anvil/level.rs +++ b/feather/base/src/anvil/level.rs @@ -149,7 +149,7 @@ pub struct SuperflatLayer { } /// The type of world generator for a level. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum LevelGeneratorType { Default, Flat, diff --git a/feather/blocks/generator/src/lib.rs b/feather/blocks/generator/src/lib.rs index b5b8fbd84..bd48b2ff3 100644 --- a/feather/blocks/generator/src/lib.rs +++ b/feather/blocks/generator/src/lib.rs @@ -369,7 +369,8 @@ fn generate_block_fns(blocks: &Blocks) -> TokenStream { } for (name, value) in default_state { - doc.push_str(&format!("* `{}`: {}\n", name, value)); + use core::fmt::Write as _; + let _ = writeln!(doc, "* `{}`: {}", name, value); } fns.push(quote! { diff --git a/feather/blocks/generator/src/load.rs b/feather/blocks/generator/src/load.rs index 10bd98909..390e0bbee 100644 --- a/feather/blocks/generator/src/load.rs +++ b/feather/blocks/generator/src/load.rs @@ -133,7 +133,7 @@ impl PropertyStore { fn update_name(name: &str) -> &str { match NAME_OVERRIDES.get(&name) { - Some(x) => *x, + Some(x) => x, None => name, } } diff --git a/feather/common/src/block_break.rs b/feather/common/src/block_break.rs new file mode 100644 index 000000000..0de68fa5f --- /dev/null +++ b/feather/common/src/block_break.rs @@ -0,0 +1,167 @@ +use anyhow::Context; +use base::{inventory::SLOT_HOTBAR_OFFSET, BlockKind, ItemStack, ValidBlockPosition}; +use ecs::{Entity, SysResult, SystemExecutor}; +use libcraft_items::EnchantmentKind; +use quill_common::components::Instabreak; + +pub struct DestroyStateChange(pub ValidBlockPosition, pub u8); + +use crate::{entities::player::HotbarSlot, Game, Window, World}; + +pub const BREAK_THRESHOLD: f32 = 0.7; + +/// Handle a player's request to start digging the block at `position`. Adds an `ActiveBreaker` component to `player`. +pub fn start_digging( + game: &mut Game, + player: Entity, + position: ValidBlockPosition, +) -> anyhow::Result { + if game.ecs.get::(player)?.0 { + game.break_block(position); + } else { + let breaker = { + let window = game.ecs.get::(player)?; + let hotbar_slot = game.ecs.get::(player)?.get(); + let main_hand = window.item(SLOT_HOTBAR_OFFSET + hotbar_slot)?; + ActiveBreaker::new(&mut game.world, position, main_hand.option_ref()) + .context("Cannot mine this block")? + }; + game.ecs.insert(player, breaker)?; + } + Ok(true) +} +/// Handle a player's request to stop digging the block at `position`. Removes `ActiveBreaker` from `player`. +pub fn cancel_digging( + game: &mut Game, + player: Entity, + position: ValidBlockPosition, +) -> anyhow::Result { + if game.ecs.get::(player).is_err() { + return Ok(false); + } + game.ecs.remove::(player)?; + game.ecs + .insert_entity_event(player, DestroyStateChange(position, 10))?; + Ok(true) +} +/// Handle a player's request to finish digging the block at `position`. +/// This is called when the block breaking finishes at the player's side. +/// +/// Will return `false` if the system hasn't finished breaking the block yet. +pub fn finish_digging( + game: &mut Game, + player: Entity, + position: ValidBlockPosition, +) -> anyhow::Result { + if game.ecs.get::(player)?.0 { + return Ok(true); + } + let success = if let Ok(breaker) = game.ecs.get::(player) { + breaker.can_break() + } else { + false + }; + if success { + let pos = game.ecs.get::(player)?.position; + game.break_block(pos); // TODO: drop an item + game.ecs.remove::(player)?; + } + game.ecs + .insert_entity_event(player, DestroyStateChange(position, 10))?; + Ok(success) +} +/// Main component for the block breaking system. +/// Tracks the position of the block being mined, whether it will drop an item and the current progress. +#[derive(Clone)] +pub struct ActiveBreaker { + pub position: ValidBlockPosition, + pub drop_item: bool, + pub progress: f32, + pub damage: f32, +} +impl ActiveBreaker { + /// Advance block breaking by one tick. + pub fn tick(&mut self) -> (bool, bool) { + let before = self.destroy_stage(); + self.progress += self.damage; + let after = self.destroy_stage(); + let break_block = self.can_break(); + let change_stage = break_block || before != after; + (break_block, change_stage) + } + /// Check if the block has been damaged enough to break. + pub fn can_break(&self) -> bool { + self.progress >= BREAK_THRESHOLD - self.damage / 2.0 + } + /// Start breaking a block. Returns an error if the block at `block_pos` is unloaded or not diggable. + pub fn new( + world: &mut World, + block_pos: ValidBlockPosition, + equipped_item: Option<&ItemStack>, + ) -> anyhow::Result { + // https://minecraft.fandom.com/wiki/Breaking + let block = world + .block_at(block_pos) + .context("Block is not loaded")? + .kind(); + if !block.diggable() || block == BlockKind::Air { + anyhow::bail!("Block is not diggable") + } + let harvestable = match (block.harvest_tools(), equipped_item) { + (None, None | Some(_)) => true, + (Some(_), None) => false, + (Some(valid_tools), Some(equipped)) => valid_tools.contains(&equipped.item()), + }; + let dig_multiplier = block // TODO: calculate with Haste effect + .dig_multipliers() + .iter() + .find_map(|(item, speed)| { + equipped_item.and_then(|e| bool::then_some(e.item() == *item, *speed)) + }) + .unwrap_or(1.0); + let effi_level = equipped_item + .and_then(ItemStack::metadata) + .and_then(|meta| meta.get_enchantment_level(EnchantmentKind::Efficiency)); + let effi_speed = effi_level.map(|level| level * level + 1).unwrap_or(0) as f32; + let damage = if harvestable { + (dig_multiplier + effi_speed) / block.hardness() / 30.0 + } else { + 1.0 / block.hardness() / 100.0 + }; + Ok(Self { + position: block_pos, + drop_item: harvestable, + progress: damage, + damage, + }) + } + /// Get the destroying progress. + pub fn destroy_stage(&self) -> u8 { + (self.progress * 9.0).round() as u8 + } + pub fn destroy_change_event(&self) -> DestroyStateChange { + DestroyStateChange(self.position, self.destroy_stage()) + } +} + +pub fn register(systems: &mut SystemExecutor) { + systems.add_system(process_block_breaking); +} + +fn process_block_breaking(game: &mut Game) -> SysResult { + let mut update_queue = vec![]; + for (entity, breaker) in game.ecs.query::<&mut ActiveBreaker>().iter() { + let (_, update_stage) = breaker.tick(); + if update_stage { + update_queue.push(entity); + } + } + for entity in update_queue { + let event = game + .ecs + .get_mut::(entity)? + .destroy_change_event(); + game.ecs.insert_entity_event(entity, event)?; + } + Ok(()) +} diff --git a/feather/common/src/game.rs b/feather/common/src/game.rs index 64e6bf87d..0ab71fd95 100644 --- a/feather/common/src/game.rs +++ b/feather/common/src/game.rs @@ -1,11 +1,11 @@ use std::{cell::RefCell, mem, rc::Rc, sync::Arc}; -use base::{BlockId, ChunkPosition, Position, Text, Title, ValidBlockPosition}; +use base::{BlockId, ChunkPosition, Gamemode, Position, Text, Title, ValidBlockPosition}; use ecs::{ Ecs, Entity, EntityBuilder, HasEcs, HasResources, NoSuchEntity, Resources, SysResult, SystemExecutor, }; -use quill_common::events::{EntityCreateEvent, EntityRemoveEvent, PlayerJoinEvent}; +use quill_common::events::{EntityCreateEvent, EntityRemoveEvent, GamemodeEvent, PlayerJoinEvent}; use quill_common::{entities::Player, entity_init::EntityInit}; use crate::{ @@ -230,6 +230,11 @@ impl Game { pub fn break_block(&mut self, pos: ValidBlockPosition) -> bool { self.set_block(pos, BlockId::air()) } + + pub fn set_gamemode(&mut self, player: Entity, new: Gamemode) -> SysResult { + self.ecs.insert_entity_event(player, GamemodeEvent(new))?; + Ok(()) + } } impl HasResources for Game { diff --git a/feather/common/src/lib.rs b/feather/common/src/lib.rs index 9f9e7348a..bc91035b6 100644 --- a/feather/common/src/lib.rs +++ b/feather/common/src/lib.rs @@ -32,12 +32,15 @@ pub mod entities; pub mod interactable; +pub mod block_break; + /// Registers gameplay systems with the given `Game` and `SystemExecutor`. pub fn register(game: &mut Game, systems: &mut SystemExecutor) { view::register(game, systems); chunk::loading::register(game, systems); chunk::entities::register(systems); interactable::register(game); + block_break::register(systems); game.add_entity_spawn_callback(entities::add_entity_components); } diff --git a/feather/datapacks/src/id.rs b/feather/datapacks/src/id.rs index e0e9beebb..7f6213385 100644 --- a/feather/datapacks/src/id.rs +++ b/feather/datapacks/src/id.rs @@ -32,7 +32,7 @@ impl NamespacedId { } /// Error returned when a namespaced ID was formatted incorrectly. -#[derive(Debug, thiserror::Error, PartialEq)] +#[derive(Debug, thiserror::Error, PartialEq, Eq)] pub enum ParseError { #[error("'{0}' is not a valid character for namespaces")] InvalidNamespaceChar(char), diff --git a/feather/protocol/src/io.rs b/feather/protocol/src/io.rs index 4c9a51be6..fbe598fd0 100644 --- a/feather/protocol/src/io.rs +++ b/feather/protocol/src/io.rs @@ -480,7 +480,7 @@ impl<'a> Readable for LengthInferredVecU8<'a> { impl<'a> Writeable for LengthInferredVecU8<'a> { fn write(&self, buffer: &mut Vec, _version: ProtocolVersion) -> anyhow::Result<()> { - buffer.extend_from_slice(&*self.0); + buffer.extend_from_slice(&self.0); Ok(()) } } diff --git a/feather/server/src/client.rs b/feather/server/src/client.rs index f18af09a1..d1f00d07a 100644 --- a/feather/server/src/client.rs +++ b/feather/server/src/client.rs @@ -21,8 +21,9 @@ use common::{ use libcraft_items::InventorySlot; use packets::server::{Particle, SetSlot, SpawnLivingEntity, UpdateLight, WindowConfirmation}; use protocol::packets::server::{ - ChangeGameState, EntityPosition, EntityPositionAndRotation, EntityTeleport, GameStateChange, - HeldItemChange, PlayerAbilities, + AcknowledgePlayerDigging, BlockBreakAnimation, ChangeGameState, EntityPosition, + EntityPositionAndRotation, EntityTeleport, GameStateChange, HeldItemChange, PlayerAbilities, + PlayerDiggingStatus, }; use protocol::{ packets::{ @@ -611,6 +612,34 @@ impl Client { self.send_packet(HeldItemChange { slot }); } + pub fn acknowledge_player_digging( + &self, + position: ValidBlockPosition, + block: BlockId, + status: PlayerDiggingStatus, + successful: bool, + ) { + self.send_packet(AcknowledgePlayerDigging { + position, + block, + status, + successful, + }) + } + + pub fn block_break_animation( + &self, + entity_id: u32, + position: ValidBlockPosition, + destroy_stage: u8, + ) { + self.send_packet(BlockBreakAnimation { + entity_id: i32::from_le_bytes(entity_id.to_le_bytes()), + position, + destroy_stage, + }) + } + pub fn change_gamemode(&self, gamemode: Gamemode) { self.send_packet(ChangeGameState { state_change: GameStateChange::ChangeGamemode { gamemode }, diff --git a/feather/server/src/initial_handler/proxy.rs b/feather/server/src/initial_handler/proxy.rs index f2a2775bb..4a590b036 100644 --- a/feather/server/src/initial_handler/proxy.rs +++ b/feather/server/src/initial_handler/proxy.rs @@ -10,7 +10,7 @@ mod bungeecord; mod velocity; /// IP forwarding data received from the proxy. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub struct ProxyData { /// IP address of the proxy. pub host: String, diff --git a/feather/server/src/packet_handlers.rs b/feather/server/src/packet_handlers.rs index b0452c96a..019495530 100644 --- a/feather/server/src/packet_handlers.rs +++ b/feather/server/src/packet_handlers.rs @@ -1,4 +1,4 @@ -use base::{Position, Text}; +use base::{Gamemode, Position, Text}; use common::{chat::ChatKind, Game}; use ecs::{Entity, EntityRef, SysResult}; use interaction::{ @@ -45,7 +45,7 @@ pub fn handle_packet( ClientPlayPacket::Animation(packet) => handle_animation(server, player, packet), - ClientPlayPacket::ChatMessage(packet) => handle_chat_message(game, player, packet), + ClientPlayPacket::ChatMessage(packet) => handle_chat_message(game, player_id, packet), ClientPlayPacket::PlayerDigging(packet) => { handle_player_digging(game, server, packet, player_id) @@ -132,8 +132,16 @@ fn handle_animation( Ok(()) } -fn handle_chat_message(game: &Game, player: EntityRef, packet: client::ChatMessage) -> SysResult { - let name = player.get::()?; +fn handle_chat_message(game: &mut Game, player: Entity, packet: client::ChatMessage) -> SysResult { + if let m @ ("c" | "s") = &*packet.message { + if m == "c" { + game.set_gamemode(player, Gamemode::Creative)?; + } else { + game.set_gamemode(player, Gamemode::Survival)?; + } + } + + let name = game.ecs.get::(player)?; let message = Text::translate_with("chat.type.text", vec![name.to_string(), packet.message]); game.broadcast_chat(ChatKind::PlayerChat, message); Ok(()) diff --git a/feather/server/src/packet_handlers/interaction.rs b/feather/server/src/packet_handlers/interaction.rs index 1c6f69d9c..a01b3621a 100644 --- a/feather/server/src/packet_handlers/interaction.rs +++ b/feather/server/src/packet_handlers/interaction.rs @@ -118,9 +118,43 @@ pub fn handle_player_digging( player: Entity, ) -> SysResult { log::trace!("Got player digging with status {:?}", packet.status); + let client = server.clients.get(*game.ecs.get(player)?).unwrap(); + use PlayerDiggingStatus::*; + if matches!(packet.status, StartDigging | CancelDigging | FinishDigging) + && game.block(packet.position).is_none() + { + client.disconnect("Cannot interact with unloaded block!"); + anyhow::bail!("Cannot interact with unloaded block!") + } match packet.status { - PlayerDiggingStatus::StartDigging | PlayerDiggingStatus::CancelDigging => { - game.break_block(packet.position); + PlayerDiggingStatus::StartDigging => { + let success = common::block_break::start_digging(game, player, packet.position)?; + client.acknowledge_player_digging( + packet.position, + game.block(packet.position).unwrap(), + protocol::packets::server::PlayerDiggingStatus::Started, + success, + ); + Ok(()) + } + PlayerDiggingStatus::CancelDigging => { + let success = common::block_break::cancel_digging(game, player, packet.position)?; + client.acknowledge_player_digging( + packet.position, + game.block(packet.position).unwrap(), + protocol::packets::server::PlayerDiggingStatus::Cancelled, + success, + ); + Ok(()) + } + PlayerDiggingStatus::FinishDigging => { + let success = common::block_break::finish_digging(game, player, packet.position)?; + client.acknowledge_player_digging( + packet.position, + game.block(packet.position).unwrap(), + protocol::packets::server::PlayerDiggingStatus::Finished, + success, + ); Ok(()) } PlayerDiggingStatus::SwapItemInHand => { @@ -145,7 +179,9 @@ pub fn handle_player_digging( Ok(()) } - _ => Ok(()), + PlayerDiggingStatus::DropItemStack => Ok(()), + PlayerDiggingStatus::DropItem => Ok(()), + PlayerDiggingStatus::ShootArrow => Ok(()), } } diff --git a/feather/server/src/packet_handlers/inventory.rs b/feather/server/src/packet_handlers/inventory.rs index 48a397197..f8723b51c 100644 --- a/feather/server/src/packet_handlers/inventory.rs +++ b/feather/server/src/packet_handlers/inventory.rs @@ -56,7 +56,7 @@ pub fn handle_click_window( } client.set_cursor_slot(window.cursor_item()); - client.send_window_items(&*window); + client.send_window_items(&window); result } diff --git a/feather/server/src/systems/block.rs b/feather/server/src/systems/block.rs index 5544da2bd..50f75b7ad 100644 --- a/feather/server/src/systems/block.rs +++ b/feather/server/src/systems/block.rs @@ -15,7 +15,7 @@ use ahash::AHashMap; use base::{chunk::SECTION_VOLUME, position, ChunkPosition, CHUNK_WIDTH}; -use common::{events::BlockChangeEvent, Game}; +use common::{block_break::DestroyStateChange, events::BlockChangeEvent, Game}; use ecs::{SysResult, SystemExecutor}; use crate::Server; @@ -23,7 +23,17 @@ use crate::Server; pub fn register(systems: &mut SystemExecutor) { systems .group::() - .add_system(broadcast_block_changes); + .add_system(broadcast_block_changes) + .add_system(broadcast_block_destroy_stage_change); +} + +fn broadcast_block_destroy_stage_change(game: &mut Game, server: &mut Server) -> SysResult { + for (entity, event) in game.ecs.query::<&DestroyStateChange>().iter() { + server.broadcast_nearby_with(event.0.position(), |client| { + client.block_break_animation(entity.id(), event.0, event.1); + }); + } + Ok(()) } fn broadcast_block_changes(game: &mut Game, server: &mut Server) -> SysResult { diff --git a/feather/server/src/systems/player_join.rs b/feather/server/src/systems/player_join.rs index f8e01b195..31cb2af3e 100644 --- a/feather/server/src/systems/player_join.rs +++ b/feather/server/src/systems/player_join.rs @@ -103,6 +103,8 @@ fn accept_new_player(game: &mut Game, server: &mut Server, client_id: ClientId) client.send_window_items(&window); + let gamemode = Gamemode::Survival; + builder .add(client_id) .add(View::new( diff --git a/libcraft/items/src/item_stack.rs b/libcraft/items/src/item_stack.rs index 410e6650d..09fc7c142 100644 --- a/libcraft/items/src/item_stack.rs +++ b/libcraft/items/src/item_stack.rs @@ -351,6 +351,11 @@ impl ItemStack { pub fn stack_size(&self) -> u32 { self.item.stack_size() } + + #[must_use] + pub fn metadata(&self) -> Option<&ItemStackMeta> { + self.meta.as_ref() + } } /// An error type that may be returned when performing @@ -399,6 +404,14 @@ impl ItemStackMeta { self.enchantments.push(Enchantment::new(ench, level)); } } + #[must_use] + pub fn enchantments(&self) -> &[Enchantment] { + &self.enchantments + } + #[must_use] + pub fn enchantments_mut(&mut self) -> &mut Vec { + &mut self.enchantments + } } pub struct ItemStackBuilder { diff --git a/libcraft/text/src/text.rs b/libcraft/text/src/text.rs index 90af776de..ea5108e3f 100644 --- a/libcraft/text/src/text.rs +++ b/libcraft/text/src/text.rs @@ -16,7 +16,7 @@ pub enum TextConversionError { InvalidStyle(String), } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum Color { DarkRed, @@ -304,7 +304,7 @@ where } } -impl<'a> From<&Translate> for String { +impl From<&Translate> for String { fn from(translate: &Translate) -> Self { match translate { Translate::ChatTypeText => "chat.type.text", diff --git a/libcraft/text/src/text/markdown/lexer.rs b/libcraft/text/src/text/markdown/lexer.rs index 27e003e3b..899357bc8 100644 --- a/libcraft/text/src/text/markdown/lexer.rs +++ b/libcraft/text/src/text/markdown/lexer.rs @@ -13,7 +13,7 @@ use std::slice::Iter; pub type Span<'a> = LocatedSpan<&'a str>; -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct LexToken<'a> { pub tok: LexTokenType<'a>, pub span: Span<'a>, @@ -34,7 +34,7 @@ pub enum LexTokenType<'a> { Word(&'a str), } -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Tokens<'a> { pub tok: &'a [LexToken<'a>], start: usize, @@ -159,7 +159,7 @@ pub fn lex_control_word(input: Span) -> IResult IResult> { map(space1, |s: Span| { - LexToken::new(s, LexTokenType::Space(*s.fragment())) + LexToken::new(s, LexTokenType::Space(s.fragment())) })(input) } @@ -173,13 +173,13 @@ pub fn valid_word(input: Span) -> IResult> { pub fn lex_word(input: Span) -> IResult> { map(valid_word, |s: Span| { - LexToken::new(s, LexTokenType::Word(*s.fragment())) + LexToken::new(s, LexTokenType::Word(s.fragment())) })(input) } pub fn lex_color_code(input: Span) -> IResult> { map(preceded(peek(tag("#")), take(7usize)), |code: Span| { - LexToken::new(code, LexTokenType::Word(*code.fragment())) + LexToken::new(code, LexTokenType::Word(code.fragment())) })(input) } diff --git a/libcraft/text/src/text/markdown/parser.rs b/libcraft/text/src/text/markdown/parser.rs index 60ba2d9c5..52ed26bd4 100644 --- a/libcraft/text/src/text/markdown/parser.rs +++ b/libcraft/text/src/text/markdown/parser.rs @@ -9,7 +9,7 @@ use nom::{Err, IResult}; pub mod events; -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct DynamicSpan { pub fragment: String, pub col: usize, diff --git a/libcraft/text/src/text/markdown/parser/events.rs b/libcraft/text/src/text/markdown/parser/events.rs index 73932a840..d3e933318 100644 --- a/libcraft/text/src/text/markdown/parser/events.rs +++ b/libcraft/text/src/text/markdown/parser/events.rs @@ -4,13 +4,13 @@ pub enum EventParseError<'a> { InvalidEventAction(&'a str), } -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum EventType { OnHover, OnClick, } -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum EventAction { ShowText, OpenUrl, diff --git a/quill/api/src/setup.rs b/quill/api/src/setup.rs index 0b555b25f..07fdebf96 100644 --- a/quill/api/src/setup.rs +++ b/quill/api/src/setup.rs @@ -24,6 +24,7 @@ impl Setup { /// /// The function should take as parameters your /// plugin instance and an `&mut Game` and return nothing. + #[allow(clippy::type_complexity)] pub fn add_system(&mut self, system: T) -> &mut Self { let system: Box = Box::new(system); let system_data = Box::leak(Box::new(system)) as *mut Box<_> as *mut u8; diff --git a/quill/common/src/component.rs b/quill/common/src/component.rs index 11e4c4651..009efba9d 100644 --- a/quill/common/src/component.rs +++ b/quill/common/src/component.rs @@ -327,7 +327,7 @@ pod_component_impl!(Position); /** If you are using this macro and you get the error: -``` +```text error[E0599]: no variant or associated item named `...` found for enum `HostComponent` in the current scope. ``` Then you need to go to the top of the file were this macro is defined. There you find the HostCompoent enum, that diff --git a/quill/common/src/components.rs b/quill/common/src/components.rs index 352c45b69..b0fecea22 100644 --- a/quill/common/src/components.rs +++ b/quill/common/src/components.rs @@ -45,7 +45,7 @@ impl Name { } pub fn as_str(&self) -> &str { - &*self + self } } @@ -73,7 +73,7 @@ impl CustomName { } pub fn as_str(&self) -> &str { - &*self + self } pub fn as_mut_str(&mut self) -> &mut str { diff --git a/quill/plugin-format/src/lib.rs b/quill/plugin-format/src/lib.rs index 20a55c417..0c7ae0c53 100644 --- a/quill/plugin-format/src/lib.rs +++ b/quill/plugin-format/src/lib.rs @@ -43,7 +43,7 @@ impl<'a> PluginFile<'a> { /// this is the contents of the shared library /// containing the plugin. pub fn module(&self) -> &[u8] { - &*self.module + &self.module } pub fn metadata(&self) -> &PluginMetadata { diff --git a/quill/plugin-format/src/metadata.rs b/quill/plugin-format/src/metadata.rs index 66cd70eb5..b72b3e1a7 100644 --- a/quill/plugin-format/src/metadata.rs +++ b/quill/plugin-format/src/metadata.rs @@ -3,7 +3,7 @@ use serde_with::{serde_as, DisplayFromStr}; use target_lexicon::Triple; /// A plugin's metadata, stored alongside its WASM module. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct PluginMetadata { /// Plugin name, no spaces pub name: String,