mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-25 01:49:30 +00:00
Merge branch 'Xiao-MoMi:dev' into dev
This commit is contained in:
@@ -10,7 +10,8 @@ import net.momirealms.craftengine.bukkit.compatibility.leveler.*;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterModelModel;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineModel;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineUtils;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicMobsListener;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicItemDropListener;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicSkillHelper;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners;
|
||||
import net.momirealms.craftengine.bukkit.compatibility.skript.SkriptHook;
|
||||
@@ -39,6 +40,7 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
|
||||
private final Map<String, LevelerProvider> levelerProviders;
|
||||
private boolean hasPlaceholderAPI;
|
||||
private boolean hasViaVersion;
|
||||
private MythicSkillHelper skillExecute;
|
||||
|
||||
public BukkitCompatibilityManager(BukkitCraftEngine plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -131,11 +133,16 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
|
||||
}
|
||||
if (this.isPluginEnabled("MythicMobs")) {
|
||||
BukkitItemManager.instance().registerExternalItemSource(new MythicMobsSource());
|
||||
new MythicMobsListener(this.plugin);
|
||||
new MythicItemDropListener(this.plugin);
|
||||
logHook("MythicMobs");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeMMSkill(String skill, float power, Player player) {
|
||||
MythicSkillHelper.execute(skill, power, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLevelerProvider(String plugin, LevelerProvider provider) {
|
||||
this.levelerProviders.put(plugin, provider);
|
||||
|
||||
@@ -21,12 +21,12 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
public class CraftEngineItemDrop extends ItemDrop implements IItemDrop {
|
||||
public class MythicItemDrop extends ItemDrop implements IItemDrop {
|
||||
private final CustomItem<ItemStack> customItem;
|
||||
private static final Constructor<?> constructor$BukkitItemStack = ReflectionUtils.getConstructor(BukkitItemStack.class, ItemStack.class);
|
||||
private static final boolean useReflection = constructor$BukkitItemStack != null;
|
||||
|
||||
public CraftEngineItemDrop(String line, MythicLineConfig config, CustomItem<ItemStack> customItem) {
|
||||
public MythicItemDrop(String line, MythicLineConfig config, CustomItem<ItemStack> customItem) {
|
||||
super(line, config);
|
||||
this.customItem = customItem;
|
||||
}
|
||||
@@ -8,10 +8,10 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public class MythicMobsListener implements Listener {
|
||||
public class MythicItemDropListener implements Listener {
|
||||
private final BukkitCraftEngine plugin;
|
||||
|
||||
public MythicMobsListener(BukkitCraftEngine plugin) {
|
||||
public MythicItemDropListener(BukkitCraftEngine plugin) {
|
||||
this.plugin = plugin;
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin.javaPlugin());
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public class MythicMobsListener implements Listener {
|
||||
this.plugin.itemManager().getCustomItem(itemId).ifPresent(customItem -> {
|
||||
String line = event.getContainer().getConfigLine();
|
||||
MythicLineConfig config = event.getConfig();
|
||||
event.register(new CraftEngineItemDrop(line, config, customItem));
|
||||
event.register(new MythicItemDrop(line, config, customItem));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.mythicmobs;
|
||||
|
||||
import io.lumine.mythic.bukkit.MythicBukkit;
|
||||
import io.lumine.mythic.core.utils.MythicUtil;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class MythicSkillHelper {
|
||||
|
||||
public static void execute(String skill, float power, Player player) {
|
||||
org.bukkit.entity.Player casterPlayer = (org.bukkit.entity.Player) player.platformPlayer();
|
||||
Location location = casterPlayer.getLocation();
|
||||
LivingEntity target = MythicUtil.getTargetedEntity(casterPlayer);
|
||||
List<Entity> targets = new ArrayList<>();
|
||||
List<Location> locations = null;
|
||||
if (target != null) {
|
||||
targets.add(target);
|
||||
locations = List.of(target.getLocation());
|
||||
}
|
||||
MythicBukkit.inst().getAPIHelper().castSkill(casterPlayer, skill, casterPlayer, location, targets, locations, power);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.worldedit;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkitWorld;
|
||||
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.FaweAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder;
|
||||
import com.fastasyncworldedit.core.math.IntPair;
|
||||
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
||||
import com.fastasyncworldedit.core.util.ProcessorTraverser;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
@@ -24,6 +27,7 @@ import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.injector.WorldStorageInjector;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.core.block.EmptyBlock;
|
||||
@@ -89,12 +93,14 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent {
|
||||
if (levelChunk != null) {
|
||||
Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk);
|
||||
CESection[] ceSections = ceChunk.sections();
|
||||
for (int i = 0; i < ceSections.length; i++) {
|
||||
CESection ceSection = ceSections[i];
|
||||
Object section = sections[i];
|
||||
int finalI = i;
|
||||
WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z),
|
||||
(injected) -> sections[finalI] = injected);
|
||||
synchronized (sections) {
|
||||
for (int i = 0; i < ceSections.length; i++) {
|
||||
CESection ceSection = ceSections[i];
|
||||
Object section = sections[i];
|
||||
int finalI = i;
|
||||
WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z),
|
||||
(injected) -> sections[finalI] = injected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,18 +180,18 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent {
|
||||
|
||||
@Override
|
||||
public @Nullable Operation commit() {
|
||||
Operation operation = super.commit();
|
||||
saveAllChunks();
|
||||
Operation operation = super.commit();
|
||||
List<ChunkPos> chunks = new ArrayList<>(this.brokenChunks);
|
||||
this.brokenChunks.clear();
|
||||
Object worldServer = this.ceWorld.world().serverWorld();
|
||||
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer);
|
||||
for (ChunkPos chunk : chunks) {
|
||||
CEChunk loaded = this.ceWorld.getChunkAtIfLoaded(chunk.longKey());
|
||||
// only inject loaded chunks
|
||||
if (loaded == null) continue;
|
||||
injectLevelChunk(chunkSource, loaded);
|
||||
}
|
||||
Object worldServer = this.ceWorld.world().serverWorld();
|
||||
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer);
|
||||
for (ChunkPos chunk : chunks) {
|
||||
CEChunk loaded = this.ceWorld.getChunkAtIfLoaded(chunk.longKey());
|
||||
// only inject loaded chunks
|
||||
if (loaded == null) continue;
|
||||
injectLevelChunk(chunkSource, loaded);
|
||||
}
|
||||
return operation;
|
||||
}
|
||||
|
||||
@@ -214,11 +220,12 @@ public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent {
|
||||
try {
|
||||
CEChunk ceChunk = Optional.ofNullable(this.ceWorld.getChunkAtIfLoaded(chunkX, chunkZ))
|
||||
.orElse(this.ceWorld.worldDataStorage().readChunkAt(this.ceWorld, new ChunkPos(chunkX, chunkZ)));
|
||||
CESection ceSection = ceChunk.sectionById(SectionPos.blockToSectionCoord(blockY));
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(newStateId);
|
||||
if (immutableBlockState == null) {
|
||||
ceChunk.setBlockState(blockX, blockY, blockZ, EmptyBlock.STATE);
|
||||
ceSection.setBlockState(blockX & 15, blockY & 15, blockZ & 15, EmptyBlock.STATE);
|
||||
} else {
|
||||
ceChunk.setBlockState(blockX, blockY, blockZ, immutableBlockState);
|
||||
ceSection.setBlockState(blockX & 15, blockY & 15, blockZ & 15, immutableBlockState);
|
||||
}
|
||||
this.chunksToSave.add(ceChunk);
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -1,23 +1,12 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.command.feature;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.entity.data.HappyGhastData;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.bukkit.parser.location.LocationParser;
|
||||
import org.incendo.cloud.parser.standard.IntegerParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class TestCommand extends BukkitCommandFeature<CommandSender> {
|
||||
|
||||
@@ -29,35 +18,9 @@ public class TestCommand extends BukkitCommandFeature<CommandSender> {
|
||||
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
|
||||
return builder
|
||||
.senderType(Player.class)
|
||||
.required("location", LocationParser.locationParser())
|
||||
.required("remove", IntegerParser.integerParser())
|
||||
.handler(context -> {
|
||||
Player player = context.sender();
|
||||
int removeEntityId = context.get("remove");
|
||||
if (removeEntityId >= 0) {
|
||||
try {
|
||||
Object packet = NetworkReflections.constructor$ClientboundRemoveEntitiesPacket.newInstance((Object) new int[]{removeEntityId});
|
||||
plugin().adapt(player).sendPacket(packet, true);
|
||||
player.sendMessage("发送成功");
|
||||
} catch (ReflectiveOperationException e) {
|
||||
player.sendMessage("发送失败");
|
||||
}
|
||||
return;
|
||||
}
|
||||
Location location = context.get("location");
|
||||
int entityId = CoreReflections.instance$Entity$ENTITY_COUNTER.incrementAndGet();
|
||||
List<Object> packets = new ArrayList<>();
|
||||
List<Object> cachedShulkerValues = new ArrayList<>();
|
||||
HappyGhastData.MobFlags.addEntityDataIfNotDefaultValue((byte) 0x01, cachedShulkerValues); // NO AI
|
||||
// HappyGhastData.SharedFlags.addEntityDataIfNotDefaultValue((byte) 0x20, cachedShulkerValues); // Invisible
|
||||
HappyGhastData.StaysStill.addEntityDataIfNotDefaultValue(true, cachedShulkerValues);
|
||||
packets.add(FastNMS.INSTANCE.constructor$ClientboundAddEntityPacket(
|
||||
entityId, UUID.randomUUID(), location.x(), location.y(), location.z(), 0, location.getYaw(),
|
||||
MEntityTypes.HAPPY_GHAST, 0, CoreReflections.instance$Vec3$Zero, 0
|
||||
));
|
||||
packets.add(FastNMS.INSTANCE.constructor$ClientboundSetEntityDataPacket(entityId, List.copyOf(cachedShulkerValues)));
|
||||
plugin().adapt(player).sendPackets(packets, true);
|
||||
player.sendMessage("发送成功 id: " + entityId);
|
||||
player.sendMessage("客户端模组状态: " + BukkitNetworkManager.instance().getUser(player).clientModEnabled());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import net.momirealms.craftengine.bukkit.plugin.network.handler.*;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.NetWorkDataTypes;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload;
|
||||
import net.momirealms.craftengine.bukkit.plugin.network.payload.UnknownPayload;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
|
||||
@@ -105,7 +106,7 @@ public class PacketConsumers {
|
||||
byte yHeadRot = buf.readByte();
|
||||
int data = buf.readVarInt();
|
||||
// Falling blocks
|
||||
int remapped = remap(data);
|
||||
int remapped = user.clientModEnabled() ? remapMOD(data) : remap(data);
|
||||
if (remapped != data) {
|
||||
int xa = buf.readShort();
|
||||
int ya = buf.readShort();
|
||||
@@ -428,7 +429,7 @@ public class PacketConsumers {
|
||||
if (user.clientModEnabled() && !BlockStateUtils.isVanillaBlock(before)) {
|
||||
return;
|
||||
}
|
||||
int state = remap(before);
|
||||
int state = user.clientModEnabled() ? remapMOD(before) : remap(before);
|
||||
if (state == before) {
|
||||
return;
|
||||
}
|
||||
@@ -450,7 +451,7 @@ public class PacketConsumers {
|
||||
BlockPos blockPos = buf.readBlockPos();
|
||||
int state = buf.readInt();
|
||||
boolean global = buf.readBoolean();
|
||||
int newState = remap(state);
|
||||
int newState = user.clientModEnabled() ? remapMOD(state) : remap(state);
|
||||
if (newState == state) {
|
||||
return;
|
||||
}
|
||||
@@ -1006,7 +1007,7 @@ public class PacketConsumers {
|
||||
if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return;
|
||||
Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option);
|
||||
int id = BlockStateUtils.blockStateToId(blockState);
|
||||
int remapped = remap(id);
|
||||
int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id);
|
||||
if (remapped == id) return;
|
||||
Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option);
|
||||
Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped));
|
||||
@@ -1046,7 +1047,7 @@ public class PacketConsumers {
|
||||
if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return;
|
||||
Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option);
|
||||
int id = BlockStateUtils.blockStateToId(blockState);
|
||||
int remapped = remap(id);
|
||||
int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id);
|
||||
if (remapped == id) return;
|
||||
Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option);
|
||||
Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped));
|
||||
@@ -1086,7 +1087,7 @@ public class PacketConsumers {
|
||||
if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return;
|
||||
Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option);
|
||||
int id = BlockStateUtils.blockStateToId(blockState);
|
||||
int remapped = remap(id);
|
||||
int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id);
|
||||
if (remapped == id) return;
|
||||
Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option);
|
||||
Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped));
|
||||
@@ -1884,34 +1885,38 @@ public class PacketConsumers {
|
||||
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> CUSTOM_PAYLOAD = (user, event, packet) -> {
|
||||
try {
|
||||
if (!VersionHelper.isOrAbove1_20_5()) return;
|
||||
if (!VersionHelper.isOrAbove1_20_2()) return;
|
||||
Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet);
|
||||
Payload clientPayload;
|
||||
if (NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) {
|
||||
Payload discardedPayload = DiscardedPayload.from(payload);
|
||||
if (discardedPayload == null || !discardedPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY))
|
||||
clientPayload = DiscardedPayload.from(payload);
|
||||
} else if (!VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$UnknownPayload.isInstance(payload)) {
|
||||
clientPayload = UnknownPayload.from(payload);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY))
|
||||
return;
|
||||
FriendlyByteBuf buf = clientPayload.toBuffer();
|
||||
NetWorkDataTypes dataType = buf.readEnumConstant(NetWorkDataTypes.class);
|
||||
if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) {
|
||||
int clientBlockRegistrySize = dataType.decode(buf);
|
||||
int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize();
|
||||
if (clientBlockRegistrySize != serverBlockRegistrySize) {
|
||||
user.kick(Component.translatable(
|
||||
"disconnect.craftengine.block_registry_mismatch",
|
||||
TranslationArgument.numeric(clientBlockRegistrySize),
|
||||
TranslationArgument.numeric(serverBlockRegistrySize)
|
||||
));
|
||||
return;
|
||||
FriendlyByteBuf buf = discardedPayload.toBuffer();
|
||||
NetWorkDataTypes<?> dataType = NetWorkDataTypes.readType(buf);
|
||||
if (dataType == NetWorkDataTypes.CLIENT_CUSTOM_BLOCK) {
|
||||
int clientBlockRegistrySize = dataType.as(Integer.class).decode(buf);
|
||||
int serverBlockRegistrySize = RegistryUtils.currentBlockRegistrySize();
|
||||
if (clientBlockRegistrySize != serverBlockRegistrySize) {
|
||||
user.kick(Component.translatable(
|
||||
"disconnect.craftengine.block_registry_mismatch",
|
||||
TranslationArgument.numeric(clientBlockRegistrySize),
|
||||
TranslationArgument.numeric(serverBlockRegistrySize)
|
||||
));
|
||||
return;
|
||||
}
|
||||
user.setClientModState(true);
|
||||
} else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) {
|
||||
if (!VersionHelper.isOrAbove1_20_2()) return;
|
||||
if (dataType.as(Boolean.class).decode(buf)) {
|
||||
FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer());
|
||||
dataType.writeType(bufPayload);
|
||||
dataType.as(Boolean.class).encode(bufPayload, true);
|
||||
user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array());
|
||||
}
|
||||
}
|
||||
user.setClientModState(true);
|
||||
} else if (dataType == NetWorkDataTypes.CANCEL_BLOCK_UPDATE) {
|
||||
if (dataType.decode(buf)) {
|
||||
FriendlyByteBuf bufPayload = new FriendlyByteBuf(Unpooled.buffer());
|
||||
bufPayload.writeEnumConstant(dataType);
|
||||
dataType.encode(bufPayload, true);
|
||||
user.sendCustomPayload(NetworkManager.MOD_CHANNEL_KEY, bufPayload.array());
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -1,64 +1,28 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.network.payload;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
|
||||
public enum NetWorkDataTypes {
|
||||
CLIENT_CUSTOM_BLOCK(NetWorkCodecs.INTEGER),
|
||||
CANCEL_BLOCK_UPDATE(NetWorkCodecs.BOOLEAN);
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
private final NetWorkCodec<?> codec;
|
||||
|
||||
public class NetWorkDataTypes<T> {
|
||||
private static final Map<Integer, NetWorkDataTypes<?>> id2NetWorkDataTypes = new HashMap<>();
|
||||
|
||||
public static final NetWorkDataTypes<Integer> CLIENT_CUSTOM_BLOCK =
|
||||
new NetWorkDataTypes<>(0, FriendlyByteBuf::readInt, FriendlyByteBuf::writeInt);
|
||||
|
||||
public static final NetWorkDataTypes<Boolean> CANCEL_BLOCK_UPDATE =
|
||||
new NetWorkDataTypes<>(1, FriendlyByteBuf::readBoolean, FriendlyByteBuf::writeBoolean);
|
||||
|
||||
static {
|
||||
register(CLIENT_CUSTOM_BLOCK);
|
||||
register(CANCEL_BLOCK_UPDATE);
|
||||
NetWorkDataTypes(NetWorkCodec<?> codec) {
|
||||
this.codec = codec;
|
||||
}
|
||||
|
||||
private static void register(NetWorkDataTypes<?> type) {
|
||||
id2NetWorkDataTypes.put(type.id, type);
|
||||
public NetWorkCodec<?> codec() {
|
||||
return codec;
|
||||
}
|
||||
|
||||
private final int id;
|
||||
private final Function<FriendlyByteBuf, T> decoder;
|
||||
private final BiConsumer<FriendlyByteBuf, T> encoder;
|
||||
|
||||
public NetWorkDataTypes(int id, Function<FriendlyByteBuf, T> decoder, BiConsumer<FriendlyByteBuf, T> encoder) {
|
||||
this.id = id;
|
||||
this.decoder = decoder;
|
||||
this.encoder = encoder;
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> V decode(ByteBuf buf) {
|
||||
return (V) codec.decode(buf);
|
||||
}
|
||||
|
||||
public T decode(FriendlyByteBuf buf) {
|
||||
return decoder.apply(buf);
|
||||
}
|
||||
|
||||
public void encode(FriendlyByteBuf buf, T data) {
|
||||
encoder.accept(buf, data);
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void writeType(FriendlyByteBuf buf) {
|
||||
buf.writeVarInt(id);
|
||||
}
|
||||
|
||||
public static NetWorkDataTypes<?> readType(FriendlyByteBuf buf) {
|
||||
int id = buf.readVarInt();
|
||||
return id2NetWorkDataTypes.get(id);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "unused"})
|
||||
public <R> NetWorkDataTypes<R> as(Class<R> clazz) {
|
||||
return (NetWorkDataTypes<R>) this;
|
||||
@SuppressWarnings("unchecked")
|
||||
public <V> void encode(ByteBuf buf, V value) {
|
||||
((NetWorkCodec<V>) codec).encode(buf, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.network.payload;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.KeyUtils;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.FriendlyByteBuf;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
|
||||
public record UnknownPayload(Key channel, ByteBuf rawPayload) implements Payload{
|
||||
|
||||
public static UnknownPayload from(Object payload) {
|
||||
try {
|
||||
Object id = NetworkReflections.field$UnknownPayload$id.get(payload);
|
||||
ByteBuf data = (ByteBuf) NetworkReflections.field$UnknownPayload$data.get(payload);
|
||||
Key channel = KeyUtils.resourceLocationToKey(id);
|
||||
return new UnknownPayload(channel, data);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to create UnknownPayload", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FriendlyByteBuf toBuffer() {
|
||||
return new FriendlyByteBuf(rawPayload);
|
||||
}
|
||||
}
|
||||
@@ -3873,4 +3873,27 @@ public final class CoreReflections {
|
||||
throw new ReflectionInitException("Failed to initialize HashOps", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Class<?> clazz$SnowLayerBlock = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.BlockSnow",
|
||||
"world.level.block.SnowLayerBlock"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Field field$SnowLayerBlock$LAYERS = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(
|
||||
clazz$SnowLayerBlock, clazz$IntegerProperty, 0
|
||||
)
|
||||
);
|
||||
|
||||
public static final Object instance$SnowLayerBlock$LAYERS;
|
||||
|
||||
static {
|
||||
try {
|
||||
instance$SnowLayerBlock$LAYERS = field$SnowLayerBlock$LAYERS.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ReflectionInitException("Failed to initialize SnowLayerBlock$LAYERS", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public final class MBlocks {
|
||||
public static final Object SHORT_GRASS$defaultState;
|
||||
public static final Object SHULKER_BOX;
|
||||
public static final Object COMPOSTER;
|
||||
public static final Object SNOW;
|
||||
|
||||
private static Object getById(String id) {
|
||||
Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id);
|
||||
@@ -35,5 +36,6 @@ public final class MBlocks {
|
||||
SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS);
|
||||
SHULKER_BOX = getById("shulker_box");
|
||||
COMPOSTER = getById("composter");
|
||||
SNOW = getById("snow");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1248,7 +1248,9 @@ public final class NetworkReflections {
|
||||
);
|
||||
|
||||
public static final Constructor<?> constructor$ClientboundCustomPayloadPacket = requireNonNull(
|
||||
ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, 0)
|
||||
VersionHelper.isOrAbove1_20_2()
|
||||
? ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, clazz$CustomPacketPayload)
|
||||
: ReflectionUtils.getConstructor(clazz$ClientboundCustomPayloadPacket, CoreReflections.clazz$ResourceLocation, CoreReflections.clazz$FriendlyByteBuf)
|
||||
);
|
||||
|
||||
// 1.20.2+
|
||||
@@ -1621,4 +1623,27 @@ public final class NetworkReflections {
|
||||
throw new ReflectionInitException("Failed to initialize HashedStack$STREAM_CODEC", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 1.20.2~1.20.4
|
||||
public static final Class<?> clazz$UnknownPayload = MiscUtils.requireNonNullIf(
|
||||
ReflectionUtils.getClazz(
|
||||
BukkitReflectionUtils.assembleMCClass("network.protocol.common.ServerboundCustomPayloadPacket$UnknownPayload")
|
||||
),
|
||||
VersionHelper.isOrAbove1_20_2() && !VersionHelper.isOrAbove1_20_5()
|
||||
);
|
||||
|
||||
// 1.20.2~1.20.4
|
||||
public static final Field field$UnknownPayload$id = Optional.ofNullable(clazz$UnknownPayload)
|
||||
.map(it -> ReflectionUtils.getDeclaredField(it, CoreReflections.clazz$ResourceLocation, 0))
|
||||
.orElse(null);
|
||||
|
||||
// 1.20.2~1.20.4
|
||||
public static final Field field$UnknownPayload$data = Optional.ofNullable(clazz$UnknownPayload)
|
||||
.map(it -> ReflectionUtils.getDeclaredField(it, ByteBuf.class, 0))
|
||||
.orElse(null);
|
||||
|
||||
// 1.20.2~1.20.4
|
||||
public static final Constructor<?> constructor$UnknownPayload = Optional.ofNullable(clazz$UnknownPayload)
|
||||
.map(ReflectionUtils::getTheOnlyConstructor)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@@ -306,13 +306,20 @@ public class BukkitServerPlayer extends Player {
|
||||
public void sendCustomPayload(Key channel, byte[] data) {
|
||||
try {
|
||||
Object channelKey = KeyUtils.toResourceLocation(channel);
|
||||
Object dataPayload;
|
||||
if (DiscardedPayload.useNewMethod) {
|
||||
dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data);
|
||||
Object responsePacket;
|
||||
if (VersionHelper.isOrAbove1_20_2()) {
|
||||
Object dataPayload;
|
||||
if (NetworkReflections.clazz$UnknownPayload != null) {
|
||||
dataPayload = NetworkReflections.constructor$UnknownPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data));
|
||||
} else if (DiscardedPayload.useNewMethod) {
|
||||
dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, data);
|
||||
} else {
|
||||
dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data));
|
||||
}
|
||||
responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload);
|
||||
} else {
|
||||
dataPayload = NetworkReflections.constructor$DiscardedPayload.newInstance(channelKey, Unpooled.wrappedBuffer(data));
|
||||
responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(channelKey, FastNMS.INSTANCE.constructor$FriendlyByteBuf(Unpooled.wrappedBuffer(data)));
|
||||
}
|
||||
Object responsePacket = NetworkReflections.constructor$ClientboundCustomPayloadPacket.newInstance(dataPayload);
|
||||
this.sendPacket(responsePacket, true);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Failed to send custom payload to " + name(), e);
|
||||
|
||||
@@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.block.DelegatingBlockState;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -142,4 +143,10 @@ public class BlockStateUtils {
|
||||
Object blockOwner = getBlockOwner(state);
|
||||
return IGNITE_ODDS.getOrDefault(blockOwner, 0) > 0;
|
||||
}
|
||||
|
||||
public static Object getBlockState(Block block) {
|
||||
Object worldServer = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld());
|
||||
Object blockPos = LocationUtils.toBlockPos(block.getX(), block.getY(), block.getZ());
|
||||
return FastNMS.INSTANCE.method$BlockGetter$getBlockState(worldServer, blockPos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ package net.momirealms.craftengine.bukkit.world;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
@@ -21,11 +24,15 @@ public class BukkitBlockInWorld implements BlockInWorld {
|
||||
|
||||
@Override
|
||||
public boolean canBeReplaced(BlockPlaceContext context) {
|
||||
ImmutableBlockState customState = CraftEngineBlocks.getCustomBlockState(this.block);
|
||||
Object state = BlockStateUtils.getBlockState(this.block);
|
||||
ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null);
|
||||
if (customState != null && !customState.isEmpty()) {
|
||||
return customState.behavior().canBeReplaced(context, customState);
|
||||
}
|
||||
return this.block.isReplaceable();
|
||||
if (BlockStateUtils.getBlockOwner(state) == MBlocks.SNOW) {
|
||||
return (int) FastNMS.INSTANCE.method$StateHolder$getValue(state, CoreReflections.instance$SnowLayerBlock$LAYERS) == 1;
|
||||
}
|
||||
return BlockStateUtils.isReplaceable(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -88,6 +88,11 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CEWorld[] getWorlds() {
|
||||
return this.worldArray;
|
||||
}
|
||||
|
||||
private void resetWorldArray() {
|
||||
this.worldArray = this.worlds.values().toArray(new CEWorld[0]);
|
||||
}
|
||||
@@ -218,7 +223,6 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
this.lastVisitedUUID = null;
|
||||
}
|
||||
this.resetWorldArray();
|
||||
|
||||
} finally {
|
||||
this.worldMapLock.writeLock().unlock();
|
||||
}
|
||||
@@ -328,74 +332,76 @@ public class BukkitWorldManager implements WorldManager, Listener {
|
||||
Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer);
|
||||
Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ());
|
||||
Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk);
|
||||
for (int i = 0; i < ceSections.length; i++) {
|
||||
CESection ceSection = ceSections[i];
|
||||
Object section = sections[i];
|
||||
if (Config.syncCustomBlocks()) {
|
||||
Object statesContainer = FastNMS.INSTANCE.field$LevelChunkSection$states(section);
|
||||
Object data = CoreReflections.varHandle$PalettedContainer$data.get(statesContainer);
|
||||
Object palette = CoreReflections.field$PalettedContainer$Data$palette.get(data);
|
||||
boolean requiresSync = false;
|
||||
if (CoreReflections.clazz$SingleValuePalette.isInstance(palette)) {
|
||||
Object onlyBlockState = CoreReflections.field$SingleValuePalette$value.get(palette);
|
||||
if (BlockStateUtils.isCustomBlock(onlyBlockState)) {
|
||||
synchronized (sections) {
|
||||
for (int i = 0; i < ceSections.length; i++) {
|
||||
CESection ceSection = ceSections[i];
|
||||
Object section = sections[i];
|
||||
if (Config.syncCustomBlocks()) {
|
||||
Object statesContainer = FastNMS.INSTANCE.field$LevelChunkSection$states(section);
|
||||
Object data = CoreReflections.varHandle$PalettedContainer$data.get(statesContainer);
|
||||
Object palette = CoreReflections.field$PalettedContainer$Data$palette.get(data);
|
||||
boolean requiresSync = false;
|
||||
if (CoreReflections.clazz$SingleValuePalette.isInstance(palette)) {
|
||||
Object onlyBlockState = CoreReflections.field$SingleValuePalette$value.get(palette);
|
||||
if (BlockStateUtils.isCustomBlock(onlyBlockState)) {
|
||||
requiresSync = true;
|
||||
}
|
||||
} else if (CoreReflections.clazz$LinearPalette.isInstance(palette)) {
|
||||
Object[] blockStates = (Object[]) CoreReflections.field$LinearPalette$values.get(palette);
|
||||
for (Object blockState : blockStates) {
|
||||
if (blockState != null) {
|
||||
if (BlockStateUtils.isCustomBlock(blockState)) {
|
||||
requiresSync = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (CoreReflections.clazz$HashMapPalette.isInstance(palette)) {
|
||||
Object biMap = CoreReflections.field$HashMapPalette$values.get(palette);
|
||||
Object[] blockStates = (Object[]) CoreReflections.field$CrudeIncrementalIntIdentityHashBiMap$keys.get(biMap);
|
||||
for (Object blockState : blockStates) {
|
||||
if (blockState != null) {
|
||||
if (BlockStateUtils.isCustomBlock(blockState)) {
|
||||
requiresSync = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
requiresSync = true;
|
||||
}
|
||||
} else if (CoreReflections.clazz$LinearPalette.isInstance(palette)) {
|
||||
Object[] blockStates = (Object[]) CoreReflections.field$LinearPalette$values.get(palette);
|
||||
for (Object blockState : blockStates) {
|
||||
if (blockState != null) {
|
||||
if (BlockStateUtils.isCustomBlock(blockState)) {
|
||||
requiresSync = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (CoreReflections.clazz$HashMapPalette.isInstance(palette)) {
|
||||
Object biMap = CoreReflections.field$HashMapPalette$values.get(palette);
|
||||
Object[] blockStates = (Object[]) CoreReflections.field$CrudeIncrementalIntIdentityHashBiMap$keys.get(biMap);
|
||||
for (Object blockState : blockStates) {
|
||||
if (blockState != null) {
|
||||
if (BlockStateUtils.isCustomBlock(blockState)) {
|
||||
requiresSync = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
requiresSync = true;
|
||||
}
|
||||
if (requiresSync) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
Object mcState = FastNMS.INSTANCE.method$LevelChunkSection$getBlockState(section, x, y, z);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(mcState);
|
||||
if (optionalCustomState.isPresent()) {
|
||||
ceSection.setBlockState(x, y, z, optionalCustomState.get());
|
||||
if (requiresSync) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
Object mcState = FastNMS.INSTANCE.method$LevelChunkSection$getBlockState(section, x, y, z);
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(mcState);
|
||||
if (optionalCustomState.isPresent()) {
|
||||
ceSection.setBlockState(x, y, z, optionalCustomState.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Config.restoreCustomBlocks()) {
|
||||
if (!ceSection.statesContainer().isEmpty()) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
ImmutableBlockState customState = ceSection.getBlockState(x, y, z);
|
||||
if (!customState.isEmpty() && customState.customBlockState() != null) {
|
||||
FastNMS.INSTANCE.method$LevelChunkSection$setBlockState(section, x, y, z, customState.customBlockState().handle(), false);
|
||||
if (Config.restoreCustomBlocks()) {
|
||||
if (!ceSection.statesContainer().isEmpty()) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
ImmutableBlockState customState = ceSection.getBlockState(x, y, z);
|
||||
if (!customState.isEmpty() && customState.customBlockState() != null) {
|
||||
FastNMS.INSTANCE.method$LevelChunkSection$setBlockState(section, x, y, z, customState.customBlockState().handle(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int finalI = i;
|
||||
WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z),
|
||||
(injected) -> sections[finalI] = injected);
|
||||
}
|
||||
int finalI = i;
|
||||
WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z),
|
||||
(injected) -> sections[finalI] = injected);
|
||||
}
|
||||
if (Config.enableRecipeSystem()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -84,8 +84,6 @@ resource-pack:
|
||||
ip: "localhost"
|
||||
port: 8163
|
||||
protocol: "http"
|
||||
# The optional URL must be complete and include a trailing slash / at the end.
|
||||
#url: "http://localhost:8163/"
|
||||
deny-non-minecraft-request: true
|
||||
one-time-token: true
|
||||
rate-limit:
|
||||
@@ -380,9 +378,9 @@ chunk-system:
|
||||
# Settings for injection
|
||||
injection:
|
||||
# Requires a restart to apply
|
||||
# SECTION: Inject the LevelChunkSection (Faster & Experimental) since 0.0.53
|
||||
# SECTION: Inject the LevelChunkSection
|
||||
# PALETTE: Inject the PalettedContainer
|
||||
target: PALETTE
|
||||
target: SECTION
|
||||
# Enables faster injection method
|
||||
# Note: May not work with certain server forks that alter chunk class structure (In most cases it won't conflict)
|
||||
use-fast-method: false
|
||||
|
||||
@@ -393,6 +393,7 @@ warning.config.function.potion_effect.missing_potion_effect: "<yellow>Issue foun
|
||||
warning.config.function.set_cooldown.missing_time: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'time' argument for 'set_cooldown' function.</yellow>"
|
||||
warning.config.function.set_cooldown.missing_id: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'id' argument for 'set_cooldown' function.</yellow>"
|
||||
warning.config.function.remove_cooldown.missing_id: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'id' argument for 'remove_cooldown' function.</yellow>"
|
||||
warning.config.function.mythic_mobs_skill.missing_skill: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'skill' argument for 'mythic_mobs_skill' 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>"
|
||||
|
||||
@@ -391,6 +391,7 @@ warning.config.function.potion_effect.missing_potion_effect: "<yellow>在文件
|
||||
warning.config.function.set_cooldown.missing_time: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'set_cooldown' 函数必需的 'time' 参数</yellow>"
|
||||
warning.config.function.set_cooldown.missing_id: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'set_cooldown' 函数必需的 'id' 参数</yellow>"
|
||||
warning.config.function.remove_cooldown.missing_id: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'remove_cooldown' 函数必需的 'id' 参数</yellow>"
|
||||
warning.config.function.mythic_mobs_skill.missing_skill: "<yellow>在文件 <arg:0> 中发现问题 - 配置项 '<arg:1>' 缺少 'mythic_mobs_skill' 函数必需的 'skill' 参数</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>"
|
||||
|
||||
@@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.util.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class Properties {
|
||||
public final class Properties {
|
||||
public static final Key BOOLEAN = Key.of("craftengine:boolean");
|
||||
public static final Key INT = Key.of("craftengine:int");
|
||||
public static final Key STRING = Key.of("craftengine:string");
|
||||
|
||||
@@ -9,11 +9,14 @@ import net.momirealms.craftengine.core.item.data.Enchantment;
|
||||
import net.momirealms.craftengine.core.item.data.JukeboxPlayable;
|
||||
import net.momirealms.craftengine.core.item.equipment.*;
|
||||
import net.momirealms.craftengine.core.item.modifier.*;
|
||||
import net.momirealms.craftengine.core.item.modifier.lore.DynamicLoreModifier;
|
||||
import net.momirealms.craftengine.core.item.modifier.lore.LoreModifier;
|
||||
import net.momirealms.craftengine.core.item.setting.EquipmentData;
|
||||
import net.momirealms.craftengine.core.pack.AbstractPackManager;
|
||||
import net.momirealms.craftengine.core.pack.LoadingSequence;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.pack.ResourceLocation;
|
||||
import net.momirealms.craftengine.core.pack.host.ResourcePackHosts;
|
||||
import net.momirealms.craftengine.core.pack.model.*;
|
||||
import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator;
|
||||
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
|
||||
@@ -534,15 +537,12 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
|
||||
return new CustomNameModifier<>(name);
|
||||
}, "custom-name", "item-name", "display-name");
|
||||
}
|
||||
registerDataType(LoreModifier::createLoreModifier, "lore", "display-lore", "description");
|
||||
registerDataType((obj) -> {
|
||||
List<String> lore = MiscUtils.getAsStringList(obj);
|
||||
return new LoreModifier<>(lore);
|
||||
}, "lore", "display-lore", "description");
|
||||
registerDataType((obj) -> {
|
||||
Map<String, List<String>> dynamicLore = new LinkedHashMap<>();
|
||||
Map<String, LoreModifier<I>> dynamicLore = new LinkedHashMap<>();
|
||||
if (obj instanceof Map<?, ?> map) {
|
||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
dynamicLore.put(entry.getKey().toString(), MiscUtils.getAsStringList(entry.getValue()));
|
||||
dynamicLore.put(entry.getKey().toString(), LoreModifier.createLoreModifier(entry.getValue()));
|
||||
}
|
||||
}
|
||||
return new DynamicLoreModifier<>(dynamicLore);
|
||||
|
||||
@@ -16,7 +16,6 @@ import net.momirealms.sparrow.nbt.Tag;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class ItemFactory<W extends ItemWrapper<I>, I> {
|
||||
protected final CraftEngine plugin;
|
||||
@@ -112,7 +111,7 @@ public abstract class ItemFactory<W extends ItemWrapper<I>, I> {
|
||||
|
||||
protected void loreComponent(W item, List<Component> component) {
|
||||
if (component != null && !component.isEmpty()) {
|
||||
loreJson(item, component.stream().map(AdventureHelper::componentToJson).collect(Collectors.toList()));
|
||||
loreJson(item, component.stream().map(AdventureHelper::componentToJson).toList());
|
||||
} else {
|
||||
loreJson(item, null);
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package net.momirealms.craftengine.core.item.modifier;
|
||||
|
||||
import net.momirealms.craftengine.core.item.ComponentKeys;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import net.momirealms.craftengine.core.item.NetworkItemHandler;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.util.AdventureHelper;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LoreModifier<I> implements ItemDataModifier<I> {
|
||||
private final List<String> argument;
|
||||
|
||||
public LoreModifier(List<String> argument) {
|
||||
if (Config.addNonItalicTag()) {
|
||||
List<String> processed = new ArrayList<>(argument.size());
|
||||
for (String arg : argument) {
|
||||
if (arg.startsWith("<!i>")) {
|
||||
processed.add(arg);
|
||||
} else {
|
||||
processed.add("<!i>" + arg);
|
||||
}
|
||||
}
|
||||
this.argument = processed;
|
||||
} else {
|
||||
this.argument = argument;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "lore";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<I> apply(Item<I> item, ItemBuildContext context) {
|
||||
item.loreComponent(this.argument.stream().map(it -> AdventureHelper.miniMessage().deserialize(it, context.tagResolvers())).toList());
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
|
||||
if (VersionHelper.isOrAbove1_20_5()) {
|
||||
Tag previous = item.getSparrowNBTComponent(ComponentKeys.LORE);
|
||||
if (previous != null) {
|
||||
networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
|
||||
} else {
|
||||
networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
|
||||
}
|
||||
} else {
|
||||
Tag previous = item.getTag("display", "Lore");
|
||||
if (previous != null) {
|
||||
networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
|
||||
} else {
|
||||
networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,29 @@
|
||||
package net.momirealms.craftengine.core.item.modifier;
|
||||
package net.momirealms.craftengine.core.item.modifier.lore;
|
||||
|
||||
import net.momirealms.craftengine.core.item.ComponentKeys;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import net.momirealms.craftengine.core.item.NetworkItemHandler;
|
||||
import net.momirealms.craftengine.core.util.AdventureHelper;
|
||||
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DynamicLoreModifier<I> implements ItemDataModifier<I> {
|
||||
public final class DynamicLoreModifier<I> implements ItemDataModifier<I> {
|
||||
public static final String CONTEXT_TAG_KEY = "craftengine:display_context";
|
||||
private final Map<String, List<String>> displayContexts;
|
||||
private final String defaultContext;
|
||||
private final Map<String, LoreModifier<I>> displayContexts;
|
||||
private final LoreModifier<I> defaultModifier;
|
||||
|
||||
public DynamicLoreModifier(Map<String, List<String>> displayContexts) {
|
||||
this.defaultContext = displayContexts.keySet().iterator().next();
|
||||
public DynamicLoreModifier(Map<String, LoreModifier<I>> displayContexts) {
|
||||
this.displayContexts = displayContexts;
|
||||
this.defaultModifier = displayContexts.values().iterator().next();
|
||||
}
|
||||
|
||||
public Map<String, List<String>> displayContexts() {
|
||||
return Collections.unmodifiableMap(this.displayContexts);
|
||||
public Map<String, LoreModifier<I>> displayContexts() {
|
||||
return displayContexts;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -35,13 +33,12 @@ public class DynamicLoreModifier<I> implements ItemDataModifier<I> {
|
||||
|
||||
@Override
|
||||
public Item<I> apply(Item<I> item, ItemBuildContext context) {
|
||||
String displayContext = Optional.ofNullable(item.getJavaTag(CONTEXT_TAG_KEY)).orElse(this.defaultContext).toString();
|
||||
List<String> lore = this.displayContexts.get(displayContext);
|
||||
String displayContext = Optional.ofNullable(item.getJavaTag(CONTEXT_TAG_KEY)).orElse(this.defaultModifier).toString();
|
||||
LoreModifier<I> lore = this.displayContexts.get(displayContext);
|
||||
if (lore == null) {
|
||||
lore = this.displayContexts.get(this.defaultContext);
|
||||
lore = this.defaultModifier;
|
||||
}
|
||||
item.loreComponent(lore.stream().map(it -> AdventureHelper.miniMessage().deserialize(it, context.tagResolvers())).toList());
|
||||
return item;
|
||||
return lore.apply(item, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,39 @@
|
||||
package net.momirealms.craftengine.core.item.modifier.lore;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import net.momirealms.craftengine.core.util.AdventureHelper;
|
||||
import net.momirealms.craftengine.core.util.TriFunction;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
// todo 可以考虑未来添加条件系统
|
||||
public record LoreModification(Operation operation, boolean split, String[] content) {
|
||||
|
||||
public Stream<Component> apply(Stream<Component> lore, ItemBuildContext context) {
|
||||
return this.operation.function.apply(lore, context, this);
|
||||
}
|
||||
|
||||
public Stream<Component> parseAsStream(ItemBuildContext context) {
|
||||
Stream<Component> parsed = Arrays.stream(this.content).map(string -> AdventureHelper.miniMessage().deserialize(string, context.tagResolvers()));
|
||||
return this.split ? parsed.map(AdventureHelper::splitLines).flatMap(List::stream) : parsed;
|
||||
}
|
||||
|
||||
public List<Component> parseAsList(ItemBuildContext context) {
|
||||
return this.parseAsStream(context).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public enum Operation {
|
||||
APPEND((s, c, modification) -> Stream.concat(s, modification.parseAsStream(c))),
|
||||
PREPEND((s, c, modification) -> Stream.concat(modification.parseAsStream(c), s));
|
||||
|
||||
private final TriFunction<Stream<Component>, ItemBuildContext, LoreModification, Stream<Component>> function;
|
||||
|
||||
Operation(TriFunction<Stream<Component>, ItemBuildContext, LoreModification, Stream<Component>> function) {
|
||||
this.function = function;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.momirealms.craftengine.core.item.modifier.lore;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record LoreModificationHolder(LoreModification modification, int priority) implements Comparable<LoreModificationHolder> {
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull LoreModificationHolder o) {
|
||||
return Integer.compare(priority, o.priority);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package net.momirealms.craftengine.core.item.modifier.lore;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.core.item.ComponentKeys;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemBuildContext;
|
||||
import net.momirealms.craftengine.core.item.NetworkItemHandler;
|
||||
import net.momirealms.craftengine.core.item.modifier.ItemDataModifier;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public sealed interface LoreModifier<I> extends ItemDataModifier<I>
|
||||
permits LoreModifier.EmptyLoreModifier, LoreModifier.CompositeLoreModifier, LoreModifier.DoubleLoreModifier, LoreModifier.SingleLoreModifier {
|
||||
|
||||
@Override
|
||||
default String name() {
|
||||
return "lore";
|
||||
}
|
||||
|
||||
@Override
|
||||
default Item<I> prepareNetworkItem(Item<I> item, ItemBuildContext context, CompoundTag networkData) {
|
||||
if (VersionHelper.isOrAbove1_20_5()) {
|
||||
Tag previous = item.getSparrowNBTComponent(ComponentKeys.LORE);
|
||||
if (previous != null) networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
|
||||
else networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
|
||||
} else {
|
||||
Tag previous = item.getTag("display", "Lore");
|
||||
if (previous != null) networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous));
|
||||
else networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE));
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
static <I> LoreModifier<I> createLoreModifier(Object arg) {
|
||||
List<Object> rawLoreData = MiscUtils.getAsList(arg, Object.class);
|
||||
String[] rawLore = new String[rawLoreData.size()];
|
||||
label_all_string_check: {
|
||||
for (int i = 0; i < rawLore.length; i++) {
|
||||
Object o = rawLoreData.get(i);
|
||||
if (o instanceof Map<?,?>) {
|
||||
break label_all_string_check;
|
||||
} else {
|
||||
rawLore[i] = o.toString();
|
||||
}
|
||||
}
|
||||
return new SingleLoreModifier<>(new LoreModification(LoreModification.Operation.APPEND, false, rawLore));
|
||||
}
|
||||
|
||||
List<LoreModificationHolder> modifications = new ArrayList<>(rawLoreData.size() + 1);
|
||||
int lastPriority = 0;
|
||||
for (Object o : rawLoreData) {
|
||||
if (o instanceof Map<?,?> complexLore) {
|
||||
String[] content = MiscUtils.getAsStringArray(complexLore.get("content"));
|
||||
LoreModification.Operation operation = ResourceConfigUtils.getAsEnum(Optional.ofNullable(complexLore.get("operation")).map(String::valueOf).orElse(null), LoreModification.Operation.class, LoreModification.Operation.APPEND);
|
||||
lastPriority = Optional.ofNullable(complexLore.get("priority")).map(it -> ResourceConfigUtils.getAsInt(it, "priority")).orElse(lastPriority);
|
||||
boolean split = ResourceConfigUtils.getAsBoolean(complexLore.get("split-lines"), "split-lines");
|
||||
modifications.add(new LoreModificationHolder(new LoreModification(operation, split, content), lastPriority));
|
||||
}
|
||||
}
|
||||
modifications.sort(LoreModificationHolder::compareTo);
|
||||
return switch (modifications.size()) {
|
||||
case 0 -> new EmptyLoreModifier<>();
|
||||
case 1 -> new SingleLoreModifier<>(modifications.get(0).modification());
|
||||
case 2 -> new DoubleLoreModifier<>(modifications.get(0).modification(), modifications.get(1).modification());
|
||||
default -> new CompositeLoreModifier<>(modifications.stream().map(LoreModificationHolder::modification).toArray(LoreModification[]::new));
|
||||
};
|
||||
}
|
||||
|
||||
non-sealed class EmptyLoreModifier<I> implements LoreModifier<I> {
|
||||
|
||||
@Override
|
||||
public Item<I> apply(Item<I> item, ItemBuildContext context) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
non-sealed class SingleLoreModifier<I> implements LoreModifier<I> {
|
||||
private final LoreModification modification;
|
||||
|
||||
public SingleLoreModifier(LoreModification modification) {
|
||||
this.modification = modification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<I> apply(Item<I> item, ItemBuildContext context) {
|
||||
item.loreComponent(this.modification.parseAsList(context));
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
non-sealed class DoubleLoreModifier<I> implements LoreModifier<I> {
|
||||
private final LoreModification modification1;
|
||||
private final LoreModification modification2;
|
||||
|
||||
public DoubleLoreModifier(LoreModification m1, LoreModification m2) {
|
||||
this.modification1 = m1;
|
||||
this.modification2 = m2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<I> apply(Item<I> item, ItemBuildContext context) {
|
||||
item.loreComponent(this.modification2.apply(this.modification1.apply(Stream.empty(), context), context).toList());
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
non-sealed class CompositeLoreModifier<I> implements LoreModifier<I> {
|
||||
private final LoreModification[] modifications;
|
||||
|
||||
public CompositeLoreModifier(LoreModification... modifications) {
|
||||
this.modifications = modifications;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<I> apply(Item<I> item, ItemBuildContext context) {
|
||||
item.loreComponent(Arrays.stream(this.modifications).reduce(Stream.<Component>empty(), (stream, modification) -> modification.apply(stream, context), Stream::concat).toList());
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public final class ResourceLocation {
|
||||
}
|
||||
|
||||
public static boolean isValidNamespace(String namespace) {
|
||||
for(int i = 0; i < namespace.length(); ++i) {
|
||||
for (int i = 0; i < namespace.length(); ++i) {
|
||||
if (!validNamespaceChar(namespace.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -34,4 +34,6 @@ public interface CompatibilityManager {
|
||||
String parse(Player player1, Player player2, String text);
|
||||
|
||||
int getPlayerProtocolVersion(UUID uuid);
|
||||
|
||||
void executeMMSkill(String skill, float power, Player player);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public class EventFunctions {
|
||||
register(CommonFunctions.LEVELER_EXP, new LevelerExpFunction.FactoryImpl<>(EventConditions::fromMap));
|
||||
register(CommonFunctions.SET_COOLDOWN, new SetCooldownFunction.FactoryImpl<>(EventConditions::fromMap));
|
||||
register(CommonFunctions.REMOVE_COOLDOWN, new RemoveCooldownFunction.FactoryImpl<>(EventConditions::fromMap));
|
||||
register(CommonFunctions.MYTHIC_MOBS_SKILL, new MythicMobsSkillFunction.FactoryImpl<>(EventConditions::fromMap));
|
||||
}
|
||||
|
||||
public static void register(Key key, FunctionFactory<PlayerOptionalContext> factory) {
|
||||
|
||||
@@ -27,4 +27,5 @@ public final class CommonFunctions {
|
||||
public static final Key DROP_LOOT = Key.of("craftengine:drop_loot");
|
||||
public static final Key SWING_HAND = Key.of("craftengine:swing_hand");
|
||||
public static final Key LEVELER_EXP = Key.of("craftengine:leveler_exp");
|
||||
public static final Key MYTHIC_MOBS_SKILL = Key.of("craftengine:mythic_mobs_skill");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package net.momirealms.craftengine.core.plugin.context.function;
|
||||
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
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 net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MythicMobsSkillFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
|
||||
private final String skill;
|
||||
private final float power;
|
||||
|
||||
public MythicMobsSkillFunction(String skill, float power, List<Condition<CTX>> predicates) {
|
||||
super(predicates);
|
||||
this.skill = skill;
|
||||
this.power = power;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runInternal(CTX ctx) {
|
||||
ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> {
|
||||
CraftEngine.instance().compatibilityManager().executeMMSkill(this.skill, this.power, it);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Key type() {
|
||||
return CommonFunctions.MYTHIC_MOBS_SKILL;
|
||||
}
|
||||
|
||||
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> args) {
|
||||
String skill = ResourceConfigUtils.requireNonEmptyStringOrThrow(args.get("skill"), "warning.config.function.mythic_mobs_skill.missing_skill");
|
||||
float power = ResourceConfigUtils.getAsFloat(args.getOrDefault("power", 1.0), "power");
|
||||
return new MythicMobsSkillFunction<>(skill, power, getPredicates(args));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,9 @@ import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentIteratorType;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TextReplacementConfig;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
@@ -15,7 +17,7 @@ import net.momirealms.sparrow.nbt.Tag;
|
||||
import net.momirealms.sparrow.nbt.adventure.NBTComponentSerializer;
|
||||
import net.momirealms.sparrow.nbt.adventure.NBTSerializerOptions;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -29,6 +31,21 @@ public class AdventureHelper {
|
||||
private final MiniMessage miniMessageCustom;
|
||||
private final GsonComponentSerializer gsonComponentSerializer;
|
||||
private final NBTComponentSerializer nbtComponentSerializer;
|
||||
private static final TextReplacementConfig REPLACE_LF = TextReplacementConfig.builder().matchLiteral("\n").replacement(Component.newline()).build();
|
||||
/**
|
||||
* This iterator slices a component into individual parts that
|
||||
* <ul>
|
||||
* <li>Can be used individually without style loss</li>
|
||||
* <li>Can be concatenated to form the original component, given that children are dropped</li>
|
||||
* </ul>
|
||||
* Any {@link net.kyori.adventure.text.ComponentIteratorFlag}s are ignored.
|
||||
*/
|
||||
private static final ComponentIteratorType SLICER = (component, deque, flags) -> {
|
||||
final List<Component> children = component.children();
|
||||
for (int i = children.size() - 1; i >= 0; i--) {
|
||||
deque.addFirst(children.get(i).applyFallbackStyle(component.style()));
|
||||
}
|
||||
};
|
||||
|
||||
private AdventureHelper() {
|
||||
this.miniMessage = MiniMessage.builder().build();
|
||||
@@ -209,6 +226,24 @@ public class AdventureHelper {
|
||||
return getNBT().deserialize(tag);
|
||||
}
|
||||
|
||||
public static List<Component> splitLines(Component component) {
|
||||
List<Component> result = new ArrayList<>(1);
|
||||
Component line = Component.empty();
|
||||
for (Iterator<Component> it = component.replaceText(REPLACE_LF).iterator(SLICER); it.hasNext(); ) {
|
||||
Component child = it.next().children(Collections.emptyList());
|
||||
if (child instanceof TextComponent text && text.content().equals(Component.newline().content())) {
|
||||
result.add(line.compact());
|
||||
line = Component.empty();
|
||||
} else {
|
||||
line = line.append(child);
|
||||
}
|
||||
}
|
||||
if (Component.IS_NOT_EMPTY.test(line)) {
|
||||
result.add(line.compact());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a character is a legacy color code.
|
||||
*
|
||||
|
||||
@@ -51,6 +51,20 @@ public class MiscUtils {
|
||||
return list;
|
||||
}
|
||||
|
||||
public static String[] getAsStringArray(Object o) {
|
||||
if (o instanceof List<?> list) {
|
||||
String[] array = new String[list.size()];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = list.get(i).toString();
|
||||
}
|
||||
return array;
|
||||
} else if (o != null) {
|
||||
return new String[]{o.toString()};
|
||||
} else {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> List<T> getAsList(Object o, Class<T> clazz) {
|
||||
if (o instanceof List<?> list) {
|
||||
|
||||
@@ -5,10 +5,7 @@ import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -20,6 +17,17 @@ public final class ResourceConfigUtils {
|
||||
return raw != null ? function.apply(raw) : defaultValue;
|
||||
}
|
||||
|
||||
public static <E extends Enum<E>> E getAsEnum(Object o, Class<E> clazz, E defaultValue) {
|
||||
if (o == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
try {
|
||||
return Enum.valueOf(clazz, o.toString().toUpperCase(Locale.ENGLISH));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T requireNonNullOrThrow(T obj, String node) {
|
||||
if (obj == null)
|
||||
throw new LocalizedResourceConfigException(node);
|
||||
|
||||
@@ -13,6 +13,8 @@ public interface WorldManager extends Manageable {
|
||||
|
||||
CEWorld getWorld(UUID uuid);
|
||||
|
||||
CEWorld[] getWorlds();
|
||||
|
||||
void loadWorld(World world);
|
||||
|
||||
void loadWorld(CEWorld world);
|
||||
|
||||
@@ -113,7 +113,7 @@ public class CEChunk {
|
||||
return this.sections[index];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
public CESection sectionById(int sectionId) {
|
||||
return this.sections[sectionIndex(sectionId)];
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ org.gradle.jvmargs=-Xmx1G
|
||||
|
||||
# Project settings
|
||||
# Rule: [major update].[feature update].[bug fix]
|
||||
project_version=0.0.60.3
|
||||
config_version=42
|
||||
project_version=0.0.60.5
|
||||
config_version=43
|
||||
lang_version=22
|
||||
project_group=net.momirealms
|
||||
latest_supported_version=1.21.8
|
||||
@@ -50,7 +50,7 @@ byte_buddy_version=1.17.5
|
||||
ahocorasick_version=0.6.3
|
||||
snake_yaml_version=2.4
|
||||
anti_grief_version=0.18
|
||||
nms_helper_version=1.0.36
|
||||
nms_helper_version=1.0.37
|
||||
evalex_version=3.5.0
|
||||
reactive_streams_version=1.0.4
|
||||
amazon_awssdk_version=2.31.23
|
||||
|
||||
Reference in New Issue
Block a user