9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-25 09:59:20 +00:00

添加新的函数和条件类型

This commit is contained in:
XiaoMoMi
2025-05-21 23:41:52 +08:00
parent 7bcfbf9cfe
commit 454e778378
37 changed files with 589 additions and 35 deletions

View File

@@ -95,6 +95,8 @@ warning.config.condition.equals.missing_value1: "<yellow>Issue found in file <ar
warning.config.condition.equals.missing_value2: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'value2' argument for 'equals' condition.</yellow>"
warning.config.condition.expression.missing_expression: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'expression' argument for 'expression' condition.</yellow>"
warning.config.condition.is_null.missing_argument: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'argument' argument for 'is_null' condition.</yellow>"
warning.config.condition.hand.missing_hand: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'hand' argument for 'hand' condition.</yellow>"
warning.config.condition.hand.invalid_hand: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid 'hand' argument '<arg:2>' for 'hand' condition. Allowed hand types: [<arg:3>]</yellow>"
warning.config.structure.not_section: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is expected to be a config section while it's actually a(n) '<arg:2>'.</yellow>"
warning.config.image.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated image '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
warning.config.image.missing_height: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is missing the required 'height' argument.</yellow>"
@@ -319,6 +321,9 @@ warning.config.function.open_window.missing_gui_type: "<yellow>Issue found in fi
warning.config.function.open_window.invalid_gui_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid gui type <arg:2> for 'open_window' function. Allowed types: [<arg:3>].</yellow>"
warning.config.function.run.missing_functions: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'functions' argument for 'run' function.</yellow>"
warning.config.function.place_block.missing_block_state: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'block-state' argument for 'place_block' function.</yellow>"
warning.config.function.set_food.missing_food: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'food' argument for 'set_food' function.</yellow>"
warning.config.function.set_saturation.missing_saturation: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'saturation' argument for 'set_saturation' function.</yellow>"
warning.config.function.play_sound.missing_sound: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'sound' argument for 'play_sound' function.</yellow>"
warning.config.selector.missing_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'type' argument for selector.</yellow>"
warning.config.selector.invalid_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid selector type '<arg:2>'.</yellow>"
warning.config.selector.invalid_target: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid selector target '<arg:2>'.</yellow>"

View File

@@ -96,6 +96,8 @@ warning.config.condition.equals.missing_value2: "<yellow>在文件 <arg:0> 中
warning.config.condition.expression.missing_expression: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'expression' 条件必需的 'expression' 参数</yellow>"
warning.config.condition.is_null.missing_argument: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'is_null' 条件的必需的 'argument' 参数.</yellow>"
warning.config.structure.not_section: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 应为配置段落 但实际类型为 '<arg:2>'</yellow>"
warning.config.condition.hand.missing_hand: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'hand' argument for 'hand' condition.</yellow>"
warning.config.condition.hand.invalid_hand: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid 'hand' argument '<arg:2>' for 'hand' condition. Allowed hand types: [<arg:3>]</yellow>"
warning.config.image.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的图片配置 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
warning.config.image.missing_height: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 缺少必需的 'height' 参数</yellow>"
warning.config.image.height_ascent_conflict: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 违反位图规则: 'height' 参数 '<arg:2>' 必须不小于 'ascent' 参数 '<arg:3>'</yellow>"
@@ -319,6 +321,9 @@ warning.config.function.open_window.missing_gui_type: "<yellow>在文件 <arg:0>
warning.config.function.open_window.invalid_gui_type: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 为 'open_window' 函数使用了无效的 GUI 类型 <arg:2>. 允许的类型: [<arg:3>]。</yellow>"
warning.config.function.run.missing_functions: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'run' 函数必需的 'functions' 参数</yellow>"
warning.config.function.place_block.missing_block_state: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'place_block' 函数必需的 'block-state' 参数.</yellow>"
warning.config.function.set_food.missing_food: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'food' argument for 'set_food' function.</yellow>"
warning.config.function.set_saturation.missing_saturation: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'saturation' argument for 'set_saturation' function.</yellow>"
warning.config.function.play_sound.missing_sound: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'sound' argument for 'play_sound' function.</yellow>"
warning.config.selector.missing_type: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少选择器必需的 'type' 参数</yellow>"
warning.config.selector.invalid_type: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 使用了无效的选择器类型 '<arg:2>'</yellow>"
warning.config.selector.invalid_target: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 使用了无效的选择器目标 '<arg:2>'</yellow>"

