diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/CraftEngineExpansion.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/CraftEngineExpansion.java new file mode 100644 index 000000000..e6c0866ed --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/CraftEngineExpansion.java @@ -0,0 +1,84 @@ +package net.momirealms.craftengine.bukkit.compatibility.papi; + +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.CooldownData; +import net.momirealms.craftengine.core.util.CountdownFormatter; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class CraftEngineExpansion extends PlaceholderExpansion { + private final CraftEngine plugin; + + public CraftEngineExpansion(CraftEngine plugin) { + this.plugin = plugin; + } + + @NotNull + @Override + public String getIdentifier() { + return "ce"; + } + + @NotNull + @Override + public String getAuthor() { + return "jhqwqmc"; + } + + @NotNull + @Override + public String getVersion() { + return "1.0"; + } + + /** + * 用法:(小括号括起来的为必填,中括号括起来的为选填) + *

+ * %ce_cd_(key)|[format]% + */ + @Override + public @Nullable String onPlaceholderRequest(Player bukkitPlayer, @NotNull String params) { + BukkitServerPlayer player = bukkitPlayer != null ? BukkitAdaptors.adapt(bukkitPlayer) : null; + int index = params.indexOf('_'); + String action = index > 0 ? params.substring(0, index) : params; + String[] param; + if (index > 0) { + String substring = params.substring(index + 1); + int i = substring.indexOf('|'); + if (i > 0) { + param = new String[]{substring.substring(0, i), substring.substring(i + 1)}; + } else { + param = new String[]{substring}; + } + } else { + param = new String[0]; + } + return switch (action) { + case "cd", "cooldown" -> handleCooldown(player, param); + default -> null; + }; + } + + @Nullable + private static String handleCooldown(@Nullable BukkitServerPlayer player, String[] param) { + if (player == null || param.length < 1) { + return null; + } + CooldownData cooldown = player.cooldown(); + if (cooldown == null) { + return null; + } + Long ms = cooldown.getCooldown(param[0]); + if (ms == null) { + return null; + } + if (param.length >= 2) { + return CountdownFormatter.of(param[1]).format(ms); + } + return String.valueOf(ms); + } +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java index 9f4dce361..fbfe15550 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java @@ -21,5 +21,6 @@ public class PlaceholderAPIUtils { new ImageExpansion(plugin).register(); new ShiftExpansion(plugin).register(); new CheckItemExpansion(plugin).register(); + new CraftEngineExpansion(plugin).register(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index be5385367..3b6b2d0e3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java @@ -603,7 +603,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // 如果不是原版物品,那么加入ce的标识符 if (!isVanillaItem) - itemBuilder.dataModifier(new IdProcessor(id)); + itemBuilder.dataModifier(new IdProcessor<>(id)); // 事件 Map>> eventTriggerListMap; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemProcessorFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemProcessorFactory.java index 52eb62df3..8e3aac5ab 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemProcessorFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemProcessorFactory.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.item.processor.ItemProcessor; -public interface ItemProcessorFactory { +public interface ItemProcessorFactory { - T create(Object arg); + ItemProcessor create(Object arg); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/processor/IdProcessor.java b/core/src/main/java/net/momirealms/craftengine/core/item/processor/IdProcessor.java index c5d3806b5..ac42c108b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/processor/IdProcessor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/processor/IdProcessor.java @@ -5,9 +5,9 @@ import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemProcessorFactory; import net.momirealms.craftengine.core.util.Key; -public class IdProcessor implements ItemProcessor { +public class IdProcessor implements ItemProcessor { public static final String CRAFT_ENGINE_ID = "craftengine:id"; - public static final ItemProcessorFactory FACTORY = new Factory(); + public static final ItemProcessorFactory FACTORY = new Factory<>(); private final Key argument; public IdProcessor(Key argument) { @@ -19,17 +19,17 @@ public class IdProcessor implements ItemProcessor { } @Override - public Item apply(Item item, ItemBuildContext context) { + public Item apply(Item item, ItemBuildContext context) { item.customId(this.argument); return item; } - private static class Factory implements ItemProcessorFactory { + private static class Factory implements ItemProcessorFactory { @Override - public IdProcessor create(Object arg) { + public ItemProcessor create(Object arg) { String id = arg.toString(); - return new IdProcessor(Key.of(id)); + return new IdProcessor<>(Key.of(id)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/processor/ItemProcessor.java b/core/src/main/java/net/momirealms/craftengine/core/item/processor/ItemProcessor.java index 661496897..6231646d0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/processor/ItemProcessor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/processor/ItemProcessor.java @@ -4,11 +4,11 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.sparrow.nbt.CompoundTag; -public interface ItemProcessor { +public interface ItemProcessor { - Item apply(Item item, ItemBuildContext context); + Item apply(Item item, ItemBuildContext context); - default Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + default Item prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { return item; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/processor/ItemProcessorType.java b/core/src/main/java/net/momirealms/craftengine/core/item/processor/ItemProcessorType.java index ef3657306..b5154e2e8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/processor/ItemProcessorType.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/processor/ItemProcessorType.java @@ -3,5 +3,5 @@ package net.momirealms.craftengine.core.item.processor; import net.momirealms.craftengine.core.item.ItemProcessorFactory; import net.momirealms.craftengine.core.util.Key; -public record ItemProcessorType(Key id, ItemProcessorFactory factory) { +public record ItemProcessorType(Key id, ItemProcessorFactory factory) { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java index 7ac74b314..88e7184cc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/CooldownData.java @@ -44,6 +44,10 @@ public class CooldownData { this.cooldownMap.clear(); } + public Long getCooldown(String key) { + return this.cooldownMap.get(key); + } + public static byte[] toBytes(CooldownData data) throws IOException { CompoundTag tag = new CompoundTag(); long currentTime = System.currentTimeMillis(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 2aff93d1c..1f643f31d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -18,7 +18,6 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorType; import net.momirealms.craftengine.core.item.equipment.Equipment; import net.momirealms.craftengine.core.item.equipment.EquipmentType; -import net.momirealms.craftengine.core.item.processor.ItemProcessor; import net.momirealms.craftengine.core.item.processor.ItemProcessorType; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.Recipe; @@ -66,7 +65,7 @@ import net.momirealms.craftengine.core.util.ResourceKey; public final class BuiltInRegistries { public static final Registry BLOCK = createDynamicBoundRegistry(Registries.BLOCK, 512); public static final Registry> BLOCK_BEHAVIOR_TYPE = createConstantBoundRegistry(Registries.BLOCK_BEHAVIOR_TYPE, 64); - public static final Registry> ITEM_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.ITEM_PROCESSOR_TYPE, 64); + public static final Registry> ITEM_PROCESSOR_TYPE = createConstantBoundRegistry(Registries.ITEM_PROCESSOR_TYPE, 64); public static final Registry> ITEM_BEHAVIOR_TYPE = createConstantBoundRegistry(Registries.ITEM_BEHAVIOR_TYPE, 64); public static final Registry>> PROPERTY_TYPE = createConstantBoundRegistry(Registries.PROPERTY_TYPE, 16); public static final Registry> LOOT_FUNCTION_TYPE = createConstantBoundRegistry(Registries.LOOT_FUNCTION_TYPE, 32); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index f13ddf7f4..24ce76c49 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -18,7 +18,6 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorType; import net.momirealms.craftengine.core.item.equipment.Equipment; import net.momirealms.craftengine.core.item.equipment.EquipmentType; -import net.momirealms.craftengine.core.item.processor.ItemProcessor; import net.momirealms.craftengine.core.item.processor.ItemProcessorType; import net.momirealms.craftengine.core.item.recipe.CustomSmithingTransformRecipe; import net.momirealms.craftengine.core.item.recipe.Recipe; @@ -69,7 +68,7 @@ public final class Registries { public static final Key ROOT_REGISTRY = Key.withDefaultNamespace("root"); public static final ResourceKey> BLOCK = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("block")); - public static final ResourceKey>> ITEM_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("item_processor_type")); + public static final ResourceKey>> ITEM_PROCESSOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("item_processor_type")); public static final ResourceKey>>> PROPERTY_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("property_type")); public static final ResourceKey>> BLOCK_BEHAVIOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("block_behavior_type")); public static final ResourceKey>> ITEM_BEHAVIOR_TYPE = ResourceKey.create(ROOT_REGISTRY, Key.withDefaultNamespace("item_behavior_type")); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/CountdownFormatter.java b/core/src/main/java/net/momirealms/craftengine/core/util/CountdownFormatter.java new file mode 100644 index 000000000..d1657faa6 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/CountdownFormatter.java @@ -0,0 +1,125 @@ +package net.momirealms.craftengine.core.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class CountdownFormatter { + private static final Pattern YEAR_PATTERN = Pattern.compile("[Yy]+"); + private static final Pattern MONTH_PATTERN = Pattern.compile("M+"); + private static final Pattern DAY_PATTERN = Pattern.compile("[Dd]+"); + private static final Pattern HOUR_PATTERN = Pattern.compile("[Hh]+"); + private static final Pattern MINUTE_PATTERN = Pattern.compile("m+"); + private static final Pattern SECOND_PATTERN = Pattern.compile("s+"); + private static final Pattern MILLIS_PATTERN = Pattern.compile("S+"); + private final String pattern; + private final Matcher yearMatcher; + private final Matcher monthMatcher; + private final Matcher dayMatcher; + private final Matcher hourMatcher; + private final Matcher minuteMatcher; + private final Matcher secondMatcher; + private final Matcher millisMatcher; + private final boolean hasYear; + private final boolean hasMonth; + private final boolean hasDay; + private final boolean hasHour; + private final boolean hasMinute; + private final boolean hasSecond; + private final boolean hasMillis; + + private CountdownFormatter(String pattern) { + this.pattern = pattern; + this.yearMatcher = YEAR_PATTERN.matcher(pattern); + this.monthMatcher = MONTH_PATTERN.matcher(pattern); + this.dayMatcher = DAY_PATTERN.matcher(pattern); + this.hourMatcher = HOUR_PATTERN.matcher(pattern); + this.minuteMatcher = MINUTE_PATTERN.matcher(pattern); + this.secondMatcher = SECOND_PATTERN.matcher(pattern); + this.millisMatcher = MILLIS_PATTERN.matcher(pattern); + this.hasYear = yearMatcher.find(); + this.hasMonth = monthMatcher.find(); + this.hasDay = dayMatcher.find(); + this.hasHour = hourMatcher.find(); + this.hasMinute = minuteMatcher.find(); + this.hasSecond = secondMatcher.find(); + this.hasMillis = millisMatcher.find(); + } + + public static CountdownFormatter of(String pattern) { + return new CountdownFormatter(pattern); + } + + public String format(long millis) { + long years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds = 0; + + if (!hasMillis) { + seconds = millis / 1000; + millis = 0; + } + if (!hasSecond) { + minutes = seconds / 60; + seconds = 0; + } + if (!hasMinute) { + hours = minutes / 60; + minutes = 0; + } + if (!hasHour) { + days = hours / 24; + hours = 0; + } + if (!hasDay) { + months = days / 30; + days = 0; + } + if (!hasMonth) { + years = months / 12; + months = 0; + } + + if (hasMillis && hasSecond) { + seconds = millis / 1000; + millis %= 1000; + } + if (hasSecond && hasMinute) { + minutes = seconds / 60; + seconds %= 60; + } + if (hasMinute && hasHour) { + hours = minutes / 60; + minutes %= 60; + } + if (hasHour && hasDay) { + days = hours / 24; + hours %= 24; + } + if (hasDay && hasMonth) { + months = days / 30; + days %= 30; + } + if (hasMonth && hasYear) { + years = months / 12; + months %= 12; + } + + StringBuilder result = new StringBuilder(pattern); + replaceUnit(result, yearMatcher, years); + replaceUnit(result, monthMatcher, months); + replaceUnit(result, dayMatcher, days); + replaceUnit(result, hourMatcher, hours); + replaceUnit(result, minuteMatcher, minutes); + replaceUnit(result, secondMatcher, seconds); + replaceUnit(result, millisMatcher, millis); + + return result.toString(); + } + + private void replaceUnit(StringBuilder text, Matcher matcher, long value) { + matcher.reset(text); + if (matcher.find()) { + int length = matcher.group().length(); + String formatted = String.format("%0" + length + "d", value); + text.replace(matcher.start(), matcher.end(), formatted); + } + } +}