From 32226f43e9676dab399b8fef93c90f36816f0197 Mon Sep 17 00:00:00 2001 From: ImpulsiveLass Date: Thu, 20 Aug 2026 23:19:48 -0400 Subject: [PATCH] beholder fixes --- .../alexscaves/client/event/ClientEvents.java | 26 +- .../mixin/client/MinecraftMixin.java | 11 + .../server/entity/item/BeholderEyeEntity.java | 276 +++++++++++++++--- 3 files changed, 262 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/event/ClientEvents.java b/src/main/java/com/github/alexmodguy/alexscaves/client/event/ClientEvents.java index bc0332823..f14caf6ee 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/event/ClientEvents.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/event/ClientEvents.java @@ -39,6 +39,7 @@ import net.minecraft.client.gui.Font; import net.minecraft.client.gui.screens.advancements.AdvancementsScreen; import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.renderer.FogRenderer; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.MultiBufferSource; @@ -240,6 +241,8 @@ public void postRenderStage(RenderLevelStageEvent event) { } } + private static final RandomSource CAMERA_RNG = RandomSource.create(); + @SubscribeEvent public void computeCameraAngles(ViewportEvent.ComputeCameraAngles event) { Entity player = Minecraft.getInstance().getCameraEntity(); @@ -264,10 +267,9 @@ public void computeCameraAngles(ViewportEvent.ComputeCameraAngles event) { } if (tremorAmount > 0) { if (ClientProxy.lastTremorTick != player.tickCount) { - RandomSource rng = player.level().random; - ClientProxy.randomTremorOffsets[0] = rng.nextFloat(); - ClientProxy.randomTremorOffsets[1] = rng.nextFloat(); - ClientProxy.randomTremorOffsets[2] = rng.nextFloat(); + ClientProxy.randomTremorOffsets[0] = CAMERA_RNG.nextFloat(); + ClientProxy.randomTremorOffsets[1] = CAMERA_RNG.nextFloat(); + ClientProxy.randomTremorOffsets[2] = CAMERA_RNG.nextFloat(); ClientProxy.lastTremorTick = player.tickCount; } double intensity = tremorAmount * Minecraft.getInstance().options.screenEffectScale().get(); @@ -1020,11 +1022,21 @@ public void onClientTick(TickEvent.ClientTickEvent event) { } } if (watcherEntity instanceof BeholderEyeEntity beholderEye) { + LocalPlayer player = Minecraft.getInstance().player; + beholderEye.setOldRots(); - beholderEye.setEyeYRot(Minecraft.getInstance().player.getYHeadRot()); - beholderEye.setEyeXRot(Minecraft.getInstance().player.getXRot()); + beholderEye.setEyeYRot(player.getYHeadRot()); + beholderEye.setEyeXRot(player.getXRot()); + + player.input.leftImpulse = 0.0F; + player.input.forwardImpulse = 0.0F; + player.input.jumping = false; + + player.setDeltaMovement(Vec3.ZERO); + player.fallDistance = 0.0F; + if (AlexsCaves.PROXY.isKeyDown(4)) { - AlexsCaves.PROXY.resetRenderViewEntity(Minecraft.getInstance().player); + AlexsCaves.PROXY.resetRenderViewEntity(player); } } } else if (ClientProxy.possessionStrengthAmount > 0F) { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/MinecraftMixin.java b/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/MinecraftMixin.java index 27682b9ce..0c802efd8 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/MinecraftMixin.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/MinecraftMixin.java @@ -66,4 +66,15 @@ private void ac_getSituationalMusic(CallbackInfoReturnable cir) { } } } + + @Inject( + method = "handleKeybinds", + at = @At("HEAD"), + cancellable = true + ) + private void ac_handleKeybinds(CallbackInfo ci) { + if (getCameraEntity() instanceof PossessesCamera) { + ci.cancel(); + } + } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/BeholderEyeEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/BeholderEyeEntity.java index 8ec2bb9a2..7ad8eee71 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/BeholderEyeEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/BeholderEyeEntity.java @@ -34,17 +34,26 @@ public class BeholderEyeEntity extends Entity implements PossessesCamera { private static final int LOAD_CHUNK_DISTANCE = 2; - private static final EntityDataAccessor> USING_PLAYER_ID = SynchedEntityData.defineId(BeholderEyeEntity.class, EntityDataSerializers.OPTIONAL_UUID); - private static final EntityDataAccessor Y_ROT = SynchedEntityData.defineId(BeholderEyeEntity.class, EntityDataSerializers.FLOAT); - private static final EntityDataAccessor X_ROT = SynchedEntityData.defineId(BeholderEyeEntity.class, EntityDataSerializers.FLOAT); + + private static final EntityDataAccessor> USING_PLAYER_ID = + SynchedEntityData.defineId( + BeholderEyeEntity.class, + EntityDataSerializers.OPTIONAL_UUID + ); private boolean loadingChunks = false; private boolean stopPossession; private boolean prevStopPossession = true; + private float eyeXRot; + private float eyeYRot; private float prevEyeXRot; private float prevEyeYRot; + private UUID lastUsingPlayerUUID; + + private static final int PLAYER_CHUNK_DISTANCE = 1; + public boolean hasTakenFullControlOfCamera; public BeholderEyeEntity(EntityType entityType, Level level) { @@ -58,47 +67,77 @@ public BeholderEyeEntity(PlayMessages.SpawnEntity spawnEntity, Level level) { @Override protected void defineSynchedData() { this.getEntityData().define(USING_PLAYER_ID, Optional.empty()); - this.getEntityData().define(X_ROT, 0F); - this.getEntityData().define(Y_ROT, 0F); } + @Override public void tick() { super.tick(); + Entity usingPlayer = getUsingPlayer(); + if (usingPlayer == null) { + if (!level().isClientSide && loadingChunks) { loadingChunks = false; + loadChunksAround(false); + + if (lastUsingPlayerUUID != null) { + ServerPlayer serverPlayer = + level().getServer().getPlayerList().getPlayer(lastUsingPlayerUUID); + + if (serverPlayer != null) { + restorePlayerChunks(serverPlayer); + } + } } + if (this.tickCount > 3) { this.discard(); } + } else { - if (!level().isClientSide && hasTakenFullControlOfCamera && !loadingChunks) { + + lastUsingPlayerUUID = usingPlayer.getUUID(); + + if (!level().isClientSide + && hasTakenFullControlOfCamera + && !loadingChunks) { + loadingChunks = true; loadChunksAround(true); } + if (usingPlayer instanceof LivingEntity living) { living.zza = 0; living.yya = 0; living.xxa = 0; } + if (level().isClientSide) { Player clientSidePlayer = AlexsCaves.PROXY.getClientSidePlayer(); + if (usingPlayer == clientSidePlayer) { if (AlexsCaves.PROXY.isKeyDown(4)) { - AlexsCaves.sendMSGToServer(new PossessionKeyMessage(this.getId(), usingPlayer.getId(), 0)); + AlexsCaves.sendMSGToServer( + new PossessionKeyMessage( + this.getId(), + usingPlayer.getId(), + 0 + ) + ); } } - } else { if (prevStopPossession != stopPossession) { handleCameraServerSide(usingPlayer, !stopPossession); prevStopPossession = stopPossession; } + if (stopPossession) { this.setUsingPlayerUUID(null); } + if (usingPlayer.isShiftKeyDown()) { stopPossession = true; } @@ -106,46 +145,68 @@ public void tick() { } } + @Override public Vec3 getDeltaMovement() { return Vec3.ZERO; } + @Override public void setDeltaMovement(Vec3 vec3) { } public void handleCameraServerSide(Entity usingPlayer, boolean turnOn) { if (usingPlayer.level().equals(this.level())) { - AlexsCaves.sendMSGToAll(new BeholderSyncMessage(this.getId(), turnOn)); + + AlexsCaves.sendMSGToAll( + new BeholderSyncMessage(this.getId(), turnOn) + ); + if (turnOn) { this.level().broadcastEntityEvent(this, (byte) 77); } else { this.level().broadcastEntityEvent(this, (byte) 78); } - if(turnOn){ + + if (turnOn) { hasTakenFullControlOfCamera = true; } + } else { this.discard(); } } + @Override public void remove(Entity.RemovalReason removalReason) { this.level().broadcastEntityEvent(this, (byte) 78); super.remove(removalReason); } + @Override public void handleEntityEvent(byte b) { if (b == 77 || b == 78) { + Entity usingPlayer = getUsingPlayer(); + if (usingPlayer instanceof Player player) { + if (b == 77) { + player.playSound(ACSoundRegistry.BEHOLDER_ENTER.get()); - AlexsCaves.PROXY.setRenderViewEntity(player, this); + + AlexsCaves.PROXY.setRenderViewEntity( + player, + this + ); + } else { + player.playSound(ACSoundRegistry.BEHOLDER_EXIT.get()); + AlexsCaves.PROXY.resetRenderViewEntity(player); } } + } else { super.handleEntityEvent(b); } @@ -154,103 +215,230 @@ public void handleEntityEvent(byte b) { @Override protected void readAdditionalSaveData(CompoundTag tag) { if (tag.contains("UsingPlayerUUID")) { - this.setUsingPlayerUUID(tag.getUUID("UsingPlayerUUID")); + this.setUsingPlayerUUID( + tag.getUUID("UsingPlayerUUID") + ); } } @Override protected void addAdditionalSaveData(CompoundTag tag) { UUID uuid1 = getUsingPlayerUUID(); + if (uuid1 != null) { tag.putUUID("UsingPlayerUUID", uuid1); } } public void setUsingPlayerUUID(UUID uuid) { - this.entityData.set(USING_PLAYER_ID, Optional.ofNullable(uuid)); + this.entityData.set( + USING_PLAYER_ID, + Optional.ofNullable(uuid) + ); } public UUID getUsingPlayerUUID() { - return this.entityData.get(USING_PLAYER_ID).orElse(null); + return this.entityData + .get(USING_PLAYER_ID) + .orElse(null); } public Entity getUsingPlayer() { UUID id = getUsingPlayerUUID(); + if (id == null) { return null; + } + + if (level().isClientSide) { + return level().getPlayerByUUID(id); } else { - if (level().isClientSide) { - return level().getPlayerByUUID(id); - } else { - return level().getServer().getPlayerList().getPlayer(id); - } + return level().getServer().getPlayerList().getPlayer(id); } } + + @Override public float getYRot() { - return this.entityData.get(Y_ROT); + return eyeYRot; } + @Override public float getXRot() { - return this.entityData.get(X_ROT); + return eyeXRot; } - public float getViewXRot(float f) { - return f == 1.0F ? this.getXRot() : Mth.lerp(f, this.prevEyeXRot, this.getXRot()); + public void setEyeYRot(float f) { + this.eyeYRot = f; } - public float getViewYRot(float f) { - return f == 1.0F ? this.getYRot() : Mth.lerp(f, this.prevEyeYRot, this.getYRot()); + public void setEyeXRot(float f) { + this.eyeXRot = f; } - public void setEyeYRot(float f) { - this.entityData.set(Y_ROT, f); + public float getViewXRot(float partialTicks) { + return partialTicks == 1.0F + ? this.getXRot() + : Mth.lerp( + partialTicks, + this.prevEyeXRot, + this.getXRot() + ); } - public void setEyeXRot(float f) { - this.entityData.set(X_ROT, f); + public float getViewYRot(float partialTicks) { + return partialTicks == 1.0F + ? this.getYRot() + : Mth.lerp( + partialTicks, + this.prevEyeYRot, + this.getYRot() + ); } @Override public Packet getAddEntityPacket() { - return (Packet) NetworkHooks.getEntitySpawningPacket(this); + return (Packet) + NetworkHooks.getEntitySpawningPacket(this); } + @Override public void onPossessionKeyPacket(Entity keyPresser, int type) { Entity possessed = this.getUsingPlayer(); + if (possessed != null && possessed.equals(keyPresser)) { stopPossession = true; } } private void loadChunksAround(boolean load) { + if (this.level() instanceof ServerLevel serverLevel) { - if(this.getUsingPlayer() instanceof ServerPlayer serverPlayer){ - ChunkPos playerChunkPos = new ChunkPos(serverPlayer.blockPosition()); - ForgeChunkManager.forceChunk(serverLevel, AlexsCaves.MODID, this, playerChunkPos.x, playerChunkPos.z, load, load); + + if (this.getUsingPlayer() instanceof ServerPlayer serverPlayer) { + + ChunkPos playerChunkPos = + new ChunkPos(serverPlayer.blockPosition()); + + for (int i = -PLAYER_CHUNK_DISTANCE; + i <= PLAYER_CHUNK_DISTANCE; i++) { + + for (int j = -PLAYER_CHUNK_DISTANCE; + j <= PLAYER_CHUNK_DISTANCE; j++) { + + int chunkX = playerChunkPos.x + i; + int chunkZ = playerChunkPos.z + j; + + ForgeChunkManager.forceChunk( + serverLevel, + AlexsCaves.MODID, + this, + chunkX, + chunkZ, + load, + load + ); + + if (load) { + serverPlayer.connection.send( + new ClientboundLevelChunkWithLightPacket( + serverLevel.getChunk(chunkX, chunkZ), + serverLevel.getLightEngine(), + (BitSet) null, + (BitSet) null + ) + ); + } + } + } } - ChunkPos chunkPos = new ChunkPos(this.blockPosition()); - int dist = Math.max(LOAD_CHUNK_DISTANCE, serverLevel.getServer().getPlayerList().getViewDistance() / 2); + + ChunkPos chunkPos = + new ChunkPos(this.blockPosition()); + + int dist = Math.max( + LOAD_CHUNK_DISTANCE, + serverLevel.getServer() + .getPlayerList() + .getViewDistance() / 2 + ); + for (int i = -dist; i <= dist; i++) { for (int j = -dist; j <= dist; j++) { - ForgeChunkManager.forceChunk(serverLevel, AlexsCaves.MODID, this, chunkPos.x + i, chunkPos.z + j, load, load); - if (load && this.getUsingPlayer() instanceof ServerPlayer serverPlayer) { - serverPlayer.connection.send(new ClientboundLevelChunkWithLightPacket(level().getChunk(chunkPos.x + i, chunkPos.z + j), level().getLightEngine(), (BitSet)null, (BitSet)null)); + + int chunkX = chunkPos.x + i; + int chunkZ = chunkPos.z + j; + + ForgeChunkManager.forceChunk( + serverLevel, + AlexsCaves.MODID, + this, + chunkX, + chunkZ, + load, + load + ); + + if (load + && this.getUsingPlayer() instanceof ServerPlayer serverPlayer) { + + serverPlayer.connection.send( + new ClientboundLevelChunkWithLightPacket( + serverLevel.getChunk(chunkX, chunkZ), + serverLevel.getLightEngine(), + (BitSet) null, + (BitSet) null + ) + ); } } } } } + private void restorePlayerChunks(ServerPlayer serverPlayer) { + + ServerLevel serverLevel = serverPlayer.serverLevel(); + + ChunkPos playerChunkPos = + new ChunkPos(serverPlayer.blockPosition()); + + int dist = Math.max( + LOAD_CHUNK_DISTANCE, + serverLevel.getServer() + .getPlayerList() + .getViewDistance() + ); + + for (int i = -dist; i <= dist; i++) { + for (int j = -dist; j <= dist; j++) { + + int chunkX = playerChunkPos.x + i; + int chunkZ = playerChunkPos.z + j; + + serverPlayer.connection.send( + new ClientboundLevelChunkWithLightPacket( + serverLevel.getChunk(chunkX, chunkZ), + serverLevel.getLightEngine(), + (BitSet) null, + (BitSet) null + ) + ); + } + } + } + @Override public float getPossessionStrength(float partialTicks) { float age = tickCount + partialTicks; + if (age > 10) { return 0.0F; - } else { - float j = age / 10F; - return 1F - j; } + + float j = age / 10F; + + return 1F - j; } @Override @@ -264,7 +452,7 @@ public boolean isPossessionBreakable() { } public void setOldRots() { - prevEyeYRot = getYRot(); - prevEyeXRot = getXRot(); + prevEyeYRot = eyeYRot; + prevEyeXRot = eyeXRot; } -} +} \ No newline at end of file