View File

@@ -42,12 +42,12 @@ public class BukkitEntity extends AbstractEntity {
}
@Override
public float getXRot() {
public float xRot() {
return literalObject().getYaw();
}
@Override
public float getYRot() {
public float yRot() {
return literalObject().getPitch();
}

View File

@@ -98,6 +98,6 @@ public class ComponentItemWrapper implements ItemWrapper<ItemStack> {
@Override
public void count(int amount) {
this.item.setAmount(amount);
this.item.setAmount(Math.max(amount, 0));
}
}

View File

@@ -60,7 +60,7 @@ public class LegacyItemWrapper implements ItemWrapper<ItemStack> {
@Override
public ItemStack load() {
ItemStack itemStack = this.rtagItem.load();
itemStack.setAmount(this.count);
itemStack.setAmount(Math.max(this.count, 0));
return itemStack;
}

View File

@@ -105,7 +105,7 @@ public class FurnitureItemBehavior extends ItemBehavior {
finalPlacePosition = new Vec3d(xz.left(), xz.right(), clickedPosition.z());
}
} else {
furnitureYaw = placement.rotationRule().apply(180 + player.getXRot());
furnitureYaw = placement.rotationRule().apply(180 + player.xRot());
Pair<Double, Double> xz = placement.alignmentRule().apply(Pair.of(clickedPosition.x(), clickedPosition.z()));
finalPlacePosition = new Vec3d(xz.left(), clickedPosition.y(), xz.right());
}

View File

@@ -675,12 +675,12 @@ public class BukkitServerPlayer extends Player {
}
@Override
public float getYRot() {
public float yRot() {
return platformPlayer().getPitch();
}
@Override
public float getXRot() {
public float xRot() {
return platformPlayer().getYaw();
}
@@ -838,4 +838,24 @@ public class BukkitServerPlayer extends Player {
public boolean isFlying() {
return platformPlayer().isFlying();
}
@Override
public int foodLevel() {
return platformPlayer().getFoodLevel();
}
@Override
public void setFoodLevel(int foodLevel) {
this.platformPlayer().setFoodLevel(Math.min(Math.max(0, foodLevel), 20));
}
@Override
public float saturation() {
return platformPlayer().getSaturation();
}
@Override
public void setSaturation(float saturation) {
this.platformPlayer().setSaturation(saturation);
}
}

View File

@@ -1,7 +1,9 @@
package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.core.block.BlockSounds;
import net.momirealms.craftengine.core.sound.SoundSource;
import net.momirealms.craftengine.core.util.Key;
import org.bukkit.SoundCategory;
public class SoundUtils {
@@ -21,4 +23,19 @@ public class SoundUtils {
public static Object getOrRegisterSoundEvent(Key key) throws ReflectiveOperationException {
return Reflections.method$SoundEvent$createVariableRangeEvent.invoke(null, KeyUtils.toResourceLocation(key));
}
public static SoundCategory toBukkit(SoundSource source) {
return switch (source) {
case BLOCK -> SoundCategory.BLOCKS;
case MUSIC -> SoundCategory.MUSIC;
case VOICE -> SoundCategory.VOICE;
case MASTER -> SoundCategory.MASTER;
case PLAYER -> SoundCategory.PLAYERS;
case RECORD -> SoundCategory.RECORDS;
case AMBIENT -> SoundCategory.AMBIENT;
case HOSTILE -> SoundCategory.HOSTILE;
case NEUTRAL -> SoundCategory.NEUTRAL;
case WEATHER -> SoundCategory.WEATHER;
};
}
}

View File

@@ -3,8 +3,10 @@ package net.momirealms.craftengine.bukkit.world;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.util.EntityUtils;
import net.momirealms.craftengine.bukkit.util.ItemUtils;
import net.momirealms.craftengine.bukkit.util.SoundUtils;
import net.momirealms.craftengine.core.block.BlockStateWrapper;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.sound.SoundSource;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.core.world.BlockInWorld;
@@ -87,6 +89,11 @@ public class BukkitWorld implements World {
});
}
@Override
public void playSound(Position location, Key sound, float volume, float pitch, SoundSource source) {
platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundUtils.toBukkit(source), volume, pitch);
}
@Override
public void playBlockSound(Position location, Key sound, float volume, float pitch) {
platformWorld().playSound(new Location(null, location.x(), location.y(), location.z()), sound.toString(), SoundCategory.BLOCKS, volume, pitch);

View File

@@ -6,6 +6,6 @@ public abstract class AbstractEntity implements Entity {
@Override
public WorldPosition position() {
return new WorldPosition(world(), x(), y(), z(), getXRot(), getYRot());
return new WorldPosition(world(), x(), y(), z(), xRot(), yRot());
}
}

View File

@@ -20,12 +20,12 @@ public interface Entity {
void tick();
float getXRot();
float xRot();
float yRot();
int entityID();
float getYRot();
World world();
Direction getDirection();

View File

@@ -116,4 +116,12 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
public boolean isAdventureMode() {
return gameMode() == GameMode.ADVENTURE;
}
public abstract int foodLevel();
public abstract void setFoodLevel(int foodLevel);
public abstract float saturation();
public abstract void setSaturation(float saturation);
}

View File

@@ -73,6 +73,6 @@ public class UseOnContext {
}
public float getRotation() {
return this.player == null ? 0.0F : this.player.getYRot();
return this.player == null ? 0.0F : this.player.yRot();
}
}

View File

@@ -34,6 +34,7 @@ public class LootConditions {
register(CommonConditions.EQUALS, new EqualsCondition.FactoryImpl<>());
register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>());
register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>());
register(CommonConditions.HAND, new HandCondition.FactoryImpl<>());
}
public static void register(Key key, ConditionFactory<LootContext> factory) {

View File

@@ -78,15 +78,15 @@ public class LootTable<T> {
);
}
public ArrayList<Item<T>> getRandomItems(ContextHolder parameters, World world) {
public List<Item<T>> getRandomItems(ContextHolder parameters, World world) {
return this.getRandomItems(parameters, world, null);
}
public ArrayList<Item<T>> getRandomItems(ContextHolder parameters, World world, @Nullable Player player) {
public List<Item<T>> getRandomItems(ContextHolder parameters, World world, @Nullable Player player) {
return this.getRandomItems(new LootContext(world, player, player == null ? 1f : (float) player.luck(), parameters));
}
private ArrayList<Item<T>> getRandomItems(LootContext context) {
private List<Item<T>> getRandomItems(LootContext context) {
ArrayList<Item<T>> list = new ArrayList<>();
this.getRandomItems(context, list::add);
return list;

View File

@@ -21,4 +21,5 @@ public final class CommonConditions {
public static final Key EQUALS = Key.from("craftengine:equals");
public static final Key EXPRESSION = Key.from("craftengine:expression");
public static final Key IS_NULL = Key.from("craftengine:is_null");
public static final Key HAND = Key.from("craftengine:hand");
}

View File

@@ -0,0 +1,49 @@
package net.momirealms.craftengine.core.plugin.context.condition;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
public class HandCondition<CTX extends Context> implements Condition<CTX> {
private final InteractionHand hand;
public HandCondition(InteractionHand hand) {
this.hand = hand;
}
@Override
public Key type() {
return CommonConditions.HAND;
}
@Override
public boolean test(CTX ctx) {
Optional<InteractionHand> optional = ctx.getOptionalParameter(DirectContextParameters.HAND);
if (optional.isPresent()) {
InteractionHand hand = optional.get();
return hand.equals(this.hand);
}
return false;
}
public static class FactoryImpl<CTX extends Context> implements ConditionFactory<CTX> {
@Override
public Condition<CTX> create(Map<String, Object> arguments) {
String hand = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("hand"), "warning.config.condition.hand.missing_hand");
try {
return new HandCondition<>(InteractionHand.valueOf(hand.toUpperCase(Locale.ENGLISH)));
} catch (IllegalArgumentException e) {
throw new LocalizedResourceConfigException("warning.config.condition.hand.invalid_hand", hand);
}
}
}
}

View File

@@ -24,7 +24,7 @@ public class IsNullCondition<CTX extends Context> implements Condition<CTX> {
@Override
public boolean test(CTX ctx) {
Optional<?> optional = ctx.getOptionalParameter(this.key);
return optional.isPresent();
return optional.isEmpty();
}
public static class FactoryImpl<CTX extends Context> implements ConditionFactory<CTX> {

View File

@@ -32,6 +32,7 @@ public class EventConditions {
register(CommonConditions.EQUALS, new EqualsCondition.FactoryImpl<>());
register(CommonConditions.EXPRESSION, new ExpressionCondition.FactoryImpl<>());
register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>());
register(CommonConditions.HAND, new HandCondition.FactoryImpl<>());
}
public static void register(Key key, ConditionFactory<PlayerOptionalContext> factory) {

View File

@@ -26,6 +26,13 @@ public class EventFunctions {
register(CommonFunctions.RUN, new RunFunction.FactoryImpl<>(EventFunctions::fromMap, EventConditions::fromMap));
register(CommonFunctions.PLACE_BLOCK, new PlaceBlockFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.BREAK_BLOCK, new BreakBlockFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.UPDATE_INTERACTION_TICK, new UpdateInteractionFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.SET_COUNT, new SetCountFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.DROP_LOOT, new DropLootFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.SWING_HAND, new SwingHandFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.SET_FOOD, new SetFoodFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.SET_SATURATION, new SetSaturationFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.PLAY_SOUND, new PlaySoundFunction.FactoryImpl<>(EventConditions::fromMap));
}
public static void register(Key key, FunctionFactory<PlayerOptionalContext> factory) {

View File

@@ -44,9 +44,9 @@ public class BreakBlockFunction<CTX extends Context> extends AbstractConditional
@Override
public Function<CTX> create(Map<String, Object> arguments) {
NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "<arg:block.block_x>"));
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:block.block_y>"));
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:block.block_z>"));
NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "<arg:position.x>"));
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:position.y>"));
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:position.z>"));
return new BreakBlockFunction<>(x, y, z, getPredicates(arguments));
}
}

View File

@@ -12,15 +12,15 @@ public final class CommonFunctions {
public static final Key TITLE = Key.of("craftengine:title");
public static final Key OPEN_WINDOW = Key.of("craftengine:open_window");
public static final Key PARTICLE = Key.of("craftengine:particle");
public static final Key SOUND = Key.of("craftengine:sound");
public static final Key PLAY_SOUND = Key.of("craftengine:play_sound");
public static final Key POTION_EFFECT = Key.of("craftengine:potion_effect");
public static final Key BREAK_BLOCK = Key.of("craftengine:break_block");
public static final Key CANCEL_EVENT = Key.of("craftengine:cancel_event");
public static final Key UPDATE_INTERACTION_TICK = Key.of("craftengine:update_interaction_tick");
public static final Key SET_COUNT = Key.of("craftengine:set_count");
public static final Key PLACE_BLOCK = Key.of("craftengine:place_block");
public static final Key FOOD = Key.of("craftengine:food");
public static final Key SATURATION = Key.of("craftengine:saturation");
public static final Key MONEY = Key.of("craftengine:money");
public static final Key OXYGEN = Key.of("craftengine:oxygen");
public static final Key MINE_RADIUS = Key.of("craftengine:mine_radius");
public static final Key SET_FOOD = Key.of("craftengine:food");
public static final Key SET_SATURATION = Key.of("craftengine:saturation");
public static final Key DROP_LOOT = Key.of("craftengine:drop_loot");
public static final Key SWING_HAND = Key.of("craftengine:swing_hand");
}

View File

@@ -0,0 +1,68 @@
package net.momirealms.craftengine.core.plugin.context.function;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldPosition;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class DropLootFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
private final NumberProvider x;
private final NumberProvider y;
private final NumberProvider z;
private final LootTable<?> lootTable;
public DropLootFunction(NumberProvider x, NumberProvider y, NumberProvider z, LootTable<?> lootTable, List<Condition<CTX>> predicates) {
super(predicates);
this.x = x;
this.y = y;
this.z = z;
this.lootTable = lootTable;
}
@Override
public void runInternal(CTX ctx) {
Optional<WorldPosition> optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION);
if (optionalWorldPosition.isPresent()) {
World world = optionalWorldPosition.get().world();
WorldPosition position = new WorldPosition(world, x.getDouble(ctx), y.getDouble(ctx), z.getDouble(ctx));
Player player = ctx.getOptionalParameter(DirectContextParameters.PLAYER).orElse(null);
List<? extends Item<?>> items = lootTable.getRandomItems(ctx.contexts(), world, player);
for (Item<?> item : items) {
world.dropItemNaturally(position, item);
}
}
}
@Override
public Key type() {
return CommonFunctions.DROP_LOOT;
}
public static class FactoryImpl<CTX extends Context> extends AbstractFactory<CTX> {
public FactoryImpl(java.util.function.Function<Map<String, Object>, Condition<CTX>> factory) {
super(factory);
}
@Override
public Function<CTX> create(Map<String, Object> arguments) {
NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "<arg:position.x>"));
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:position.y>"));
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:position.z>"));
LootTable<?> loots = LootTable.fromMap(MiscUtils.castToMap(arguments.get("loot"), true));
return new DropLootFunction<>(x, y, z, loots, getPredicates(arguments));
}
}
}

