Skip to content

Commit

Permalink
feat: add amount to /give (#525)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrew Gazelka <andrew.gazelka@gmail.com>
  • Loading branch information
CuzImClicks and andrewgazelka authored Oct 30, 2024
1 parent c85f961 commit bf7663b
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 27 deletions.
81 changes: 60 additions & 21 deletions events/proof-of-concept/src/module/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@ use std::borrow::Cow;

use flecs_ecs::prelude::*;
use hyperion::{
chat,
egress::player_join::{PlayerListActions, PlayerListEntry, PlayerListS2c},
net::{Compose, NetworkStreamRef},
simulation::{
blocks::Blocks,
command::{add_command, get_root_command, Command, Parser},
event, Health, InGameName, Position, Uuid,
command::{add_command, cmd_with, get_root_command, Command, Parser},
event, Health, IgnMap, InGameName, Position, Uuid,
},
storage::EventQueue,
system_registry::SystemId,
uuid,
valence_ident::ident,
valence_protocol::{
self,
game_mode::OptGameMode,
ident,
math::IVec3,
nbt,
packets::play::{
Expand Down Expand Up @@ -43,9 +44,26 @@ pub fn add_to_tree(world: &World) {
// add to tree
add_command(world, Command::literal("team"), root_command);
add_command(world, Command::literal("zombie"), root_command);
add_command(world, Command::literal("give"), root_command);
add_command(world, Command::literal("upgrade"), root_command);

cmd_with(world, "give", |scope| {
scope.argument_with(
"player",
Parser::Entity {
single: true,
only_players: true,
},
|scope| {
scope.argument_with("", Parser::ItemStack, |scope| {
scope.argument("count", Parser::Integer {
min: Some(1),
max: None,
});
});
},
);
});

let speed = add_command(world, Command::literal("speed"), root_command);
add_command(
world,
Expand Down Expand Up @@ -101,6 +119,7 @@ struct CommandContext<'a> {
inventory: &'a mut PlayerInventory,
level: &'a mut Level,
health: &'a mut Health,
ign_map: &'a IgnMap,
}

fn process_command(command: &ParsedCommand, context: &mut CommandContext<'_>) {
Expand All @@ -109,7 +128,11 @@ fn process_command(command: &ParsedCommand, context: &mut CommandContext<'_>) {
ParsedCommand::Team => handle_team_command(context),
ParsedCommand::Zombie => handle_zombie_command(context),
ParsedCommand::Dirt { x, y, z } => handle_dirt_command(*x, *y, *z, context),
ParsedCommand::Give => handle_give_command(context),
ParsedCommand::Give {
username,
item,
count,
} => handle_give_command(username, item, *count, context),
ParsedCommand::Upgrade => handle_upgrade_command(context),
ParsedCommand::Stats(stat, amount) => handle_stats(*stat, *amount, context),
ParsedCommand::Health(amount) => handle_health_command(*amount, context),
Expand Down Expand Up @@ -351,24 +374,39 @@ fn handle_stats(stat: Stat, amount: f32, context: &CommandContext<'_>) {
});
}

fn handle_give_command(context: &mut CommandContext<'_>) {
let mut blue_wool_nbt = nbt::Compound::new();
fn handle_give_command(username: &str, item_name: &str, count: i8, context: &CommandContext<'_>) {
let Some(item) = ItemKind::from_str(item_name) else {
let packet = chat!("Unknown item '{item_name:?}'");
context
.compose
.unicast(&packet, context.stream, context.system_id, context.world)
.unwrap();
return;
};

let Some(player) = context.ign_map.get(username) else {
let chat = chat!("Player {username} does not exist");
context
.compose
.unicast(&chat, context.stream, context.system_id, context.world)
.unwrap();
return;
};

let can_place_on = [
"minecraft:stone",
"minecraft:dirt",
"minecraft:grass_block",
"minecraft:blue_wool",
]
.into_iter()
.map(std::convert::Into::into)
.collect();
context
.world
.entity_from_id(*player)
.get::<&mut PlayerInventory>(|inventory| {
inventory.try_add_item(ItemStack::new(item, count, None));
});

blue_wool_nbt.insert("CanPlaceOn", nbt::List::String(can_place_on));
let name = item.to_str();

let packet = chat!("Gave {count} [{name}] to {username}");
context
.inventory
.try_add_item(ItemStack::new(ItemKind::BlueWool, 4, Some(blue_wool_nbt)));
.compose
.unicast(&packet, context.stream, context.system_id, context.world)
.unwrap();
}

fn handle_dirt_command(x: i32, y: i32, z: i32, context: &mut CommandContext<'_>) {
Expand Down Expand Up @@ -603,9 +641,9 @@ impl Module for CommandModule {

let system_id = SystemId(8);

system!("handle_poc_events_player", world, &Compose($), &mut EventQueue<event::Command<'_>>($), &mut Blocks($))
system!("handle_poc_events_player", world, &Compose($), &mut EventQueue<event::Command<'_>>($), &mut Blocks($), &IgnMap($))
.multi_threaded()
.each_iter(move |it: TableIter<'_, false>, _, (compose, event_queue, mc)| {
.each_iter(move |it: TableIter<'_, false>, _, (compose, event_queue, mc, ign_map)| {
let span = trace_span!("handle_poc_events_player");
let _enter = span.enter();

Expand Down Expand Up @@ -644,6 +682,7 @@ impl Module for CommandModule {
level,
health,
position,
ign_map,
};
process_command(&command, &mut context);
},
Expand Down
67 changes: 61 additions & 6 deletions events/proof-of-concept/src/module/command/parse.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use nom::{
branch::alt,
bytes::complete::{tag, take_until},
bytes::complete::{tag, take_until, take_while1},
character::complete::space1,
combinator::{map, map_res},
combinator::{map, map_res, opt},
number::complete::float,
sequence::preceded,
IResult, Parser,
Expand All @@ -21,13 +21,33 @@ pub enum ParsedCommand {
Speed(f32),
Team,
Zombie,
Dirt { x: i32, y: i32, z: i32 },
Give,
Dirt {
x: i32,
y: i32,
z: i32,
},
Give {
username: String,
item: String,
count: i8,
},
Upgrade,
Stats(Stat, f32),
Health(f32),
TpHere,
Tp { x: f32, y: f32, z: f32 },
Tp {
x: f32,
y: f32,
z: f32,
},
}

fn is_valid_player_char(c: char) -> bool {
c.is_alphanumeric() || c == '_'
}

fn space1_str(input: &str) -> IResult<&str, &str> {
space1::<&str, nom::error::Error<&str>>(input)
}

fn parse_speed(input: &str) -> IResult<&str, ParsedCommand> {
Expand Down Expand Up @@ -62,7 +82,23 @@ fn parse_dirt(input: &str) -> IResult<&str, ParsedCommand> {
}

fn parse_give(input: &str) -> IResult<&str, ParsedCommand> {
map(tag("give"), |_| ParsedCommand::Give).parse(input)
map(
(
tag("give "),
take_while1(is_valid_player_char),
preceded(
space1_str,
preceded(opt(tag("minecraft:")), take_while1(is_valid_player_char)),
),
opt(preceded(space1_str, nom::character::complete::i8)),
),
|(_, username, item, count)| ParsedCommand::Give {
username: username.to_string(),
item: item.to_string(),
count: count.unwrap_or(1),
},
)
.parse(input)
}

fn parse_upgrade(input: &str) -> IResult<&str, ParsedCommand> {
Expand Down Expand Up @@ -124,3 +160,22 @@ pub fn command(input: &str) -> IResult<&str, ParsedCommand> {
))
.parse(input)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_parse_give_command() {
let input = "give Cuz_Im_Clicks minecraft:dirt 64";
let result = parse_give(input);
assert!(result.is_ok());
}

#[test]
fn test_parse_give_command_no_minecraft() {
let input = "give Cuz_Im_Clicks acacia_button 64";
let result = parse_give(input);
assert!(result.is_ok());
}
}

0 comments on commit bf7663b

Please sign in to comment.