9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-31 04:46:37 +00:00

增加条件,改进命令事件

This commit is contained in:
halogly
2025-08-23 11:27:07 +08:00
parent f8bbe9011a
commit cdad8190f1
19 changed files with 221 additions and 42 deletions

View File

@@ -52,6 +52,14 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
public abstract boolean isSneaking();
public abstract boolean isSwimming();
public abstract boolean isClimbing();
public abstract boolean isGliding();
public abstract boolean isFlying();
public abstract GameMode gameMode();
public abstract void setGameMode(GameMode gameMode);
@@ -106,9 +114,9 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
public abstract void performCommand(String command);
public abstract double luck();
public abstract void performCommandAsEvent(String command);
public abstract boolean isFlying();
public abstract double luck();
@Override
public Key type() {

View File

@@ -2,6 +2,8 @@ package net.momirealms.craftengine.core.plugin.context.condition;
import net.momirealms.craftengine.core.util.Key;
import java.util.Set;
public final class CommonConditions {
private CommonConditions() {}
@@ -10,6 +12,8 @@ public final class CommonConditions {
public static final Key ANY_OF = Key.of("craftengine:any_of");
public static final Key INVERTED = Key.of("craftengine:inverted");
public static final Key MATCH_ITEM = Key.of("craftengine:match_item");
public static final Key MATCH_ENTITY_TYPE = Key.of("craftengine:match_entity_type");
public static final Key MATCH_BLOCK_TYPE = Key.of("craftengine:match_block_type");
public static final Key MATCH_BLOCK_PROPERTY = Key.from("craftengine:match_block_property");
public static final Key TABLE_BONUS = Key.from("craftengine:table_bonus");
public static final Key SURVIVES_EXPLOSION = Key.from("craftengine:survives_explosion");
@@ -26,4 +30,18 @@ public final class CommonConditions {
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");
public static boolean matchObject(Key key, boolean regexMatch, Set<String> ids) {
String id = key.toString();
if (regexMatch) {
for (String regex : ids) {
if (id.matches(regex)) {
return true;
}
}
} else {
return ids.contains(id);
}
return false;
}
}

View File

@@ -0,0 +1,50 @@
package net.momirealms.craftengine.core.plugin.context.condition;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
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.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.BlockInWorld;
import java.util.*;
public class MatchBlockTypeCondition<CTX extends Context> implements Condition<CTX> {
private final Set<String> ids;
private final boolean regexMatch;
public MatchBlockTypeCondition(Collection<String> ids, boolean regexMatch) {
this.ids = new HashSet<>(ids);
this.regexMatch = regexMatch;
}
@Override
public Key type() {
return CommonConditions.MATCH_ENTITY_TYPE;
}
@Override
public boolean test(CTX ctx) {
Optional<BlockInWorld> block = ctx.getOptionalParameter(DirectContextParameters.BLOCK);
if (block.isEmpty()) return false;
Optional<ImmutableBlockState> customBlock = ctx.getOptionalParameter(DirectContextParameters.CUSTOM_BLOCK_STATE);
Key key = customBlock.isPresent() ? customBlock.get().owner().value().id() : block.get().type();
return CommonConditions.matchObject(key, this.regexMatch, this.ids);
}
public static class FactoryImpl<CTX extends Context> implements ConditionFactory<CTX> {
@Override
public Condition<CTX> create(Map<String, Object> arguments) {
List<String> ids = MiscUtils.getAsStringList(arguments.get("id"));
if (ids.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.condition.match_block_type.missing_id");
}
boolean regex = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("regex", false), "regex");
return new MatchBlockTypeCondition<>(ids, regex);
}
}
}

View File

@@ -0,0 +1,48 @@
package net.momirealms.craftengine.core.plugin.context.condition;
import net.momirealms.craftengine.core.entity.Entity;
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.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.*;
public class MatchEntityTypeCondition<CTX extends Context> implements Condition<CTX> {
private final Set<String> ids;
private final boolean regexMatch;
public MatchEntityTypeCondition(Collection<String> ids, boolean regexMatch) {
this.ids = new HashSet<>(ids);
this.regexMatch = regexMatch;
}
@Override
public Key type() {
return CommonConditions.MATCH_ENTITY_TYPE;
}
@Override
public boolean test(CTX ctx) {
Optional<Entity> entity = ctx.getOptionalParameter(DirectContextParameters.ENTITY);
if (entity.isEmpty()) return false;
Key key = entity.get().type();
return CommonConditions.matchObject(key, this.regexMatch, this.ids);
}
public static class FactoryImpl<CTX extends Context> implements ConditionFactory<CTX> {
@Override
public Condition<CTX> create(Map<String, Object> arguments) {
List<String> ids = MiscUtils.getAsStringList(arguments.get("id"));
if (ids.isEmpty()) {
throw new LocalizedResourceConfigException("warning.config.condition.match_entity_type.missing_id");
}
boolean regex = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("regex", false), "regex");
return new MatchEntityTypeCondition<>(ids, regex);
}
}
}

View File

@@ -30,17 +30,7 @@ public class MatchItemCondition<CTX extends Context> implements Condition<CTX> {
Optional<Item<?>> item = ctx.getOptionalParameter(DirectContextParameters.ITEM_IN_HAND);
if (item.isEmpty()) return false;
Key key = item.get().id();
String itemId = key.toString();
if (this.regexMatch) {
for (String regex : ids) {
if (itemId.matches(regex)) {
return true;
}
}
} else {
return this.ids.contains(itemId);
}
return false;
return CommonConditions.matchObject(key, this.regexMatch, this.ids);
}
public static class FactoryImpl<CTX extends Context> implements ConditionFactory<CTX> {

View File

@@ -17,6 +17,8 @@ public class EventConditions {
static {
register(CommonConditions.MATCH_ITEM, new MatchItemCondition.FactoryImpl<>());
register(CommonConditions.MATCH_ENTITY_TYPE, new MatchEntityTypeCondition.FactoryImpl<>());
register(CommonConditions.MATCH_BLOCK_TYPE, new MatchBlockTypeCondition.FactoryImpl<>());
register(CommonConditions.MATCH_BLOCK_PROPERTY, new MatchBlockPropertyCondition.FactoryImpl<>());
register(CommonConditions.TABLE_BONUS, new TableBonusCondition.FactoryImpl<>());
register(CommonConditions.SURVIVES_EXPLOSION, new SurvivesExplosionCondition.FactoryImpl<>());

View File

@@ -16,34 +16,34 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public class CommandFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
private final List<TextProvider> command;
private final boolean asPlayer;
private final PlayerSelector<CTX> selector;
private final boolean asPlayer;
private final boolean asEvent;
public CommandFunction(List<Condition<CTX>> predicates, @Nullable PlayerSelector<CTX> selector, List<TextProvider> command, boolean asPlayer) {
public CommandFunction(List<Condition<CTX>> predicates, @Nullable PlayerSelector<CTX> selector, List<TextProvider> command, boolean asPlayer, boolean asEvent) {
super(predicates);
this.asPlayer = asPlayer;
this.command = command;
this.selector = selector;
this.asPlayer = asPlayer;
this.asEvent = asEvent;
}
@Override
public void runInternal(CTX ctx) {
if (this.asPlayer) {
if (this.selector == null) {
ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> {
for (TextProvider c : this.command) {
it.performCommand(c.get(ctx));
}
});
ctx.getOptionalParameter(DirectContextParameters.PLAYER)
.ifPresent(player -> executeCommands(
ctx, this.asEvent ? player::performCommandAsEvent : player::performCommand
));
} else {
for (Player viewer : this.selector.get(ctx)) {
RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer, ContextHolder.EMPTY));
for (TextProvider c : this.command) {
viewer.performCommand(c.get(relationalContext));
}
executeCommands(relationalContext, this.asEvent ? viewer::performCommandAsEvent : viewer::performCommand);
}
}
} else {
@@ -54,6 +54,12 @@ public class CommandFunction<CTX extends Context> extends AbstractConditionalFun
}
}
private void executeCommands(Context ctx, Consumer<String> executor) {
for (TextProvider c : this.command) {
executor.accept(c.get(ctx));
}
}
@Override
public Key type() {
return CommonFunctions.COMMAND;
@@ -70,7 +76,8 @@ public class CommandFunction<CTX extends Context> extends AbstractConditionalFun
Object command = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(arguments, "command", "commands"), "warning.config.function.command.missing_command");
List<TextProvider> commands = MiscUtils.getAsStringList(command).stream().map(TextProviders::fromString).toList();
boolean asPlayer = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("as-player", false), "as-player");
return new CommandFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), commands, asPlayer);
boolean asEvent = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("as-event", false), "as-event");
return new CommandFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), commands, asPlayer, asEvent);
}
}
}