View File

@@ -77,9 +77,9 @@ public class PlaceBlockFunction<CTX extends Context> extends AbstractConditional
public Function<CTX> create(Map<String, Object> arguments) {
String state = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("block-state"), "warning.config.function.place_block.missing_block_state");
DelayedInitBlockState delayedInitBlockState = new DelayedInitBlockState(state);
NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "<arg:block.block_x>"));
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:block.block_y>"));
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:block.block_z>"));
NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "<arg:position.x>"));
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:position.y>"));
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:position.z>"));
NumberProvider flags = Optional.ofNullable(arguments.get("update-flags")).map(NumberProviders::fromObject).orElse(NumberProviders.direct(UpdateOption.UPDATE_ALL.flags()));
return new PlaceBlockFunction<>(delayedInitBlockState, x, y, z, flags, getPredicates(arguments));
}

View File

@@ -0,0 +1,73 @@
package net.momirealms.craftengine.core.plugin.context.function;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.sound.SoundSource;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldPosition;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
public class PlaySoundFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
private final Key soundEvent;
private final NumberProvider x;
private final NumberProvider y;
private final NumberProvider z;
private final NumberProvider volume;
private final NumberProvider pitch;
private final SoundSource source;
public PlaySoundFunction(Key soundEvent, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider volume, NumberProvider pitch, SoundSource source, List<Condition<CTX>> predicates) {
super(predicates);
this.soundEvent = soundEvent;
this.x = x;
this.y = y;
this.z = z;
this.volume = volume;
this.pitch = pitch;
this.source = source;
}
@Override
public void runInternal(CTX ctx) {
Optional<WorldPosition> optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION);
if (optionalWorldPosition.isPresent()) {
World world = optionalWorldPosition.get().world();
world.playSound(new Vec3d(this.x.getDouble(ctx), this.y.getDouble(ctx), this.z.getDouble(ctx)),
this.soundEvent, this.volume.getFloat(ctx), this.pitch.getFloat(ctx), this.source);
}
}
@Override
public Key type() {
return CommonFunctions.PLAY_SOUND;
}
public static class FactoryImpl<CTX extends Context> extends AbstractFactory<CTX> {
public FactoryImpl(java.util.function.Function<Map<String, Object>, Condition<CTX>> factory) {
super(factory);
}
@Override
public Function<CTX> create(Map<String, Object> arguments) {
Key soundEvent = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("sound"), "warning.config.function.play_sound.missing_sound"));
NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "<arg:position.x>"));
NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "<arg:position.y>"));
NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "<arg:position.z>"));
NumberProvider volume = NumberProviders.fromObject(arguments.getOrDefault("volume", 1));
NumberProvider pitch = NumberProviders.fromObject(arguments.getOrDefault("pitch", 1));
SoundSource source = Optional.ofNullable(arguments.get("source")).map(String::valueOf).map(it -> SoundSource.valueOf(it.toUpperCase(Locale.ENGLISH))).orElse(SoundSource.MASTER);
return new PlaySoundFunction<>(soundEvent, x, y, z, volume, pitch, source, getPredicates(arguments));
}
}
}

