mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-26 10:29:20 +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")
|
||||
|
||||
Reference in New Issue
Block a user