From 4ddcb53ea07364b902350544d5d5d625f2c2f26c Mon Sep 17 00:00:00 2001 From: 3944Realms Date: Mon, 23 Mar 2026 02:00:21 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=B7=B2=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=E7=9A=84NPC=E5=9C=A8=E7=99=BB=E9=99=86=E5=90=8E?= =?UTF-8?q?=E7=9C=8B=E4=B8=8D=E8=A7=81=E3=80=81=E7=8A=B6=E6=80=81=E4=B8=8D?= =?UTF-8?q?=E5=AF=B9=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/ClientNPCManager.java | 353 ++++++++++++++++++ .../content/animation/IEDGAnimation.java | 17 +- .../blockentity/BaseSeatBlockEntity.java | 4 +- .../content/entity/SeatEntity.java | 3 +- .../content/entity/npc/NPCPlayerList.java | 10 +- .../content/entity/npc/NPCServerPlayer.java | 1 + .../capability/DungeonDataSyncManager.java | 22 +- .../core/event/ClientHandler.java | 15 + .../core/event/CommonHandler.java | 7 +- .../core/network/EDGNetworkHandler.java | 11 +- .../network/toClient/NPCInfoUpdatePacket.java | 2 + .../RefreshPlayerAnimationPacket.java | 48 +++ .../core/service/SeatService.java | 48 ++- .../datagen/EDGRegistries.java | 16 + .../minecraft/MixinClientPacketListener.java | 225 ++++++++++- .../mixin/minecraft/MixinGameTestServer.java | 2 +- .../minecraft/MixinItemInHandRenderer.java | 16 + .../mixin/minecraft/MixinServerPlayer.java | 3 +- .../util/IEDGClientPacketListener.java | 28 ++ 19 files changed, 783 insertions(+), 48 deletions(-) create mode 100644 src/main/java/top/r3944realms/eroticdungeongame/client/ClientNPCManager.java create mode 100644 src/main/java/top/r3944realms/eroticdungeongame/core/network/toServer/RefreshPlayerAnimationPacket.java diff --git a/src/main/java/top/r3944realms/eroticdungeongame/client/ClientNPCManager.java b/src/main/java/top/r3944realms/eroticdungeongame/client/ClientNPCManager.java new file mode 100644 index 00000000..5f00394f --- /dev/null +++ b/src/main/java/top/r3944realms/eroticdungeongame/client/ClientNPCManager.java @@ -0,0 +1,353 @@ +/* + * Copyright 2025-2026 R3944Realms + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.r3944realms.eroticdungeongame.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.client.multiplayer.PlayerInfo; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.*; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.eroticdungeongame.EroticDungeon; +import top.r3944realms.eroticdungeongame.content.entity.npc.INPCPlayer; +import top.r3944realms.eroticdungeongame.util.IEDGClientPacketListener; +import top.r3944realms.superleadrope.util.riding.RidingFinder; + +import java.util.*; + +@SuppressWarnings("ConstantValue") +public class ClientNPCManager { + + // 缓存待处理的 NPC 玩家包 + private static final Set pendingNPCs = new HashSet<>(); + + // 缓存待处理的实体包(坐骑、宠物等) +// private static final Set pendingEntities = new HashSet<>(); + + // 缓存待处理的实体数据包 + private static final Set pendingEntityData = new HashSet<>(); + + // 缓存待处理的属性包 + private static final Set pendingAttributes = new HashSet<>(); + + // 缓存待处理的装备包 + private static final Set pendingEquipment = new HashSet<>(); + + // 缓存待处理的乘客包 + private static final Set pendingPassengers = new HashSet<>(); + + // 缓存待处理的链接包(拴绳) + private static final Set pendingLinks = new HashSet<>(); + + // 缓存待处理的头部旋转包 + private static final Set pendingHeadRotations = new HashSet<>(); + + // 缓存待处理的移动包 + private static final Set> pendingMovements = new HashSet<>(); + + // 缓存待处理的运动包 + private static final Set pendingMotions = new HashSet<>(); + + public static void reset() { + pendingNPCs.clear(); +// pendingEntities.clear(); + pendingEntityData.clear(); + pendingAttributes.clear(); + pendingEquipment.clear(); + pendingPassengers.clear(); + pendingLinks.clear(); + pendingHeadRotations.clear(); + pendingMovements.clear(); + pendingMotions.clear(); + EroticDungeon.LOGGER.debug("ClientNPCManager reset"); + } + + // ========== 缓存方法 ========== + + /** + * 缓存 NPC 玩家包 + */ + public static void cacheNPCIfNeeded(ClientboundAddPlayerPacket packet) { + ClientPacketListener connection = Minecraft.getInstance().getConnection(); + if (connection instanceof IEDGClientPacketListener iedgListener) { + UUID playerId = packet.getPlayerId(); + PlayerInfo info = iedgListener.getNPCPlayerInfoMap().get(playerId); + if (info == null && !iedgListener.getNPCPlayerInfoMap().containsKey(playerId)) { + pendingNPCs.add(packet); + EroticDungeon.LOGGER.debug("Cached AddPlayer packet for NPC: {} (entityId: {})", + playerId, packet.getEntityId()); + } + } + } + +// /** +// * 缓存实体包 +// */ +// public static void cacheEntityIfNeeded(@NotNull ClientboundAddEntityPacket packet) { +// pendingEntities.add(packet); +// EroticDungeon.LOGGER.debug("Cached AddEntity packet {}", packet); +// } + + /** + * 缓存实体数据包 + */ + public static void cacheEntityDataIfNeeded(@NotNull ClientboundSetEntityDataPacket packet) { + pendingEntityData.add(packet); + EroticDungeon.LOGGER.debug("Cached SetEntityData packet {}, ID: {}", packet, packet.id()); + } + + /** + * 缓存属性包 + */ + public static void cacheAttributesIfNeeded(@NotNull ClientboundUpdateAttributesPacket packet) { + pendingAttributes.add(packet); + EroticDungeon.LOGGER.debug("Cached UpdateAttributes packet {}, ID: {}", packet, packet.getEntityId()); + } + + /** + * 缓存装备包 + */ + public static void cacheEquipmentIfNeeded(@NotNull ClientboundSetEquipmentPacket packet) { + pendingEquipment.add(packet); + EroticDungeon.LOGGER.debug("Cached SetEquipment packet{}, ID: {}", packet, packet.getEntity()); + } + + /** + * 缓存乘客包 + */ + public static void cachePassengersIfNeeded(@NotNull ClientboundSetPassengersPacket packet) { + pendingPassengers.add(packet); + EroticDungeon.LOGGER.debug("Cached SetPassengers packet {}, (as vehicle) ID: {}", packet, packet.getVehicle()); + } + + /** + * 缓存链接包(拴绳) + */ + public static void cacheLinkIfNeeded(@NotNull ClientboundSetEntityLinkPacket packet) { + pendingLinks.add(packet); + EroticDungeon.LOGGER.debug("Cached SetEntityLink packet {}, (as source) ID: {}", packet, packet.getSourceId()); + } + + /** + * 缓存头部旋转包 + */ + public static void cacheHeadRotationIfNeeded(ClientboundRotateHeadPacket packet) { + pendingHeadRotations.add(packet); + EroticDungeon.LOGGER.debug("Cached RotateHead packet {}", packet); + } + + /** + * 缓存移动包 + */ + public static void cacheMoveEntityIfNeeded(ClientboundMoveEntityPacket packet) { + pendingMovements.add(packet); + EroticDungeon.LOGGER.debug("Cached MoveEntity packet {}", packet); + } + + /** + * 缓存传送包 + */ + public static void cacheTeleportEntityIfNeeded(ClientboundTeleportEntityPacket packet) { + EroticDungeon.LOGGER.debug("Cached TeleportEntity packet {}", packet); + pendingMovements.add(packet); + } + + /** + * 缓存运动包 + */ + public static void cacheMotionIfNeeded(ClientboundSetEntityMotionPacket packet) { + pendingMotions.add(packet); + EroticDungeon.LOGGER.debug("Cached SetEntityMotion packet {}, ID: {}", packet, packet.getId()); + } + + // ========== 处理方法 ========== + + /** + * 处理缓存的 NPC 包(当 NPCInfo 到达时调用) + */ + public static void processPendingNPCs(@NotNull PlayerInfo npcInfo) { + UUID uuid = npcInfo.getProfile().getId(); + ClientPacketListener connection = Minecraft.getInstance().getConnection(); + + if (!(connection instanceof IEDGClientPacketListener iedgListener)) { + return; + } + + // 处理缓存的 AddPlayer 包 + Iterator playerIterator = pendingNPCs.iterator(); + while (playerIterator.hasNext()) { + ClientboundAddPlayerPacket packet = playerIterator.next(); + if (packet.getPlayerId().equals(uuid)) { + PlayerInfo npcPlayerInfo = iedgListener.getNPCPlayerInfo(uuid); + if (npcPlayerInfo != null) { + // 创建 NPC 玩家实体 + iedgListener.edg$createNPCPlayer(packet, npcPlayerInfo); + playerIterator.remove(); + EroticDungeon.LOGGER.debug("Processed AddPlayer packet for NPC: {}", uuid); + + // 处理所有缓存的包 + processAllCachedPackets(iedgListener); + break; + } else { + EroticDungeon.LOGGER.warn("NPC Player {} not found", uuid); + } + } + } + } + + /** + * 处理所有缓存的包 + */ + private static void processAllCachedPackets(IEDGClientPacketListener iedgListener) { + Level level = Minecraft.getInstance().level; + if (level == null) return; + +// // 处理实体包 +// Iterator entityIterator = pendingEntities.iterator(); +// while (entityIterator.hasNext()) { +// ClientboundAddEntityPacket packet = entityIterator.next(); +// Entity entity = level.getEntity(packet.getId()); +// if (entity != null) { +// iedgListener.edg$createEntity(packet); +// entityIterator.remove(); +// EroticDungeon.LOGGER.debug("Processed AddEntity packet: {}", entity.getUUID()); +// } +// +// } + + // 处理实体数据包 + Iterator dataIterator = pendingEntityData.iterator(); + while (dataIterator.hasNext()) { + ClientboundSetEntityDataPacket packet = dataIterator.next(); + Entity entity = level.getEntity(packet.id()); + if (entity != null) { + iedgListener.edg$setEntityData(packet); + dataIterator.remove(); + EroticDungeon.LOGGER.debug("Processed SetEntityData packet: {}", entity.getUUID()); + } + } + + // 处理属性包 + Iterator attrIterator = pendingAttributes.iterator(); + while (attrIterator.hasNext()) { + ClientboundUpdateAttributesPacket packet = attrIterator.next(); + Entity entity = level.getEntity(packet.getEntityId()); + if (entity != null) { + iedgListener.edg$updateAttributes(packet); + attrIterator.remove(); + EroticDungeon.LOGGER.debug("Processed UpdateAttributes packet: {}", entity.getUUID()); + } + } + + // 处理装备包 + Iterator equipIterator = pendingEquipment.iterator(); + while (equipIterator.hasNext()) { + ClientboundSetEquipmentPacket packet = equipIterator.next(); + Entity entity = level.getEntity(packet.getEntity()); + if (entity != null) { + iedgListener.edg$setEquipment(packet); + equipIterator.remove(); + EroticDungeon.LOGGER.debug("Processed SetEquipment packet for: {}", entity.getUUID()); + } + } + + // 处理乘客包 + Iterator passengerIterator = pendingPassengers.iterator(); + while (passengerIterator.hasNext()) { + ClientboundSetPassengersPacket packet = passengerIterator.next(); + Entity vehicle = level.getEntity(packet.getVehicle()); + if (vehicle != null) { + boolean flag = true; + for (int passengerId : packet.getPassengers()) { + Entity passenger = level.getEntity(passengerId); + if (passenger == null) { + flag = false; + break; + } + } + if (flag) { + iedgListener.edg$setPassengers(packet); + passengerIterator.remove(); + EroticDungeon.LOGGER.debug("Processed SetPassengers packet: {}", vehicle.getUUID()); + } + } + } + + // 处理链接包 + Iterator linkIterator = pendingLinks.iterator(); + while (linkIterator.hasNext()) { + ClientboundSetEntityLinkPacket packet = linkIterator.next(); + Entity source = level.getEntity(packet.getSourceId()); + Entity dest = level.getEntity(packet.getDestId()); + if (source != null && dest != null) { + iedgListener.edg$setEntityLink(packet); + linkIterator.remove(); + EroticDungeon.LOGGER.debug("Processed SetEntityLink packet: {}", source.getUUID()); + } + } + + // 处理头部旋转包 + Iterator headIterator = pendingHeadRotations.iterator(); + while (headIterator.hasNext()) { + ClientboundRotateHeadPacket packet = headIterator.next(); + Entity entity = packet.getEntity(level); + if (entity != null){ + iedgListener.edg$rotateHead(packet); + headIterator.remove(); + } + EroticDungeon.LOGGER.debug("Processed RotateHead packet for NPC: {}", entity.getUUID()); + } + + // 处理移动包 + Iterator> moveIterator = pendingMovements.iterator(); + while (moveIterator.hasNext()) { + Packet packet = moveIterator.next(); + Entity entity = null; + + if (packet instanceof ClientboundMoveEntityPacket movePacket) { + entity = movePacket.getEntity(level); + } else if (packet instanceof ClientboundTeleportEntityPacket teleportPacket) { + entity = level.getEntity(teleportPacket.getId()); + } + + if (entity != null) { + if (packet instanceof ClientboundMoveEntityPacket movePacket) { + iedgListener.edg$moveEntity(movePacket); + } else if (packet instanceof ClientboundTeleportEntityPacket teleportPacket) { + iedgListener.edg$teleportEntity(teleportPacket); + } + + moveIterator.remove(); + EroticDungeon.LOGGER.debug("Processed movement packet for NPC: {}", entity.getUUID()); + } + } + + // 处理运动包 + Iterator motionIterator = pendingMotions.iterator(); + while (motionIterator.hasNext()) { + ClientboundSetEntityMotionPacket packet = motionIterator.next(); + Entity entity = level.getEntity(packet.getId()); + if (entity != null) { + iedgListener.edg$setEntityMotion(packet); + motionIterator.remove(); + EroticDungeon.LOGGER.debug("Processed SetEntityMotion packet for NPC: {}", entity.getUUID()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/top/r3944realms/eroticdungeongame/content/animation/IEDGAnimation.java b/src/main/java/top/r3944realms/eroticdungeongame/content/animation/IEDGAnimation.java index f01ebbce..e4d41208 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/content/animation/IEDGAnimation.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/content/animation/IEDGAnimation.java @@ -19,7 +19,9 @@ package top.r3944realms.eroticdungeongame.content.animation; import io.zershyan.sccore.animation.AnimationApi; import io.zershyan.sccore.animation.helper.AnimationHelper; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; +import org.apache.logging.log4j.core.jmx.Server; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import top.r3944realms.eroticdungeongame.EroticDungeon; @@ -50,14 +52,14 @@ public interface IEDGAnimation { default void play(Player player) { - if (player != null && !player.level().isClientSide) { + if (player != null) { AnimationHelper helper = AnimationApi.getHelper(player); helper.playAnimation(IEDGAnimation.LAYER, getBaseId().withSuffix("01")); } } default void play(Player player, int varNumber) { - if (player != null && !player.level().isClientSide) { + if (player != null) { AnimationHelper helper = AnimationApi.getHelper(player); helper.playAnimation(IEDGAnimation.LAYER, getBaseId().withSuffix(String.format("%02d", Math.max(1, Math.min(99, varNumber))))); } @@ -65,7 +67,7 @@ public interface IEDGAnimation { @Nullable static ResourceLocation getPlayingAnimation(Player player) { - if (player != null && !player.level().isClientSide) { + if (player != null) { AnimationHelper helper = AnimationApi.getHelper(player); return helper.getAnimationPlaying(IEDGAnimation.LAYER); } @@ -81,9 +83,16 @@ public interface IEDGAnimation { } static void stop(Player player) { - if (player != null && !player.level().isClientSide) { + if (player != null) { AnimationHelper helper = AnimationApi.getHelper(player); helper.removeAnimation(IEDGAnimation.LAYER); } } + + static void refresh(ServerPlayer target, Player receiver) { + if (target != null) { + AnimationHelper helper = AnimationApi.getHelper(target); + helper.playAnimation(LAYER, helper.getAnimationPlaying(IEDGAnimation.LAYER)); + } + } } diff --git a/src/main/java/top/r3944realms/eroticdungeongame/content/block/blockentity/BaseSeatBlockEntity.java b/src/main/java/top/r3944realms/eroticdungeongame/content/block/blockentity/BaseSeatBlockEntity.java index c0e59f03..34a28e76 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/content/block/blockentity/BaseSeatBlockEntity.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/content/block/blockentity/BaseSeatBlockEntity.java @@ -93,8 +93,8 @@ public abstract class BaseSeatBlockEntity extends BlockEntity { return false; } - protected final void playAnimation(Player player, ISeatType ISeatType) { - if(getPlayerAnimationNumber() == 1) { + public final void playAnimation(Player player, ISeatType ISeatType) { + if (getPlayerAnimationNumber() == 1) { SeatService.playBindingAnimation(player, ISeatType); } else SeatService.playBindingAnimation(player, ISeatType, getPlayerAnimationNumber()); } diff --git a/src/main/java/top/r3944realms/eroticdungeongame/content/entity/SeatEntity.java b/src/main/java/top/r3944realms/eroticdungeongame/content/entity/SeatEntity.java index c52baa52..d97fbf90 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/content/entity/SeatEntity.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/content/entity/SeatEntity.java @@ -64,7 +64,6 @@ public class SeatEntity extends Entity { if (!this.level().isClientSide) { // 简化的检查逻辑 if (shouldRemove() && linkedBlockPos != null) { - SeatService.releasePlayerFromBlock(this.level(), this.linkedBlockPos); this.discard(); } } else { @@ -234,7 +233,7 @@ public class SeatEntity extends Entity { @Override public void remove(@NotNull RemovalReason reason) { if (!level().isClientSide && this.linkedBlockPos != null) { - SeatService.releasePlayerFromBlock(level(), this.linkedBlockPos); + SeatService.releasePlayerFromBlock(level(), this.linkedBlockPos, this); } super.remove(reason); } diff --git a/src/main/java/top/r3944realms/eroticdungeongame/content/entity/npc/NPCPlayerList.java b/src/main/java/top/r3944realms/eroticdungeongame/content/entity/npc/NPCPlayerList.java index 02aa29cc..5c1c900b 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/content/entity/npc/NPCPlayerList.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/content/entity/npc/NPCPlayerList.java @@ -47,7 +47,6 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.server.players.GameProfileCache; import net.minecraft.server.players.PlayerList; -import net.minecraft.stats.Stats; import net.minecraft.tags.TagNetworkSerialization; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; @@ -139,7 +138,6 @@ public class NPCPlayerList { servergamepacketlistenerimpl.send(new ClientboundUpdateRecipesPacket(this.server.getRecipeManager().getRecipes())); servergamepacketlistenerimpl.send(new ClientboundUpdateTagsPacket(TagNetworkSerialization.serializeTagsToNetwork(this.registries))); this.sendPlayerPermissionLevel(npc); - npc.getStats().markAllDirty(); npc.getRecipeBook().sendInitialRecipeBook(npc); this.updateEntireScoreboard(serverlevel1.getScoreboard(), npc); this.server.invalidateStatus(); @@ -364,11 +362,11 @@ public class NPCPlayerList { protected void save(NPCServerPlayer npcServerPlayer) { this.npcIo.save(npcServerPlayer); } + public void removeAll() { for (NPCServerPlayer npc : this.npcs) { npc.connection.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown")); } - } public void delete(NPCServerPlayer npc) { @@ -379,15 +377,14 @@ public class NPCPlayerList { public void remove(NPCServerPlayer npc) { net.minecraftforge.event.ForgeEventFactory.firePlayerLoggedOut(npc); ServerLevel serverlevel = npc.serverLevel(); - npc.awardStat(Stats.LEAVE_GAME); this.save(npc); if (npc.isPassenger()) { Entity entity = npc.getRootVehicle(); if (entity.hasExactlyOnePlayerPassenger()) { LOGGER.debug("Removing player mount"); npc.stopRiding(); - entity.getPassengersAndSelf().forEach((p_215620_) -> { - p_215620_.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER); + entity.getPassengersAndSelf().forEach((entity1) -> { + entity1.setRemoved(Entity.RemovalReason.UNLOADED_WITH_PLAYER); }); } } @@ -508,6 +505,7 @@ public class NPCPlayerList { } } + public MinecraftServer getServer() { return this.server; } diff --git a/src/main/java/top/r3944realms/eroticdungeongame/content/entity/npc/NPCServerPlayer.java b/src/main/java/top/r3944realms/eroticdungeongame/content/entity/npc/NPCServerPlayer.java index 602674a6..4d9c309c 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/content/entity/npc/NPCServerPlayer.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/content/entity/npc/NPCServerPlayer.java @@ -68,6 +68,7 @@ public class NPCServerPlayer extends ServerPlayer implements INPCPlayer { }; public NPCServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile) { super(server, level, gameProfile); + getAdvancements().stopListening(); } public static @Nullable NPCServerPlayer createNPC(String username, @NotNull MinecraftServer server, double x, double y, double z, double yaw, double pitch, ResourceKey dimensionId, GameType gamemode, boolean isflying) { diff --git a/src/main/java/top/r3944realms/eroticdungeongame/core/capability/DungeonDataSyncManager.java b/src/main/java/top/r3944realms/eroticdungeongame/core/capability/DungeonDataSyncManager.java index 52c8cc14..41074e6f 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/core/capability/DungeonDataSyncManager.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/core/capability/DungeonDataSyncManager.java @@ -27,6 +27,9 @@ import top.r3944realms.eroticdungeongame.content.animation.IEDGAnimation; import top.r3944realms.eroticdungeongame.content.block.ISeatBlock; import top.r3944realms.eroticdungeongame.content.block.blockentity.BaseSeatBlockEntity; import top.r3944realms.eroticdungeongame.content.util.FurnitureHelper; +import top.r3944realms.eroticdungeongame.core.device.ISeatType; +import top.r3944realms.eroticdungeongame.core.network.EDGNetworkHandler; +import top.r3944realms.eroticdungeongame.core.network.toServer.RefreshPlayerAnimationPacket; import top.r3944realms.eroticdungeongame.util.IEDGEntity; import top.r3944realms.lib39.core.sync.CachedSyncManager; @@ -39,12 +42,15 @@ public class DungeonDataSyncManager extends CachedSyncManager, AbstractPlayerDungeonData> getSyncMap() { return playerDungeonData; } - + static int cooldown = 0; public static void tick(@NotNull Player player) { + if (cooldown > 0) { + cooldown--; + } player.getCapability(PlayerDungeonDataProvider.PLAYER_DUNGEON_DATA_CAP).ifPresent( cap -> { if (player.level().isClientSide) { - clientTick(player); + clientTick(player, cap); } else if (cap.getDeviceMainBlockPos() != null) { if (cap.getEyeHeight() != -1.0 && cap.getEyeHeight() >= 0.0) { EntityDimensions dimensions = player.getDimensions(player.getPose()); @@ -57,8 +63,16 @@ public class DungeonDataSyncManager extends CachedSyncManager void sendToAllPlayer(MSG message){ CHANNEL.send(ALL_PLAYER.noArg(), message); } + public static void sendToServer(MSG message){ + CHANNEL.sendToServer(message); + } } diff --git a/src/main/java/top/r3944realms/eroticdungeongame/core/network/toClient/NPCInfoUpdatePacket.java b/src/main/java/top/r3944realms/eroticdungeongame/core/network/toClient/NPCInfoUpdatePacket.java index 8cc2ae8e..3358ab32 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/core/network/toClient/NPCInfoUpdatePacket.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/core/network/toClient/NPCInfoUpdatePacket.java @@ -33,6 +33,7 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import top.r3944realms.eroticdungeongame.EroticDungeon; +import top.r3944realms.eroticdungeongame.client.ClientNPCManager; import top.r3944realms.eroticdungeongame.content.entity.npc.NPCServerPlayer; import top.r3944realms.eroticdungeongame.util.IEDGClientPacketListener; @@ -96,6 +97,7 @@ public final class NPCInfoUpdatePacket { for (Entry entry : packet.newEntries()) { PlayerInfo npcInfo = new PlayerInfo(entry.profile, false); iedgClientPacketListener.getNPCPlayerInfoMap().putIfAbsent(entry.uuid(), npcInfo); + ClientNPCManager.processPendingNPCs(npcInfo); } for (Entry entry : packet.entries) { PlayerInfo npcInfo = iedgClientPacketListener.getNPCPlayerInfoMap().get(entry.uuid); diff --git a/src/main/java/top/r3944realms/eroticdungeongame/core/network/toServer/RefreshPlayerAnimationPacket.java b/src/main/java/top/r3944realms/eroticdungeongame/core/network/toServer/RefreshPlayerAnimationPacket.java new file mode 100644 index 00000000..21dc0432 --- /dev/null +++ b/src/main/java/top/r3944realms/eroticdungeongame/core/network/toServer/RefreshPlayerAnimationPacket.java @@ -0,0 +1,48 @@ +/* + * Copyright 2025-2026 R3944Realms + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package top.r3944realms.eroticdungeongame.core.network.toServer; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkEvent; +import org.jetbrains.annotations.NotNull; +import top.r3944realms.eroticdungeongame.content.animation.IEDGAnimation; + +import java.util.UUID; +import java.util.function.Supplier; + +public record RefreshPlayerAnimationPacket(UUID uuid) { + public RefreshPlayerAnimationPacket(@NotNull FriendlyByteBuf buf) { + this(buf.readUUID()); + } + public void encode(@NotNull FriendlyByteBuf buf) { + buf.writeUUID(uuid); + } + + public void handle(@NotNull Supplier contextSupplier) { + NetworkEvent.Context context = contextSupplier.get(); + ServerPlayer sender = context.getSender(); + context.enqueueWork(() -> { + if (sender != null) { + if (sender.serverLevel().getEntity(uuid) instanceof ServerPlayer target) { + IEDGAnimation.refresh(target, sender); + } + } + }); + context.setPacketHandled(true); + } +} diff --git a/src/main/java/top/r3944realms/eroticdungeongame/core/service/SeatService.java b/src/main/java/top/r3944realms/eroticdungeongame/core/service/SeatService.java index bc8772bf..d8905e95 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/core/service/SeatService.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/core/service/SeatService.java @@ -28,6 +28,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import top.r3944realms.eroticdungeongame.EroticDungeon; import top.r3944realms.eroticdungeongame.api.event.RideDeviceEvent; import top.r3944realms.eroticdungeongame.api.event.UnRideDeviceEvent; @@ -125,6 +126,17 @@ public class SeatService { return false; } + /** + * 从方块位置释放玩家(但会检查是否为目标座椅,避免释放错座椅) + */ + public static boolean releasePlayerFromBlock(@NotNull Level level, @NotNull BlockPos blockPos, SeatEntity seat) { + BaseSeatBlockEntity blockEntity = FurnitureHelper.getSeatBlockEntity(level, blockPos); + if (blockEntity != null) { + return releasePlayer(level, blockPos, seat); + } + return false; + } + public static @NotNull Optional getPlayerSeat(@NotNull Player player) { return player.getCapability(PlayerDungeonDataProvider.PLAYER_DUNGEON_DATA_CAP).resolve().map(cap -> { BlockPos deviceMainBlockPos = cap.getDeviceMainBlockPos(); @@ -241,14 +253,29 @@ public class SeatService { */ public static boolean releasePlayer(@NotNull Level level, BlockPos blockPos) { BaseSeatBlockEntity seatBlockEntity = FurnitureHelper.getSeatBlockEntity(level, blockPos); - return releasePlayerInternal(seatBlockEntity, level, blockPos); + BlockState blockState = level.getBlockState(blockPos); + boolean flag = releasePlayerInternal(seatBlockEntity, level, blockState, blockPos); + if (flag) { + FurnitureHelper.setSeatOccupied(level, blockPos, false); + } + return flag; + } + public static boolean releasePlayer(@NotNull Level level, BlockPos blockPos,@NotNull SeatEntity seat) { + BaseSeatBlockEntity seatBe = FurnitureHelper.getSeatBlockEntity(level, blockPos); + BlockState blockState = level.getBlockState(blockPos); + boolean flag = releasePlayerInternal(seatBe, level, blockPos, blockState, seat); + if (flag) { + FurnitureHelper.setSeatOccupied(level, blockPos, false); + } + return flag; } - private static boolean releasePlayerInternal(BaseSeatBlockEntity be, @NotNull Level level, BlockPos blockPos) { - BlockState blockState = level.getBlockState(blockPos); - // 1. 更新方块状态 - FurnitureHelper.setSeatOccupied(level, blockPos, false); + private static boolean releasePlayerInternal(BaseSeatBlockEntity be, @NotNull Level level, BlockState blockState, BlockPos blockPos) { + return releasePlayerInternal(be, level, blockPos, blockState, null); + } + //检查是否与释放预期座椅一致 + private static boolean releasePlayerInternal(BaseSeatBlockEntity be, @NotNull Level level, BlockPos blockPos, BlockState blockState, @Nullable SeatEntity seat) { // 2. 处理实体(只在服务端) if (level instanceof ServerLevel) { Player playerByUUID; @@ -256,13 +283,16 @@ public class SeatService { if (be.getBoundPlayerUUID() != null) { playerByUUID = level.getPlayerByUUID(be.getBoundPlayerUUID()); if (playerByUUID != null) { - SeatEntity seat = null; + SeatEntity seat_ = null; if (playerByUUID.isPassenger() && playerByUUID.getVehicle() instanceof SeatEntity seatEntity) { - seat = seatEntity; + seat_ = seatEntity; + if (seat != null && seat_ != seat) { + return false; //预期座椅不一致 + } } - isCancelled = EroticDungeon.EVENT_BUS.post(new UnRideDeviceEvent.Pre(playerByUUID, blockPos, blockState, be, seat)); + isCancelled = EroticDungeon.EVENT_BUS.post(new UnRideDeviceEvent.Pre(playerByUUID, blockPos, blockState, be, seat_)); if (!isCancelled) { - if(seat != null) ((IEDGEntity)(playerByUUID)).releaseEntityFromEDGDevice(true); + if(seat_ != null) ((IEDGEntity)(playerByUUID)).releaseEntityFromEDGDevice(true); playerByUUID.getCapability(PlayerDungeonDataProvider.PLAYER_DUNGEON_DATA_CAP) .ifPresent(i -> i.clearDungeonData(playerByUUID)); } else { diff --git a/src/main/java/top/r3944realms/eroticdungeongame/datagen/EDGRegistries.java b/src/main/java/top/r3944realms/eroticdungeongame/datagen/EDGRegistries.java index f070d6e8..ca0c9e46 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/datagen/EDGRegistries.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/datagen/EDGRegistries.java @@ -1,3 +1,19 @@ +/* + * Copyright 2025-2026 R3944Realms + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package top.r3944realms.eroticdungeongame.datagen; import net.minecraft.core.RegistrySetBuilder; diff --git a/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinClientPacketListener.java b/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinClientPacketListener.java index 9b4c4f80..b59d0295 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinClientPacketListener.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinClientPacketListener.java @@ -20,16 +20,18 @@ import com.google.common.collect.Maps; import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.brigadier.ParseResults; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.multiplayer.PlayerInfo; +import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.PacketUtils; -import net.minecraft.network.protocol.game.ClientboundAddPlayerPacket; -import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; +import net.minecraft.network.protocol.game.*; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.vehicle.Boat; import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -40,6 +42,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import top.r3944realms.eroticdungeongame.client.ClientNPCManager; import top.r3944realms.eroticdungeongame.client.EDGKeyBindings; import top.r3944realms.eroticdungeongame.content.entity.SeatEntity; import top.r3944realms.eroticdungeongame.content.entity.npc.NPCRemotePlayer; @@ -50,6 +53,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +@SuppressWarnings("ConstantValue") @Mixin(ClientPacketListener.class) public abstract class MixinClientPacketListener implements IEDGClientPacketListener { @Unique @@ -66,6 +70,27 @@ public abstract class MixinClientPacketListener implements IEDGClientPacketListe @Shadow @Final private Set listedPlayers; @Shadow private ClientLevel level; + + @Shadow public abstract void handleSetEntityMotion(ClientboundSetEntityMotionPacket packet); + + @Shadow public abstract void handleSetEntityData(ClientboundSetEntityDataPacket packet); + + @Shadow public abstract void handleUpdateAttributes(ClientboundUpdateAttributesPacket packet); + + @Shadow public abstract void handleSetEquipment(ClientboundSetEquipmentPacket packet); + + @Shadow public abstract void handleSetEntityPassengersPacket(ClientboundSetPassengersPacket packet); + + @Shadow public abstract void handleEntityLinkPacket(ClientboundSetEntityLinkPacket packet); + + @Shadow protected abstract ParseResults parseCommand(String command); + + @Shadow public abstract void handleRotateMob(ClientboundRotateHeadPacket packet); + + @Shadow public abstract void handleMoveEntity(ClientboundMoveEntityPacket packet); + + @Shadow public abstract void handleTeleportEntity(ClientboundTeleportEntityPacket packet); + @Unique private Entity edg$cachedMount = null; @@ -91,26 +116,149 @@ public abstract class MixinClientPacketListener implements IEDGClientPacketListe if (playerinfo == null) { PlayerInfo npcPlayerInfo = getNPCPlayerInfo(packet.getPlayerId()); if (npcPlayerInfo == null) { + ClientNPCManager.cacheNPCIfNeeded(packet); original.call(packet); } else { - double d0 = packet.getX(); - double d1 = packet.getY(); - double d2 = packet.getZ(); - float f = (float)(packet.getyRot() * 360) / 256.0F; - float f1 = (float)(packet.getxRot() * 360) / 256.0F; - int i = packet.getEntityId(); - assert this.minecraft.level != null; - NPCRemotePlayer npcRemotePlayer = new NPCRemotePlayer(this.minecraft.level, npcPlayerInfo.getProfile()); - npcRemotePlayer.setUUID(packet.getPlayerId()); - npcRemotePlayer.setId(i); - npcRemotePlayer.syncPacketPositionCodec(d0, d1, d2); - npcRemotePlayer.absMoveTo(d0, d1, d2, f, f1); - npcRemotePlayer.setOldPosAndRot(); - this.level.addPlayer(i, npcRemotePlayer); + edg$createNPCPlayer(packet, npcPlayerInfo); } } else original.call(packet); } + @WrapMethod( + method = "handleSetEntityData" + ) + private void edg$handleSetEntityData(ClientboundSetEntityDataPacket packet, Operation original){ + PacketUtils.ensureRunningOnSameThread(packet, ClientPacketListener.class.cast(this), this.minecraft); + Entity entity = this.level.getEntity(packet.id()); + if (entity == null) { + ClientNPCManager.cacheEntityDataIfNeeded(packet); + original.call(packet); + } else original.call(packet); + } + + @WrapMethod( + method = "handleSetEntityMotion" + ) + private void edg$handleSetEntityMotion(ClientboundSetEntityMotionPacket packet, Operation original){ + PacketUtils.ensureRunningOnSameThread(packet, ClientPacketListener.class.cast(this), this.minecraft); + Entity entity = this.level.getEntity(packet.getId()); + if (entity == null) { + ClientNPCManager.cacheMotionIfNeeded(packet); + original.call(packet); + } else original.call(packet); + } + + @WrapMethod( + method = "handleTeleportEntity" + ) + private void edg$handleTeleportEntity(ClientboundTeleportEntityPacket packet, Operation original){ + PacketUtils.ensureRunningOnSameThread(packet, ClientPacketListener.class.cast(this), this.minecraft); + Entity entity = this.level.getEntity(packet.getId()); + if (entity == null) { + ClientNPCManager.cacheTeleportEntityIfNeeded(packet); + original.call(packet); + } else original.call(packet); + } + + @WrapMethod( + method = "handleMoveEntity" + ) + private void edg$handleMoveEntity(ClientboundMoveEntityPacket packet, Operation original){ + PacketUtils.ensureRunningOnSameThread(packet, ClientPacketListener.class.cast(this), this.minecraft); + Entity entity = packet.getEntity(this.level); + if (entity == null) { + ClientNPCManager.cacheMoveEntityIfNeeded(packet); + original.call(packet); + } else original.call(packet); + } + + @WrapMethod( + method = "handleUpdateAttributes" + ) + private void edg$handleUpdateAttributes(ClientboundUpdateAttributesPacket packet, Operation original){ + PacketUtils.ensureRunningOnSameThread(packet, ClientPacketListener.class.cast(this), this.minecraft); + Entity entity = this.level.getEntity(packet.getEntityId()); + if (entity == null) { + ClientNPCManager.cacheAttributesIfNeeded(packet); + original.call(packet); + } else original.call(packet); + } + + @WrapMethod( + method = "handleSetEntityPassengersPacket" + ) + private void edg$handleSetEntityPassengersPacket(ClientboundSetPassengersPacket packet, Operation original){ + PacketUtils.ensureRunningOnSameThread(packet, ClientPacketListener.class.cast(this), this.minecraft); + Entity entity = this.level.getEntity(packet.getVehicle()); + if (entity == null) { + ClientNPCManager.cachePassengersIfNeeded(packet); + original.call(packet); + } else { + for(int i : packet.getPassengers()) { + Entity entity1 = this.level.getEntity(i); + if (entity1 == null) { + ClientNPCManager.cachePassengersIfNeeded(packet); + break; + } + } + original.call(packet); + } + } + + @WrapMethod( + method = "handleSetEquipment" + ) + private void edg$handleSetEquipment(ClientboundSetEquipmentPacket packet, Operation original){ + PacketUtils.ensureRunningOnSameThread(packet, ClientPacketListener.class.cast(this), this.minecraft); + Entity entity = this.level.getEntity(packet.getEntity()); + if (entity == null) { + ClientNPCManager.cacheEquipmentIfNeeded(packet); + original.call(packet); + } else original.call(packet); + } + + @WrapMethod( + method = "handleEntityLinkPacket" + ) + private void edg$handleEntityLinkPacket(ClientboundSetEntityLinkPacket packet, Operation original){ + PacketUtils.ensureRunningOnSameThread(packet, ClientPacketListener.class.cast(this), this.minecraft); + Entity entity = this.level.getEntity(packet.getSourceId()); + if (entity == null) { + ClientNPCManager.cacheLinkIfNeeded(packet); + original.call(packet); + } else original.call(packet); + } + + @WrapMethod( + method = "handleRotateMob" + ) + private void edg$handleRotateMob(ClientboundRotateHeadPacket packet, Operation original){ + PacketUtils.ensureRunningOnSameThread(packet, ClientPacketListener.class.cast(this), this.minecraft); + Entity entity = packet.getEntity(this.level); + if (entity == null) { + ClientNPCManager.cacheHeadRotationIfNeeded(packet); + original.call(packet); + } else original.call(packet); + } + + @Override + public void edg$createNPCPlayer(@NotNull ClientboundAddPlayerPacket packet, @NotNull PlayerInfo npcPlayerInfo) { + double d0 = packet.getX(); + double d1 = packet.getY(); + double d2 = packet.getZ(); + float f = (float)(packet.getyRot() * 360) / 256.0F; + float f1 = (float)(packet.getxRot() * 360) / 256.0F; + int i = packet.getEntityId(); + assert this.minecraft.level != null; + NPCRemotePlayer npcRemotePlayer = new NPCRemotePlayer(this.minecraft.level, npcPlayerInfo.getProfile()); + npcRemotePlayer.setUUID(packet.getPlayerId()); + npcRemotePlayer.setId(i); + npcRemotePlayer.syncPacketPositionCodec(d0, d1, d2); + npcRemotePlayer.absMoveTo(d0, d1, d2, f, f1); + npcRemotePlayer.setOldPosAndRot(); + this.level.addPlayer(i, npcRemotePlayer); + } + @SuppressWarnings({"unchecked", "SuspiciousMethodCalls"}) @WrapOperation( method = "handlePlayerInfoUpdate", @@ -138,4 +286,49 @@ public abstract class MixinClientPacketListener implements IEDGClientPacketListe public Set getListedNPCPlayers() { return listedPlayers; } + + @Override + public void edg$setEntityMotion(ClientboundSetEntityMotionPacket packet) { + handleSetEntityMotion(packet); + } + + @Override + public void edg$setEntityData(ClientboundSetEntityDataPacket packet) { + handleSetEntityData(packet); + } + + @Override + public void edg$updateAttributes(ClientboundUpdateAttributesPacket packet) { + handleUpdateAttributes(packet); + } + + @Override + public void edg$setEquipment(ClientboundSetEquipmentPacket packet) { + handleSetEquipment(packet); + } + + @Override + public void edg$setPassengers(ClientboundSetPassengersPacket packet) { + handleSetEntityPassengersPacket(packet); + } + + @Override + public void edg$setEntityLink(ClientboundSetEntityLinkPacket packet) { + handleEntityLinkPacket(packet); + } + + @Override + public void edg$rotateHead(ClientboundRotateHeadPacket packet) { + handleRotateMob(packet); + } + + @Override + public void edg$moveEntity(ClientboundMoveEntityPacket packet) { + handleMoveEntity(packet); + } + + @Override + public void edg$teleportEntity(ClientboundTeleportEntityPacket packet) { + handleTeleportEntity(packet); + } } diff --git a/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinGameTestServer.java b/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinGameTestServer.java index 215944bd..26a25521 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinGameTestServer.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinGameTestServer.java @@ -30,7 +30,7 @@ public abstract class MixinGameTestServer implements IEDGMinecraftServer { @WrapOperation( method = "initServer", at = @At( - value = "HEAD", + value = "INVOKE", target = "Lnet/minecraft/gametest/framework/GameTestServer;setPlayerList(Lnet/minecraft/server/players/PlayerList;)V" ) ) diff --git a/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinItemInHandRenderer.java b/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinItemInHandRenderer.java index cb9a078a..7db5d507 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinItemInHandRenderer.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinItemInHandRenderer.java @@ -1,3 +1,19 @@ +/* + * Copyright 2025-2026 R3944Realms + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package top.r3944realms.eroticdungeongame.mixin.minecraft; import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; diff --git a/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinServerPlayer.java b/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinServerPlayer.java index 47cb7b6c..57ee1f83 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinServerPlayer.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/mixin/minecraft/MixinServerPlayer.java @@ -83,8 +83,7 @@ public abstract class MixinServerPlayer extends Player implements IEDGEntity { if (data.getDeviceMainBlockPos() != null && level().getBlockEntity(data.getDeviceMainBlockPos()) instanceof BaseSeatBlockEntity seatBe) { if (isCreative() || forced || (seatBe.hasLockCode() && Objects.equals(seatBe.getLockCode(), lock)) || !seatBe.hasLockCode()) { Entity entity = this.getVehicle(); - this.removeVehicle(); - if (entity != null && entity != this.getVehicle() && !this.level().isClientSide) { + if (entity != null && !this.level().isClientSide) { Vec3 vec3; if (this.isRemoved()) { vec3 = this.position(); diff --git a/src/main/java/top/r3944realms/eroticdungeongame/util/IEDGClientPacketListener.java b/src/main/java/top/r3944realms/eroticdungeongame/util/IEDGClientPacketListener.java index d851c9b5..e4c8ff90 100644 --- a/src/main/java/top/r3944realms/eroticdungeongame/util/IEDGClientPacketListener.java +++ b/src/main/java/top/r3944realms/eroticdungeongame/util/IEDGClientPacketListener.java @@ -17,6 +17,7 @@ package top.r3944realms.eroticdungeongame.util; import net.minecraft.client.multiplayer.PlayerInfo; +import net.minecraft.network.protocol.game.*; import javax.annotation.Nullable; import java.util.Collection; @@ -26,17 +27,22 @@ import java.util.UUID; public interface IEDGClientPacketListener { Map getNPCPlayerInfoMap(); + Set getListedNPCPlayers(); + default Collection getOnlineNPCPlayers() { return getNPCPlayerInfoMap().values(); } + default Collection getOnlineNPCPlayerIds() { return getNPCPlayerInfoMap().keySet(); } + @Nullable default PlayerInfo getNPCPlayerInfo(UUID uniqueId) { return getNPCPlayerInfoMap().get(uniqueId); } + @Nullable default PlayerInfo getNPCPlayerInfo(String name) { for(PlayerInfo playerinfo : getNPCPlayerInfoMap().values()) { @@ -46,4 +52,26 @@ public interface IEDGClientPacketListener { } return null; } + + void edg$createNPCPlayer(ClientboundAddPlayerPacket packet, PlayerInfo playerInfo); + +// void edg$createEntity(ClientboundAddEntityPacket packet); + + void edg$setEntityMotion(ClientboundSetEntityMotionPacket packet); + + void edg$setEntityData(ClientboundSetEntityDataPacket packet); + + void edg$updateAttributes(ClientboundUpdateAttributesPacket packet); + + void edg$setEquipment(ClientboundSetEquipmentPacket packet); + + void edg$setPassengers(ClientboundSetPassengersPacket packet); + + void edg$setEntityLink(ClientboundSetEntityLinkPacket packet); + + void edg$rotateHead(ClientboundRotateHeadPacket packet); + + void edg$moveEntity(ClientboundMoveEntityPacket movePacket); + + void edg$teleportEntity(ClientboundTeleportEntityPacket teleportPacket); }