View File

@@ -0,0 +1,57 @@
package net.momirealms.craftengine.core.plugin.context.function;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class SetCountFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
private final NumberProvider count;
private final boolean add;
public SetCountFunction(NumberProvider count, boolean add, List<Condition<CTX>> predicates) {
super(predicates);
this.count = count;
this.add = add;
}
@Override
public void runInternal(CTX ctx) {
Optional<Item<?>> optionalItem = ctx.getOptionalParameter(DirectContextParameters.ITEM_IN_HAND);
if (optionalItem.isPresent()) {
Item<?> item = optionalItem.get();
if (this.add) {
item.count(Math.min(item.count() + (this.count.getInt(ctx)), item.maxStackSize()));
} else {
item.count(Math.min(this.count.getInt(ctx), item.maxStackSize()));
}
}
}
@Override
public Key type() {
return CommonFunctions.SET_COUNT;
}
public static class FactoryImpl<CTX extends Context> extends AbstractFactory<CTX> {
public FactoryImpl(java.util.function.Function<Map<String, Object>, Condition<CTX>> factory) {
super(factory);
}
@Override
public Function<CTX> create(Map<String, Object> arguments) {
Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("count"), "warning.config.function.set_count.missing_count");
boolean add = (boolean) arguments.getOrDefault("add", false);
return new SetCountFunction<>(NumberProviders.fromObject(value), add, getPredicates(arguments));
}
}
}