View File

@@ -57,8 +57,11 @@ public final class DirectContextParameters {
public static final ContextKey<AnchorType> ANCHOR_TYPE = ContextKey.direct("anchor_type");
public static final ContextKey<InteractionHand> HAND = ContextKey.direct("hand");
public static final ContextKey<Cancellable> EVENT = ContextKey.direct("event");
public static final ContextKey<Boolean> IS_FLYING = ContextKey.direct("is_flying");
public static final ContextKey<Boolean> IS_SNEAKING = ContextKey.direct("is_sneaking");
public static final ContextKey<Boolean> IS_SWIMMING = ContextKey.direct("is_swimming");
public static final ContextKey<Boolean> IS_CLIMBING = ContextKey.direct("is_climbing");
public static final ContextKey<Boolean> IS_GLIDING = ContextKey.direct("is_gliding");
public static final ContextKey<Boolean> IS_FLYING = ContextKey.direct("is_flying");
public static final ContextKey<Boolean> IS_CUSTOM = ContextKey.direct("is_custom");
public static final ContextKey<Boolean> IS_BLOCK_ITEM = ContextKey.direct("is_block_item");
public static final ContextKey<GameMode> GAMEMODE = ContextKey.direct("gamemode");

View File

@@ -29,8 +29,11 @@ public class PlayerParameterProvider implements ChainParameterProvider<Player> {
CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, Player::name);
CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, Player::uuid);
CONTEXT_FUNCTIONS.put(DirectContextParameters.WORLD, Entity::world);
CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_FLYING, Player::isFlying);
CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_SNEAKING, Player::isSneaking);
CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_SWIMMING, Player::isSwimming);
CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_CLIMBING, Player::isClimbing);
CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_GLIDING, Player::isGliding);
CONTEXT_FUNCTIONS.put(DirectContextParameters.IS_FLYING, Player::isFlying);
CONTEXT_FUNCTIONS.put(DirectContextParameters.GAMEMODE, Player::gameMode);
CONTEXT_FUNCTIONS.put(DirectContextParameters.MAIN_HAND_ITEM, p -> p.getItemInHand(InteractionHand.MAIN_HAND));
CONTEXT_FUNCTIONS.put(DirectContextParameters.OFF_HAND_ITEM, p -> p.getItemInHand(InteractionHand.OFF_HAND));

View File

@@ -12,7 +12,8 @@ public enum SoundSource {
NEUTRAL("neutral"),
PLAYER("player"),
AMBIENT("ambient"),
VOICE("voice");
VOICE("voice"),
UI("ui");
private final String id;

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.world;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.Nullable;
public interface BlockInWorld {
@@ -27,6 +28,8 @@ public interface BlockInWorld {
World world();
Key type();
int x();
int y();