View File

@@ -0,0 +1,50 @@
package net.momirealms.craftengine.core.plugin.context.function;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class SetFoodFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
private final NumberProvider count;
private final boolean add;
public SetFoodFunction(NumberProvider count, boolean add, List<Condition<CTX>> predicates) {
super(predicates);
this.count = count;
this.add = add;
}
@Override
public void runInternal(CTX ctx) {
Optional<Player> optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER);
optionalPlayer.ifPresent(player -> player.setFoodLevel(this.add ? player.foodLevel() + this.count.getInt(ctx) : this.count.getInt(ctx)));
}
@Override
public Key type() {
return CommonFunctions.SET_FOOD;
}
public static class FactoryImpl<CTX extends Context> extends AbstractFactory<CTX> {
public FactoryImpl(java.util.function.Function<Map<String, Object>, Condition<CTX>> factory) {
super(factory);
}
@Override
public Function<CTX> create(Map<String, Object> arguments) {
Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("food"), "warning.config.function.set_food.missing_food");
boolean add = (boolean) arguments.getOrDefault("add", false);
return new SetFoodFunction<>(NumberProviders.fromObject(value), add, getPredicates(arguments));
}
}
}

View File

@@ -0,0 +1,50 @@
package net.momirealms.craftengine.core.plugin.context.function;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class SetSaturationFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
private final NumberProvider count;
private final boolean add;
public SetSaturationFunction(NumberProvider count, boolean add, List<Condition<CTX>> predicates) {
super(predicates);
this.count = count;
this.add = add;
}
@Override
public void runInternal(CTX ctx) {
Optional<Player> optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER);
optionalPlayer.ifPresent(player -> player.setSaturation(this.add ? player.saturation() + this.count.getFloat(ctx) : this.count.getFloat(ctx)));
}
@Override
public Key type() {
return CommonFunctions.SET_SATURATION;
}
public static class FactoryImpl<CTX extends Context> extends AbstractFactory<CTX> {
public FactoryImpl(java.util.function.Function<Map<String, Object>, Condition<CTX>> factory) {
super(factory);
}
@Override
public Function<CTX> create(Map<String, Object> arguments) {
Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("saturation"), "warning.config.function.set_saturation.missing_saturation");
boolean add = (boolean) arguments.getOrDefault("add", false);
return new SetSaturationFunction<>(NumberProviders.fromObject(value), add, getPredicates(arguments));
}
}
}

View File

@@ -0,0 +1,52 @@
package net.momirealms.craftengine.core.plugin.context.function;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.Key;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
public class SwingHandFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
private final Optional<InteractionHand> hand;
public SwingHandFunction(Optional<InteractionHand> hand, List<Condition<CTX>> predicates) {
super(predicates);
this.hand = hand;
}
@Override
public void runInternal(CTX ctx) {
Optional<Player> cancellable = ctx.getOptionalParameter(DirectContextParameters.PLAYER);
cancellable.ifPresent(value -> {
if (this.hand.isPresent()) {
value.swingHand(this.hand.get());
} else {
value.swingHand(ctx.getOptionalParameter(DirectContextParameters.HAND).orElse(InteractionHand.MAIN_HAND));
}
});
}
@Override
public Key type() {
return CommonFunctions.SWING_HAND;
}
public static class FactoryImpl<CTX extends Context> extends AbstractFactory<CTX> {
public FactoryImpl(java.util.function.Function<Map<String, Object>, Condition<CTX>> factory) {
super(factory);
}
@Override
public Function<CTX> create(Map<String, Object> arguments) {
Optional<InteractionHand> optionalHand = Optional.ofNullable(arguments.get("hand")).map(it -> InteractionHand.valueOf(it.toString().toUpperCase(Locale.ENGLISH)));
return new SwingHandFunction<>(optionalHand, getPredicates(arguments));
}
}
}

View File

@@ -0,0 +1,41 @@
package net.momirealms.craftengine.core.plugin.context.function;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.Key;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class UpdateInteractionFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
public UpdateInteractionFunction(List<Condition<CTX>> predicates) {
super(predicates);
}
@Override
public void runInternal(CTX ctx) {
Optional<Player> cancellable = ctx.getOptionalParameter(DirectContextParameters.PLAYER);
cancellable.ifPresent(value -> value.updateLastSuccessfulInteractionTick(value.gameTicks()));
}
@Override
public Key type() {
return CommonFunctions.UPDATE_INTERACTION_TICK;
}
public static class FactoryImpl<CTX extends Context> extends AbstractFactory<CTX> {
public FactoryImpl(java.util.function.Function<Map<String, Object>, Condition<CTX>> factory) {
super(factory);
}
@Override
public Function<CTX> create(Map<String, Object> arguments) {
return new UpdateInteractionFunction<>(getPredicates(arguments));
}
}
}

View File

@@ -39,9 +39,13 @@ public final class DirectContextParameters {
public static final ContextKey<Double> X = ContextKey.direct("x");
public static final ContextKey<Double> Y = ContextKey.direct("y");
public static final ContextKey<Double> Z = ContextKey.direct("z");
public static final ContextKey<Float> YAW = ContextKey.direct("yaw");
public static final ContextKey<Float> PITCH = ContextKey.direct("pitch");
public static final ContextKey<Integer> BLOCK_X = ContextKey.direct("block_x");
public static final ContextKey<Integer> BLOCK_Y = ContextKey.direct("block_y");
public static final ContextKey<Integer> BLOCK_Z = ContextKey.direct("block_z");
public static final ContextKey<Integer> FOOD = ContextKey.direct("food");
public static final ContextKey<Float> SATURATION = ContextKey.direct("saturation");
public static final ContextKey<UUID> UUID = ContextKey.direct("uuid");
public static final ContextKey<Item<?>> MAIN_HAND_ITEM = ContextKey.direct("main_hand_item");
public static final ContextKey<Item<?>> OFF_HAND_ITEM = ContextKey.direct("off_hand_item");

View File

@@ -16,6 +16,8 @@ public class EntityParameterProvider implements ChainParameterProvider<Entity> {
CONTEXT_FUNCTIONS.put(DirectContextParameters.X, Entity::x);
CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, Entity::y);
CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, Entity::z);
CONTEXT_FUNCTIONS.put(DirectContextParameters.YAW, Entity::xRot);
CONTEXT_FUNCTIONS.put(DirectContextParameters.PITCH, Entity::yRot);
CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, Entity::position);
CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x()));
CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y()));

View File

@@ -1,6 +1,5 @@
package net.momirealms.craftengine.core.plugin.context.parameter;
import net.momirealms.craftengine.core.entity.AbstractEntity;
import net.momirealms.craftengine.core.entity.Entity;
import net.momirealms.craftengine.core.entity.player.InteractionHand;
import net.momirealms.craftengine.core.entity.player.Player;
@@ -16,13 +15,17 @@ import java.util.function.Function;
public class PlayerParameterProvider implements ChainParameterProvider<Player> {
private static final Map<ContextKey<?>, Function<Player, Object>> CONTEXT_FUNCTIONS = new HashMap<>();
static {
CONTEXT_FUNCTIONS.put(DirectContextParameters.X, AbstractEntity::x);
CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, AbstractEntity::y);
CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, AbstractEntity::z);
CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, AbstractEntity::position);
CONTEXT_FUNCTIONS.put(DirectContextParameters.X, Entity::x);
CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, Entity::y);
CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, Entity::z);
CONTEXT_FUNCTIONS.put(DirectContextParameters.YAW, Entity::xRot);
CONTEXT_FUNCTIONS.put(DirectContextParameters.PITCH, Entity::yRot);
CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, Entity::position);
CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x()));
CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y()));
CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z()));
CONTEXT_FUNCTIONS.put(DirectContextParameters.FOOD, Player::foodLevel);
CONTEXT_FUNCTIONS.put(DirectContextParameters.SATURATION, Player::saturation);
CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, Player::name);
CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, Player::uuid);
CONTEXT_FUNCTIONS.put(DirectContextParameters.WORLD, Entity::world);

View File

@@ -18,6 +18,8 @@ public class PositionParameterProvider implements ChainParameterProvider<WorldPo
CONTEXT_FUNCTIONS.put(DirectContextParameters.X, WorldPosition::x);
CONTEXT_FUNCTIONS.put(DirectContextParameters.Y, WorldPosition::y);
CONTEXT_FUNCTIONS.put(DirectContextParameters.Z, WorldPosition::z);
CONTEXT_FUNCTIONS.put(DirectContextParameters.YAW, WorldPosition::xRot);
CONTEXT_FUNCTIONS.put(DirectContextParameters.PITCH, WorldPosition::yRot);
CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x()));
CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y()));
CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z()));

View File

@@ -0,0 +1,27 @@
package net.momirealms.craftengine.core.sound;
import org.jetbrains.annotations.NotNull;
public enum SoundSource {
MASTER("master"),
MUSIC("music"),
RECORD("record"),
WEATHER("weather"),
BLOCK("block"),
HOSTILE("hostile"),
NEUTRAL("neutral"),
PLAYER("player"),
AMBIENT("ambient"),
VOICE("voice");
private final String id;
SoundSource(final String id) {
this.id = id;
}
@NotNull
public String id() {
return this.id;
}
}

View File

@@ -94,8 +94,8 @@ public enum Direction {
}
public static Direction[] orderedByNearest(AbstractEntity entity) {
float xRotation = entity.getXRot() * (float) (Math.PI / 180.0);
float yRotation = -entity.getYRot() * (float) (Math.PI / 180.0);
float xRotation = entity.xRot() * (float) (Math.PI / 180.0);
float yRotation = -entity.yRot() * (float) (Math.PI / 180.0);
float sinX = (float) Math.sin(xRotation);
float cosX = (float) Math.cos(xRotation);
float sinY = (float) Math.sin(yRotation);

View File

@@ -1,8 +1,10 @@
package net.momirealms.craftengine.core.world;
import net.kyori.adventure.sound.Sound;
import net.momirealms.craftengine.core.block.BlockStateWrapper;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.sound.SoundData;
import net.momirealms.craftengine.core.sound.SoundSource;
import net.momirealms.craftengine.core.util.Key;
import java.nio.file.Path;
@@ -34,6 +36,8 @@ public interface World {
void dropExp(Position location, int amount);
void playSound(Position location, Key sound, float volume, float pitch, SoundSource source);
void playBlockSound(Position location, Key sound, float volume, float pitch);
default void playBlockSound(Position location, SoundData data) {