diff --git a/gradle.properties b/gradle.properties index 21ad5926a..d7500751a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,8 +17,8 @@ parchment_mappings_version=2024.07.28 mod_id=alexscaves mod_name=Alex's Caves mod_license=GNU LESSER GENERAL PUBLIC LICENSE -mod_version=1.0.0 -mod_authors=Alex_The_Create +mod_version=2.0.2 +mod_authors=Alexthe668, Noonyeyz mod_description=Explore new rare cave biomes hidden under the surface of the Overworld... # JEI (optional, for recipe viewing) diff --git a/src/main/java/com/github/alexmodguy/alexscaves/AlexsCaves.java b/src/main/java/com/github/alexmodguy/alexscaves/AlexsCaves.java index a86a853bb..3771aec96 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/AlexsCaves.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/AlexsCaves.java @@ -33,6 +33,7 @@ import com.github.alexmodguy.alexscaves.server.misc.*; import com.github.alexmodguy.alexscaves.server.potion.ACEffectRegistry; import com.github.alexmodguy.alexscaves.server.recipe.ACRecipeRegistry; +import com.github.alexmodguy.alexscaves.server.message.UpdateMagneticDataMessage; import com.mojang.logging.LogUtils; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; @@ -167,6 +168,8 @@ private void registerPayloads(RegisterPayloadHandlersEvent event) { registrar.playToClient(SundropRainbowMessage.TYPE, SundropRainbowMessage.CODEC, SundropRainbowMessage::handle); registrar.playToClient(SpelunkeryTableCompleteTutorialMessage.TYPE, SpelunkeryTableCompleteTutorialMessage.CODEC, SpelunkeryTableCompleteTutorialMessage::handle); + registrar.playToClient(UpdateMagneticDataMessage.TYPE, UpdateMagneticDataMessage.CODEC, + UpdateMagneticDataMessage::handle); // Client-to-server messages registrar.playToServer(MultipartEntityMessage.TYPE, MultipartEntityMessage.CODEC, MultipartEntityMessage::handle); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/ClientProxy.java b/src/main/java/com/github/alexmodguy/alexscaves/client/ClientProxy.java index 5279b6141..38ec62639 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/ClientProxy.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/ClientProxy.java @@ -25,6 +25,7 @@ import com.github.alexmodguy.alexscaves.server.block.blockentity.*; import com.github.alexmodguy.alexscaves.server.block.fluid.ACFluidRegistry; import com.github.alexmodguy.alexscaves.server.entity.ACEntityRegistry; +import com.github.alexmodguy.alexscaves.server.entity.item.BeholderEyeEntity; import com.github.alexmodguy.alexscaves.server.entity.item.QuarrySmasherEntity; import com.github.alexmodguy.alexscaves.server.entity.item.SubmarineEntity; import com.github.alexmodguy.alexscaves.server.entity.living.*; @@ -125,6 +126,8 @@ public class ClientProxy extends CommonProxy { public static float possessionStrengthAmount = 0; public static int renderNukeSkyDarkFor = 0; public static float masterVolumeNukeModifier = 0.0F; + // Client-side tracking for bubbled effect visuals (entity ID -> remaining ticks) + private static final it.unimi.dsi.fastutil.ints.Int2IntMap BUBBLED_EFFECT_TICKS = new it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap(); public static final Int2ObjectMap ENTITY_SOUND_INSTANCE_MAP = new Int2ObjectOpenHashMap<>(); public static final Map BLOCK_ENTITY_SOUND_INSTANCE_MAP = new HashMap<>(); private final ACItemRenderProperties isterProperties = new ACItemRenderProperties(); @@ -143,6 +146,23 @@ public class ClientProxy extends CommonProxy { public static Vec3 acSkyOverrideColor = Vec3.ZERO; public static boolean disabledBiomeAmbientLightByOtherMod = false; + /** + * Ticks down all bubbled effect timers. Called from ClientEvents. + */ + public static void tickBubbledEffects() { + if (BUBBLED_EFFECT_TICKS.isEmpty()) return; + var iterator = BUBBLED_EFFECT_TICKS.int2IntEntrySet().iterator(); + while (iterator.hasNext()) { + var entry = iterator.next(); + int newValue = entry.getIntValue() - 1; + if (newValue <= 0) { + iterator.remove(); + } else { + entry.setValue(newValue); + } + } + } + @SuppressWarnings("removal") @Override public void commonInit(IEventBus modEventBus) { @@ -535,12 +555,12 @@ private void registerShaders(final RegisterShadersEvent e) { e.registerShader( new ShaderInstance(e.getResourceProvider(), ResourceLocation.fromNamespaceAndPath(AlexsCaves.MODID, "rendertype_irradiated"), - DefaultVertexFormat.POSITION_TEX_COLOR), + DefaultVertexFormat.NEW_ENTITY), ACInternalShaders::setRenderTypeIrradiatedShader); e.registerShader( new ShaderInstance(e.getResourceProvider(), ResourceLocation.fromNamespaceAndPath(AlexsCaves.MODID, "rendertype_blue_irradiated"), - DefaultVertexFormat.POSITION_TEX_COLOR), + DefaultVertexFormat.NEW_ENTITY), ACInternalShaders::setRenderTypeBlueIrradiatedShader); e.registerShader(new ShaderInstance(e.getResourceProvider(), ResourceLocation.fromNamespaceAndPath(AlexsCaves.MODID, "rendertype_bubbled"), @@ -687,6 +707,54 @@ public void resetRenderViewEntity(Player player) { } } + @Override + public boolean hasBubbledEffectVisual(int entityId) { + return BUBBLED_EFFECT_TICKS.getOrDefault(entityId, 0) > 0; + } + + @Override + public void setBubbledEffectTicks(int entityId, int ticks) { + if (ticks <= 0) { + BUBBLED_EFFECT_TICKS.remove(entityId); + } else { + BUBBLED_EFFECT_TICKS.put(entityId, ticks); + } + } + + @Override + public void handleBeholderSync(int beholderId, boolean active, double x, double y, double z, float yRot, float xRot, UUID usingPlayerUUID) { + Player playerSided = getClientSidePlayer(); + if (playerSided != null && playerSided.level() instanceof ClientLevel clientLevel) { + Entity watcher = clientLevel.getEntity(beholderId); + // If entity doesn't exist on client and we have spawn data, create it + // This is necessary when viewing a Beholder from far away (unloaded chunks) + if (watcher == null && active && usingPlayerUUID != null) { + BeholderEyeEntity beholderEye = ACEntityRegistry.BEHOLDER_EYE.get().create(clientLevel); + if (beholderEye != null) { + beholderEye.setId(beholderId); + beholderEye.setPos(x, y, z); + beholderEye.setEyeYRot(yRot); + beholderEye.setEyeXRot(xRot); + beholderEye.setUsingPlayerUUID(usingPlayerUUID); + beholderEye.hasTakenFullControlOfCamera = true; + clientLevel.addEntity(beholderEye); + watcher = beholderEye; + } + } + if (watcher instanceof BeholderEyeEntity beholderEye) { + Entity beholderEyePlayer = beholderEye.getUsingPlayer(); + beholderEye.hasTakenFullControlOfCamera = true; + if (beholderEyePlayer != null && beholderEyePlayer instanceof Player && beholderEyePlayer.equals(playerSided)) { + if (active) { + setRenderViewEntity(playerSided, beholderEye); + } else { + resetRenderViewEntity(playerSided); + } + } + } + } + } + @Override public void playWorldSound(@Nullable Object soundEmitter, byte type) { if (soundEmitter instanceof Entity entity && !entity.level().isClientSide) { 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 6bc043910..1792efd98 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 @@ -290,8 +290,6 @@ public void postRenderStage(RenderLevelStageEvent event) { RenderSystem.runAsFancy(() -> HologramProjectorBlockRenderer.renderEntireBatch(event.getLevelRenderer(), event.getPoseStack(), event.getRenderTick(), event.getCamera(), event.getPartialTick().getGameTimeDeltaPartialTick(false))); - } - if (event.getStage() == RenderLevelStageEvent.Stage.AFTER_CUTOUT_BLOCKS) { RenderSystem.runAsFancy(() -> CorrodentRenderer.renderEntireBatch(event.getLevelRenderer(), event.getPoseStack(), event.getRenderTick(), event.getCamera(), event.getPartialTick().getGameTimeDeltaPartialTick(false))); @@ -311,43 +309,11 @@ public void postRenderStage(RenderLevelStageEvent event) { public void computeCameraAngles(ViewportEvent.ComputeCameraAngles event) { Entity player = Minecraft.getInstance().getCameraEntity(); float partialTick = Minecraft.getInstance().getTimer().getGameTimeDeltaPartialTick(false); - float tremorAmount = ClientProxy.renderNukeSkyDarkFor > 0 ? 1.5F : 0F; if (player instanceof PossessesCamera watcherEntity) { Minecraft.getInstance().options.setCameraType(CameraType.FIRST_PERSON); - tremorAmount = watcherEntity.isPossessionBreakable() - ? AlexsCaves.PROXY.getPossessionStrengthAmount(partialTick) - : 0F; - } - if (player != null && AlexsCaves.CLIENT_CONFIG.screenShaking.get()) { - double shakeDistanceScale = 64; - double distance = Double.MAX_VALUE; - if (tremorAmount == 0) { - AABB aabb = player.getBoundingBox().inflate(shakeDistanceScale); - for (Mob screenShaker : Minecraft.getInstance().level.getEntitiesOfClass(Mob.class, aabb, - (mob -> mob instanceof ShakesScreen))) { - ShakesScreen shakesScreen = (ShakesScreen) screenShaker; - if (shakesScreen.canFeelShake(player) && screenShaker.distanceTo(player) < distance) { - distance = screenShaker.distanceTo(player); - tremorAmount = Math.min((1F - (float) Math.min(1, distance / shakesScreen.getShakeDistance())) - * Math.max(shakesScreen.getScreenShakeAmount(partialTick), 0F), 2.0F); - } - } - } - 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.lastTremorTick = player.tickCount; - } - float intensity = (float)(tremorAmount * Minecraft.getInstance().options.screenEffectScale().get()); - ((CameraAccessor) event.getCamera()).invokeMove( - ClientProxy.randomTremorOffsets[0] * 0.2F * intensity, - ClientProxy.randomTremorOffsets[1] * 0.2F * intensity, - ClientProxy.randomTremorOffsets[2] * 0.5F * intensity); - } } + // Screen shake logic has been moved to CameraMixin because ComputeCameraAngles + // event fires BEFORE setPosition() in Camera.setup(), causing move() effects to be overwritten if (player != null && player.isPassenger() && player.getVehicle() instanceof SubmarineEntity && event.getCamera().isDetached()) { CameraAccessor cameraAccessor = (CameraAccessor) event.getCamera(); @@ -701,7 +667,7 @@ public void onPoseHand(EventPosePlayerHand event) { public void onPostRenderGuiOverlay(RenderGuiLayerEvent.Post event) { Player player = AlexsCaves.PROXY.getClientSidePlayer(); int hudY = 0; - if (event.getName().equals(VanillaGuiLayers.CROSSHAIR) && player.getVehicle() instanceof RidingMeterMount mount + if (event.getName().equals(VanillaGuiLayers.HOTBAR) && player.getVehicle() instanceof RidingMeterMount mount && mount.hasRidingMeter()) { int screenWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight(); @@ -755,7 +721,7 @@ public void onPostRenderGuiOverlay(RenderGuiLayerEvent.Post event) { (int) Math.floor(dinoHeight * invProgress), 128, 512); event.getGuiGraphics().pose().popPose(); } - if (event.getName().equals(VanillaGuiLayers.CROSSHAIR) && DarknessArmorItem.hasMeter(player)) { + if (event.getName().equals(VanillaGuiLayers.HOTBAR) && DarknessArmorItem.hasMeter(player)) { ItemStack stack = player.getItemBySlot(EquipmentSlot.CHEST); int screenWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight(); @@ -1123,6 +1089,8 @@ private Vec3 calculateBiomeWaterFogColor(Entity player) { public void onClientTick(ClientTickEvent.Post event) { Entity cameraEntity = Minecraft.getInstance().cameraEntity; float partialTicks = AlexsCaves.PROXY.getPartialTicks(); + // Tick down bubbled effect visual timers + ClientProxy.tickBubbledEffects(); if (ClientProxy.shaderLoadAttemptCooldown > 0) { ClientProxy.shaderLoadAttemptCooldown--; } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/CaveBookScreen.java b/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/CaveBookScreen.java index 735f0d722..e1a4d3b79 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/CaveBookScreen.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/CaveBookScreen.java @@ -12,8 +12,8 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.OverlayTexture; +import net.neoforged.neoforge.client.NeoForgeRenderTypes; import net.minecraft.client.resources.sounds.SimpleSoundInstance; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import net.neoforged.neoforge.common.NeoForge; public class CaveBookScreen extends Screen { @@ -36,10 +35,10 @@ public class CaveBookScreen extends Screen { public static final float MOUSE_LEAN_THRESHOLD = 0.75F; public static final int PAGE_SIZE_IN_LINES = 15; - public static final int TEXT_COLOR = 0X5A4830; + public static final int TEXT_COLOR = 0X826A41; public static final int TEXT_LINK_COLOR = 0X111111; public static final int TEXT_LINK_HOVER_COLOR = 0X0094FF; - public static final int TEXT_LINK_LOCKED_COLOR = 0XA09078; + public static final int TEXT_LINK_LOCKED_COLOR = 0XD3C9AB; private final CaveBookProgress caveBookProgress; public boolean unlockTooltip; private boolean incrementingPage; @@ -243,7 +242,7 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float fakePa poseStack.pushPose(); BOOK_MODEL.setupAnim(null, openBookAmount, pageAngle, pageUp, -20 * (openBookAmount) - 10 * pageFlipBump, 0); BOOK_MODEL.mouseOver(mouseLeanX, mouseLeanY, ageInTicks, flip, canGoLeft(), canGoRight()); - BOOK_MODEL.renderToBuffer(poseStack, bufferSource.getBuffer(RenderType.entityTranslucent(BOOK_TEXTURE)), 240, OverlayTexture.NO_OVERLAY, -1); + BOOK_MODEL.renderToBuffer(poseStack, bufferSource.getBuffer(NeoForgeRenderTypes.getUnlitTranslucent(BOOK_TEXTURE)), 240, OverlayTexture.NO_OVERLAY, -1); renderBookContents(poseStack, mouseX, mouseY, partialTick); guiGraphics.flush(); poseStack.popPose(); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/widget/CraftingRecipeWidget.java b/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/widget/CraftingRecipeWidget.java index e8a507f3b..01e8b1ecd 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/widget/CraftingRecipeWidget.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/widget/CraftingRecipeWidget.java @@ -67,9 +67,9 @@ public void render(PoseStack poseStack, MultiBufferSource.BufferSource bufferSou float texWidth = 55 / 2F; float texHeight = 37 / 2F; vertexconsumer.addVertex(matrix4f, -texWidth, -texHeight, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(0, 0).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); - vertexconsumer.addVertex(matrix4f, texWidth, -texHeight, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU1, 0).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F).setUv(0, scaledV1); - vertexconsumer.addVertex(matrix4f, texWidth, texHeight, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU1, scaledV1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F).setUv(0, 0); - vertexconsumer.addVertex(matrix4f, -texWidth, texHeight, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(0, scaledV1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F).setUv(scaledU1, 0); + vertexconsumer.addVertex(matrix4f, texWidth, -texHeight, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU1, 0).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + vertexconsumer.addVertex(matrix4f, texWidth, texHeight, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU1, scaledV1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + vertexconsumer.addVertex(matrix4f, -texWidth, texHeight, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(0, scaledV1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); poseStack.popPose(); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/widget/EntityBoxWidget.java b/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/widget/EntityBoxWidget.java index ef9593068..44b100356 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/widget/EntityBoxWidget.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/gui/book/widget/EntityBoxWidget.java @@ -120,8 +120,8 @@ private void renderQuad(PoseStack poseStack, VertexConsumer vertexconsumer, floa float scaledV1 = v1 / (float)BORDER_TEXTURE_SIZE; vertexconsumer.addVertex(matrix4f, x0, y0, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU1, scaledV0).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); - vertexconsumer.addVertex(matrix4f, x1, y0, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU0, scaledV0).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F).setUv(scaledU0, scaledV1); - vertexconsumer.addVertex(matrix4f, x1, y1, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU0, scaledV1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F).setUv(scaledU0, scaledV0); - vertexconsumer.addVertex(matrix4f, x0, y1, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU1, scaledV1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F).setUv(scaledU1, scaledV0); + vertexconsumer.addVertex(matrix4f, x1, y0, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU0, scaledV0).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + vertexconsumer.addVertex(matrix4f, x1, y1, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU0, scaledV1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + vertexconsumer.addVertex(matrix4f, x0, y1, 0.0F).setColor(1.0F, 1.0F, 1.0F, 1.0F).setUv(scaledU1, scaledV1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/model/SauropodBaseModel.java b/src/main/java/com/github/alexmodguy/alexscaves/client/model/SauropodBaseModel.java index 45f0b9d79..7217d4d0d 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/model/SauropodBaseModel.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/model/SauropodBaseModel.java @@ -365,7 +365,9 @@ public void setupAnim(SauropodBaseEntity entity, float limbSwing, float limbSwin float danceAmount = entity.getDanceProgress(partialTicks); float buryEggsAmount = entity.getBuryEggsProgress(partialTicks); positionNeckAndTail(entity, netHeadYaw, headPitch, partialTicks); - articulateLegs(entity.legSolver, raiseArmsAmount, partialTicks); + if (!straighten) { + articulateLegs(entity.legSolver, raiseArmsAmount, partialTicks); + } if (buryEggsAmount > 0.0F) { limbSwing = ageInTicks; limbSwingAmount = buryEggsAmount * 0.5F; diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/particle/RainbowParticle.java b/src/main/java/com/github/alexmodguy/alexscaves/client/particle/RainbowParticle.java index fe26051bd..5fe8de7a2 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/particle/RainbowParticle.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/particle/RainbowParticle.java @@ -29,7 +29,7 @@ public class RainbowParticle extends Particle { public static final ParticleGroup PARTICLE_GROUP = new ParticleGroup(100); - private static final RenderType RAINBOW_RENDER_TYPE = ACRenderTypes.getTeslaBulb(ResourceLocation.fromNamespaceAndPath(AlexsCaves.MODID, "textures/particle/rainbow.png")); + private static final RenderType RAINBOW_RENDER_TYPE = ACRenderTypes.getRainbow(ResourceLocation.fromNamespaceAndPath(AlexsCaves.MODID, "textures/particle/rainbow.png")); public int rainbowVecCount = 64; public int fadeSpeed = 15; public int fillSpeed = 40; diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/particle/StunStarParticle.java b/src/main/java/com/github/alexmodguy/alexscaves/client/particle/StunStarParticle.java index 0c5842916..c0a45617c 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/particle/StunStarParticle.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/particle/StunStarParticle.java @@ -1,7 +1,6 @@ package com.github.alexmodguy.alexscaves.client.particle; import com.github.alexmodguy.alexscaves.AlexsCaves; -import com.github.alexmodguy.alexscaves.client.render.ACRenderTypes; import com.github.alexmodguy.alexscaves.server.entity.living.SauropodBaseEntity; import com.github.alexmodguy.alexscaves.server.potion.ACEffectRegistry; import com.mojang.blaze3d.vertex.PoseStack; @@ -13,9 +12,9 @@ import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.ParticleProvider; import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; import net.minecraft.core.particles.SimpleParticleType; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.FastColor; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; @@ -77,7 +76,7 @@ public void render(VertexConsumer vertexConsumer, Camera camera, float partialTi } MultiBufferSource.BufferSource multibuffersource$buffersource = Minecraft.getInstance().renderBuffers().bufferSource(); - VertexConsumer vertexconsumer = multibuffersource$buffersource.getBuffer(ACRenderTypes.itemEntityTranslucentCull(CENTER_TEXTURE)); + VertexConsumer vertexconsumer = multibuffersource$buffersource.getBuffer(RenderType.entityTranslucent(CENTER_TEXTURE)); Vector3f vector3f1 = new Vector3f(-1.0F, -1.0F, 0.0F); vector3f1.rotate(quaternion); @@ -100,11 +99,10 @@ public void render(VertexConsumer vertexConsumer, Camera camera, float partialTi PoseStack.Pose posestack$pose = posestack.last(); Matrix4f matrix4f = posestack$pose.pose(); Matrix3f matrix3f = posestack$pose.normal(); - int packedColor = FastColor.ARGB32.color((int)(alpha * 255), (int)(this.rCol * 255), (int)(this.gCol * 255), (int)(this.bCol * 255)); - vertexconsumer.addVertex(avector3f[0].x(), avector3f[0].y(), avector3f[0].z()).setColor(packedColor).setUv(f8, f6).setOverlay(NO_OVERLAY).setLight(j).setNormal(0.0F, 1.0F, 0.0F); - vertexconsumer.addVertex(avector3f[1].x(), avector3f[1].y(), avector3f[1].z()).setColor(packedColor).setUv(f8, f5).setOverlay(NO_OVERLAY).setLight(j).setNormal(0.0F, 1.0F, 0.0F); - vertexconsumer.addVertex(avector3f[2].x(), avector3f[2].y(), avector3f[2].z()).setColor(packedColor).setUv(f7, f5).setOverlay(NO_OVERLAY).setLight(j).setNormal(0.0F, 1.0F, 0.0F); - vertexconsumer.addVertex(avector3f[3].x(), avector3f[3].y(), avector3f[3].z()).setColor(packedColor).setUv(f7, f6).setOverlay(NO_OVERLAY).setLight(j).setNormal(0.0F, 1.0F, 0.0F); + vertexconsumer.addVertex(avector3f[0].x(), avector3f[0].y(), avector3f[0].z()).setColor(this.rCol, this.gCol, this.bCol, alpha).setUv(f8, f6).setOverlay(NO_OVERLAY).setLight(j).setNormal(0.0F, 1.0F, 0.0F); + vertexconsumer.addVertex(avector3f[1].x(), avector3f[1].y(), avector3f[1].z()).setColor(this.rCol, this.gCol, this.bCol, alpha).setUv(f8, f5).setOverlay(NO_OVERLAY).setLight(j).setNormal(0.0F, 1.0F, 0.0F); + vertexconsumer.addVertex(avector3f[2].x(), avector3f[2].y(), avector3f[2].z()).setColor(this.rCol, this.gCol, this.bCol, alpha).setUv(f7, f5).setOverlay(NO_OVERLAY).setLight(j).setNormal(0.0F, 1.0F, 0.0F); + vertexconsumer.addVertex(avector3f[3].x(), avector3f[3].y(), avector3f[3].z()).setColor(this.rCol, this.gCol, this.bCol, alpha).setUv(f7, f6).setOverlay(NO_OVERLAY).setLight(j).setNormal(0.0F, 1.0F, 0.0F); multibuffersource$buffersource.endBatch(); super.render(vertexConsumer, camera, partialTick); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/particle/WatcherAppearanceParticle.java b/src/main/java/com/github/alexmodguy/alexscaves/client/particle/WatcherAppearanceParticle.java index 1fd68ded8..59aee9135 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/particle/WatcherAppearanceParticle.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/particle/WatcherAppearanceParticle.java @@ -2,7 +2,6 @@ import com.github.alexmodguy.alexscaves.AlexsCaves; import com.github.alexmodguy.alexscaves.client.model.WatcherModel; -import com.github.alexmodguy.alexscaves.client.render.ColorUtil; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; @@ -18,11 +17,13 @@ import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.core.particles.SimpleParticleType; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FastColor; import net.minecraft.util.Mth; public class WatcherAppearanceParticle extends Particle { private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(AlexsCaves.MODID, "textures/entity/watcher_appearance.png"); private final WatcherModel model = new WatcherModel(); + private final RenderType renderType = RenderType.entityTranslucent(TEXTURE); private WatcherAppearanceParticle(ClientLevel lvl, double x, double y, double z) { super(lvl, x, y, z); @@ -42,17 +43,23 @@ public void render(VertexConsumer vertexConsumer, Camera camera, float partialTi float f = (age - 5) / (float) (this.lifetime - 5); float initalFlip = Math.min(f, 0.1F) / 0.1F; float scale = 1; + float alpha = Mth.clamp(1 - f * f, 0F, 1F); + int color = FastColor.ARGB32.colorFromFloat(alpha, 1.0F, 1.0F, 1.0F); + PoseStack posestack = new PoseStack(); + posestack.pushPose(); posestack.mulPose(camera.rotation()); + posestack.mulPose(Axis.YP.rotationDegrees(180F)); posestack.translate(0.0D, 0F, -1.2F); - posestack.mulPose(Axis.XP.rotationDegrees(0F)); posestack.scale(-scale, -scale, scale); posestack.translate(0.0D, 0.5F, 2 + (1F - initalFlip)); + MultiBufferSource.BufferSource multibuffersource$buffersource = Minecraft.getInstance().renderBuffers().bufferSource(); - VertexConsumer vertexconsumer = multibuffersource$buffersource.getBuffer(RenderType.entityTranslucent(TEXTURE)); + VertexConsumer vertexconsumer = multibuffersource$buffersource.getBuffer(this.renderType); this.model.positionForParticle(partialTick, age); - this.model.renderToBuffer(posestack, vertexconsumer, 240, OverlayTexture.NO_OVERLAY, ColorUtil.packColor(1.0F, 1.0F, 1.0F, Mth.clamp(1 - f * f, 0F, 1F))); + this.model.renderToBuffer(posestack, vertexconsumer, 240, OverlayTexture.NO_OVERLAY, color); multibuffersource$buffersource.endBatch(); + posestack.popPose(); RenderSystem.setShaderFogEnd(fogBefore); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/ACRenderTypes.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/ACRenderTypes.java index 1d4b5e6d6..f8481f775 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/ACRenderTypes.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/ACRenderTypes.java @@ -28,6 +28,8 @@ public class ACRenderTypes extends RenderType { if (target != null) { target.copyDepthFrom(Minecraft.getInstance().getMainRenderTarget()); target.bindWrite(false); + } else { + com.github.alexmodguy.alexscaves.AlexsCaves.LOGGER.warn("IRRADIATED_OUTPUT target is null!"); } }, () -> { Minecraft.getInstance().getMainRenderTarget().bindWrite(false); @@ -105,6 +107,7 @@ public static RenderType getHologramLights() { .setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY) .setCullState(CULL) .setDepthTestState(LEQUAL_DEPTH_TEST) + .setWriteMaskState(COLOR_WRITE) .setLightmapState(NO_LIGHTMAP) .setOutputState(HOLOGRAM_OUTPUT) .createCompositeState(false)); @@ -142,25 +145,31 @@ public static RenderType getGel(ResourceLocation locationIn) { } public static RenderType getRadiationGlow(ResourceLocation locationIn) { - return create("radiation_glow", DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS, 256, false, true, RenderType.CompositeState.builder() + // Use NEW_ENTITY format since model.renderToBuffer() outputs NEW_ENTITY vertices + return create("radiation_glow", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true, true, RenderType.CompositeState.builder() .setShaderState(RENDERTYPE_IRRADIATED_SHADER) .setCullState(NO_CULL) .setTextureState(new RenderStateShard.TextureStateShard(locationIn, false, false)) .setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY) + .setLightmapState(LIGHTMAP) + .setOverlayState(OVERLAY) .setDepthTestState(LEQUAL_DEPTH_TEST) .setOutputState(IRRADIATED_OUTPUT) - .createCompositeState(false)); + .createCompositeState(true)); } public static RenderType getBlueRadiationGlow(ResourceLocation locationIn) { - return create("blue_radiation_glow", DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS, 256, false, true, RenderType.CompositeState.builder() + // Use NEW_ENTITY format since model.renderToBuffer() outputs NEW_ENTITY vertices + return create("blue_radiation_glow", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true, true, RenderType.CompositeState.builder() .setShaderState(RENDERTYPE_BLUE_IRRADIATED_SHADER) .setCullState(NO_CULL) .setTextureState(new RenderStateShard.TextureStateShard(locationIn, false, false)) .setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY) + .setLightmapState(LIGHTMAP) + .setOverlayState(OVERLAY) .setDepthTestState(LEQUAL_DEPTH_TEST) .setOutputState(IRRADIATED_OUTPUT) - .createCompositeState(false)); + .createCompositeState(true)); } public static RenderType getGelTriangles(ResourceLocation locationIn) { return create("ferrouslime_gel_triangles", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.TRIANGLES, 256, true, true, RenderType.CompositeState.builder() @@ -196,6 +205,11 @@ public static RenderType getTeslaBulb(ResourceLocation resourceLocation) { return create("tesla_bulb", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, RenderType.CompositeState.builder().setShaderState(RenderStateShard.RENDERTYPE_ENERGY_SWIRL_SHADER).setTextureState(new RenderStateShard.TextureStateShard(resourceLocation, false, true)).setLightmapState(LIGHTMAP).setCullState(RenderStateShard.NO_CULL).setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY).setDepthTestState(LEQUAL_DEPTH_TEST).createCompositeState(true)); } + public static RenderType getRainbow(ResourceLocation resourceLocation) { + // Use TRANSLUCENT_TRANSPARENCY like 1.20 for more solid rainbow appearance + return create("rainbow", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, RenderType.CompositeState.builder().setShaderState(RenderStateShard.RENDERTYPE_ENERGY_SWIRL_SHADER).setTextureState(new RenderStateShard.TextureStateShard(resourceLocation, false, true)).setLightmapState(LIGHTMAP).setCullState(RenderStateShard.NO_CULL).setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY).setDepthTestState(LEQUAL_DEPTH_TEST).createCompositeState(true)); + } + public static RenderType getHologram(ResourceLocation locationIn) { // In 1.21, use NEW_ENTITY format since model.renderToBuffer() outputs NEW_ENTITY vertices // Use RENDERTYPE_ENTITY_TRANSLUCENT_SHADER which is compatible with NEW_ENTITY format @@ -219,6 +233,7 @@ public static RenderType getRedGhost(ResourceLocation locationIn) { .setCullState(NO_CULL) .setTextureState(new RenderStateShard.TextureStateShard(locationIn, false, false)) .setTransparencyState(EYES_ALPHA_TRANSPARENCY) + .setLightmapState(LIGHTMAP) .setWriteMaskState(COLOR_DEPTH_WRITE) .setDepthTestState(LEQUAL_DEPTH_TEST) .setOverlayState(OVERLAY) @@ -243,6 +258,7 @@ public static RenderType getBookWidget(ResourceLocation locationIn, boolean sepi .setCullState(NO_CULL) .setTextureState(new RenderStateShard.TextureStateShard(locationIn, false, false)) .setTransparencyState(RenderStateShard.TRANSLUCENT_TRANSPARENCY) + .setLightmapState(LIGHTMAP) .setOverlayState(OVERLAY) .createCompositeState(true)); }else{ @@ -252,12 +268,12 @@ public static RenderType getBookWidget(ResourceLocation locationIn, boolean sepi } public static RenderType getBubbledCull(ResourceLocation locationIn) { - RenderType.CompositeState rendertype$compositestate = RenderType.CompositeState.builder().setShaderState(RENDERTYPE_BUBBLED_SHADER).setTextureState(new RenderStateShard.TextureStateShard(locationIn, false, false)).setTransparencyState(TRANSLUCENT_TRANSPARENCY).setLightmapState(LIGHTMAP).setOutputState(RenderStateShard.ITEM_ENTITY_TARGET).setOverlayState(OVERLAY).setWriteMaskState(RenderStateShard.COLOR_DEPTH_WRITE).createCompositeState(true); + RenderType.CompositeState rendertype$compositestate = RenderType.CompositeState.builder().setShaderState(RENDERTYPE_BUBBLED_SHADER).setTextureState(new RenderStateShard.TextureStateShard(locationIn, false, false)).setTransparencyState(TRANSLUCENT_TRANSPARENCY).setLightmapState(LIGHTMAP).setOutputState(RenderStateShard.ITEM_ENTITY_TARGET).setOverlayState(OVERLAY).setWriteMaskState(RenderStateShard.COLOR_WRITE).createCompositeState(true); return create("bubbled_cull", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, true, true, rendertype$compositestate); } public static RenderType getBubbledNoCull(ResourceLocation locationIn) { - RenderType.CompositeState rendertype$compositestate = RenderType.CompositeState.builder().setShaderState(RENDERTYPE_BUBBLED_SHADER).setTextureState(new RenderStateShard.TextureStateShard(locationIn, false, false)).setTransparencyState(TRANSLUCENT_TRANSPARENCY).setCullState(NO_CULL).setLightmapState(LIGHTMAP).setOutputState(RenderStateShard.ITEM_ENTITY_TARGET).setOverlayState(OVERLAY).setWriteMaskState(RenderStateShard.COLOR_DEPTH_WRITE).createCompositeState(true); + RenderType.CompositeState rendertype$compositestate = RenderType.CompositeState.builder().setShaderState(RENDERTYPE_BUBBLED_SHADER).setTextureState(new RenderStateShard.TextureStateShard(locationIn, false, false)).setTransparencyState(TRANSLUCENT_TRANSPARENCY).setCullState(NO_CULL).setLightmapState(LIGHTMAP).setOutputState(RenderStateShard.ITEM_ENTITY_TARGET).setOverlayState(OVERLAY).setWriteMaskState(RenderStateShard.COLOR_WRITE).createCompositeState(true); return create("bubbled_no_cull", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, false, rendertype$compositestate); } @@ -294,4 +310,16 @@ public static RenderType getPurpleWitch(ResourceLocation locationIn) { .createCompositeState(false)); } + public static RenderType getWatcherAppearance(ResourceLocation locationIn) { + RenderType.CompositeState rendertype$compositestate = RenderType.CompositeState.builder() + .setShaderState(RENDERTYPE_ENTITY_TRANSLUCENT_CULL_SHADER) + .setTextureState(new RenderStateShard.TextureStateShard(locationIn, false, false)) + .setTransparencyState(TRANSLUCENT_TRANSPARENCY) + .setCullState(NO_CULL) + .setLightmapState(NO_LIGHTMAP) + .setOverlayState(OVERLAY) + .createCompositeState(true); + return create("watcher_appearance", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, 256, false, true, rendertype$compositestate); + } + } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/AmbersolBlockRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/AmbersolBlockRenderer.java index 491881db1..71b35207d 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/AmbersolBlockRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/AmbersolBlockRenderer.java @@ -100,32 +100,30 @@ private static void renderAt(AmbersolBlockEntity ambersol, float partialTicks, P matrixStackIn.mulPose(Axis.ZN.rotationDegrees(time1 - (i / (float) lights * 360))); PoseStack.Pose posestack$pose = matrixStackIn.last(); Matrix4f matrix4f = posestack$pose.pose(); - Matrix3f matrix3f = posestack$pose.normal(); - shineOriginVertex(lightConsumer, matrix4f, matrix3f, j, u, v); - shineLeftCornerVertex(lightConsumer, matrix4f, matrix3f, length, width, u, v); - shineRightCornerVertex(lightConsumer, matrix4f, matrix3f, length, width, u, v); - shineLeftCornerVertex(lightConsumer, matrix4f, matrix3f, length, width, u, v); + shineOriginVertex(lightConsumer, matrix4f, j, u, v); + shineLeftCornerVertex(lightConsumer, matrix4f, length, width, u, v); + shineRightCornerVertex(lightConsumer, matrix4f, length, width, u, v); + shineLeftCornerVertex(lightConsumer, matrix4f, length, width, u, v); matrixStackIn.popPose(); } //minecrafts janky render system wont do transparent blocks unless you render a selection box behind it. PoseStack.Pose posestack$pose = matrixStackIn.last(); Matrix4f matrix4f = posestack$pose.pose(); - Matrix3f matrix3f = posestack$pose.normal(); VertexConsumer lines = bufferIn.getBuffer(RenderType.lines()); matrixStackIn.popPose(); } } - private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, Matrix3f p_114092_, int p_114222_, float xOffset, float yOffset) { - p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(SHINE_CENTER_R, SHINE_CENTER_G, SHINE_CENTER_B, 230).setUv(xOffset + 0.5F, yOffset).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, int p_114222_, float xOffset, float yOffset) { + p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(SHINE_CENTER_R, SHINE_CENTER_G, SHINE_CENTER_B, 230); } - private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, Matrix3f p_114092_, float p_114217_, float p_114218_, float xOffset, float yOffset) { - p_114215_.addVertex(p_114216_, -HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(SHINE_R, SHINE_G, SHINE_B, 0).setUv(xOffset, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, float p_114217_, float p_114218_, float xOffset, float yOffset) { + p_114215_.addVertex(p_114216_, -HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(SHINE_R, SHINE_G, SHINE_B, 0); } - private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, Matrix3f p_114092_, float p_114226_, float p_114227_, float xOffset, float yOffset) { - p_114224_.addVertex(p_114225_, HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(SHINE_R, SHINE_G, SHINE_B, 0).setUv(xOffset + 1, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, float p_114226_, float p_114227_, float xOffset, float yOffset) { + p_114224_.addVertex(p_114225_, HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(SHINE_R, SHINE_G, SHINE_B, 0); } public int getViewDistance() { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/ConversionCrucibleBlockRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/ConversionCrucibleBlockRenderer.java index d2f57116b..1b58b6655 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/ConversionCrucibleBlockRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/ConversionCrucibleBlockRenderer.java @@ -129,12 +129,11 @@ public void render(T crucible, float partialTicks, PoseStack poseStack, MultiBuf poseStack.mulPose(Axis.YP.rotationDegrees(180 - cameraY)); PoseStack.Pose posestack$pose1 = poseStack.last(); Matrix4f matrix4f2 = posestack$pose1.pose(); - Matrix3f matrix3f2 = posestack$pose1.normal(); VertexConsumer lightConsumer = bufferIn.getBuffer(ACRenderTypes.getCrucibleItemBeam()); - shineOriginVertex(lightConsumer, matrix4f2, matrix3f2, 0, 0, r, g, b, 12 * showItemProgress); - shineLeftCornerVertex(lightConsumer, matrix4f2, matrix3f2, lightLength, lightWidth, 0, 0, r, g, b, 0); - shineRightCornerVertex(lightConsumer, matrix4f2, matrix3f2, lightLength, lightWidth, 0, 0, r, g, b, 0); - shineLeftCornerVertex(lightConsumer, matrix4f2, matrix3f2, lightLength, lightWidth, 0, 0, r, g, b, 0); + shineOriginVertex(lightConsumer, matrix4f2, 0, 0, r, g, b, 12 * showItemProgress); + shineLeftCornerVertex(lightConsumer, matrix4f2, lightLength, lightWidth, 0, 0, r, g, b, 0); + shineRightCornerVertex(lightConsumer, matrix4f2, lightLength, lightWidth, 0, 0, r, g, b, 0); + shineLeftCornerVertex(lightConsumer, matrix4f2, lightLength, lightWidth, 0, 0, r, g, b, 0); poseStack.popPose(); } } @@ -165,16 +164,16 @@ private static void renderQuadList(PoseStack.Pose p_111059_, VertexConsumer p_11 } - private static void shineOriginVertex(VertexConsumer vertexConsumer, Matrix4f matrix4f, Matrix3f matrix3f, float xOffset, float yOffset, float r, float g, float b, float a) { - vertexConsumer.addVertex(matrix4f, 0.0F, 0.0F, 0.0F).setColor(r, g, b, a).setUv(xOffset + 0.5F, yOffset).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + private static void shineOriginVertex(VertexConsumer vertexConsumer, Matrix4f matrix4f, float xOffset, float yOffset, float r, float g, float b, float a) { + vertexConsumer.addVertex(matrix4f, 0.0F, 0.0F, 0.0F).setColor(r, g, b, a); } - private static void shineLeftCornerVertex(VertexConsumer vertexConsumer, Matrix4f matrix4f, Matrix3f matrix3f, float length, float width, float xOffset, float yOffset, float r, float g, float b, float a) { - vertexConsumer.addVertex(matrix4f, -ACMath.HALF_SQRT_3 * width, length, 0).setColor(r, g, b, a).setUv(xOffset, yOffset + 1).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineLeftCornerVertex(VertexConsumer vertexConsumer, Matrix4f matrix4f, float length, float width, float xOffset, float yOffset, float r, float g, float b, float a) { + vertexConsumer.addVertex(matrix4f, -ACMath.HALF_SQRT_3 * width, length, 0).setColor(r, g, b, a); } - private static void shineRightCornerVertex(VertexConsumer vertexConsumer, Matrix4f matrix4f, Matrix3f matrix3f, float length, float width, float xOffset, float yOffset, float r, float g, float b, float a) { - vertexConsumer.addVertex(matrix4f, ACMath.HALF_SQRT_3 * width, length, 0).setColor(r, g, b, a).setUv(xOffset + 1, yOffset + 1).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineRightCornerVertex(VertexConsumer vertexConsumer, Matrix4f matrix4f, float length, float width, float xOffset, float yOffset, float r, float g, float b, float a) { + vertexConsumer.addVertex(matrix4f, ACMath.HALF_SQRT_3 * width, length, 0).setColor(r, g, b, a); } public int getViewDistance() { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/HologramProjectorBlockRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/HologramProjectorBlockRenderer.java index 9b3ba1bd9..6a2ee23d1 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/HologramProjectorBlockRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/HologramProjectorBlockRenderer.java @@ -104,22 +104,20 @@ private static void renderAt(HologramProjectorBlockEntity projectorBlockEntity, float cameraY = Minecraft.getInstance().getEntityRenderDispatcher().camera.getYRot(); PoseStack.Pose posestack$pose = poseStack.last(); Matrix4f matrix4f1 = posestack$pose.pose(); - Matrix3f matrix3f1 = posestack$pose.normal(); - lightConsumer.addVertex(matrix4f1, padStart, 0.0F, padEnd).setColor(220, 220, 255, (int) (amount * 150)).setUv(0.0F, 1.0F).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); - lightConsumer.addVertex(matrix4f1, padEnd, 0.0F, padEnd).setColor(220, 220, 255, (int) (amount * 150)).setUv(1.0F, 1.0F).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); - lightConsumer.addVertex(matrix4f1, padEnd, 0.0F, padStart).setColor(220, 220, 255, (int) (amount * 150)).setUv(1.0F, 0.0F).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); - lightConsumer.addVertex(matrix4f1, padStart, 0.0F, padStart).setColor(220, 220, 255, (int) (amount * 150)).setUv(0.0F, 0.0F).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + lightConsumer.addVertex(matrix4f1, padStart, 0.0F, padEnd).setColor(220, 220, 255, (int) (amount * 150)); + lightConsumer.addVertex(matrix4f1, padEnd, 0.0F, padEnd).setColor(220, 220, 255, (int) (amount * 150)); + lightConsumer.addVertex(matrix4f1, padEnd, 0.0F, padStart).setColor(220, 220, 255, (int) (amount * 150)); + lightConsumer.addVertex(matrix4f1, padStart, 0.0F, padStart).setColor(220, 220, 255, (int) (amount * 150)); poseStack.popPose(); poseStack.pushPose(); poseStack.translate(0F, -0.2F, 0F); poseStack.mulPose(Axis.YP.rotationDegrees(180 - cameraY)); PoseStack.Pose posestack$pose1 = poseStack.last(); Matrix4f matrix4f2 = posestack$pose1.pose(); - Matrix3f matrix3f2 = posestack$pose1.normal(); - shineOriginVertex(lightConsumer, matrix4f2, matrix3f2, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f2, matrix3f2, length, width, 0, 0); - shineRightCornerVertex(lightConsumer, matrix4f2, matrix3f2, length, width, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f2, matrix3f2, length, width, 0, 0); + shineOriginVertex(lightConsumer, matrix4f2, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f2, length, width, 0, 0); + shineRightCornerVertex(lightConsumer, matrix4f2, length, width, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f2, length, width, 0, 0); if (projectorBlockEntity.isPlayerRender()) { poseStack.pushPose(); poseStack.scale(1, amount, 1); @@ -185,16 +183,16 @@ private static void renderPlayerHologram(UUID lastPlayerUUID, float partialTicks } - private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, Matrix3f p_114092_, float xOffset, float yOffset) { - p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(255, 255, 255, 230).setUv(xOffset + 0.5F, yOffset).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, float xOffset, float yOffset) { + p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(255, 255, 255, 230); } - private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, Matrix3f p_114092_, float p_114217_, float p_114218_, float xOffset, float yOffset) { - p_114215_.addVertex(p_114216_, -ACMath.HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(0, 0, 255, 0).setUv(xOffset, yOffset + 1).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, float p_114217_, float p_114218_, float xOffset, float yOffset) { + p_114215_.addVertex(p_114216_, -ACMath.HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(0, 0, 255, 0); } - private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, Matrix3f p_114092_, float p_114226_, float p_114227_, float xOffset, float yOffset) { - p_114224_.addVertex(p_114225_, ACMath.HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(0, 0, 255, 0).setUv(xOffset + 1, yOffset + 1).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, float p_114226_, float p_114227_, float xOffset, float yOffset) { + p_114224_.addVertex(p_114225_, ACMath.HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(0, 0, 255, 0); } public int getViewDistance() { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/SirenLightBlockRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/SirenLightBlockRenderer.java index 36138f8cb..591db673c 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/SirenLightBlockRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/blockentity/SirenLightBlockRenderer.java @@ -70,19 +70,17 @@ public void render(T light, float partialTicks, PoseStack poseStack, MultiBuffer poseStack.mulPose(Axis.ZN.rotationDegrees(90)); PoseStack.Pose posestack$pose = poseStack.last(); Matrix4f matrix4f1 = posestack$pose.pose(); - Matrix3f matrix3f1 = posestack$pose.normal(); VertexConsumer lightConsumer = bufferIn.getBuffer(ACRenderTypes.getNucleeperLights()); - shineOriginVertex(lightConsumer, matrix4f1, matrix3f1, 0, 0, r, g, b); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0, r, g, b); - shineRightCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0, r, g, b); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0, r, g, b); + shineOriginVertex(lightConsumer, matrix4f1, 0, 0, r, g, b); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0, r, g, b); + shineRightCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0, r, g, b); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0, r, g, b); Matrix4f matrix4f2 = posestack$pose.pose(); - Matrix3f matrix3f2 = posestack$pose.normal(); poseStack.mulPose(Axis.ZN.rotationDegrees(180)); - shineOriginVertex(lightConsumer, matrix4f2, matrix3f2, 0, 0, r, g, b); - shineLeftCornerVertex(lightConsumer, matrix4f2, matrix3f2, length, width, 0, 0, r, g, b); - shineRightCornerVertex(lightConsumer, matrix4f2, matrix3f2, length, width, 0, 0, r, g, b); - shineLeftCornerVertex(lightConsumer, matrix4f2, matrix3f2, length, width, 0, 0, r, g, b); + shineOriginVertex(lightConsumer, matrix4f2, 0, 0, r, g, b); + shineLeftCornerVertex(lightConsumer, matrix4f2, length, width, 0, 0, r, g, b); + shineRightCornerVertex(lightConsumer, matrix4f2, length, width, 0, 0, r, g, b); + shineLeftCornerVertex(lightConsumer, matrix4f2, length, width, 0, 0, r, g, b); poseStack.popPose(); poseStack.popPose(); @@ -91,16 +89,16 @@ public void render(T light, float partialTicks, PoseStack poseStack, MultiBuffer poseStack.popPose(); } - private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, Matrix3f p_114092_, float xOffset, float yOffset, float r, float g, float b) { - p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(r, g, b, 1).setUv(xOffset + 0.5F, yOffset).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, float xOffset, float yOffset, float r, float g, float b) { + p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(r, g, b, 1); } - private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, Matrix3f p_114092_, float p_114217_, float p_114218_, float xOffset, float yOffset, float r, float g, float b) { - p_114215_.addVertex(p_114216_, -ACMath.HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(r, g, b, 0).setUv(xOffset, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, float p_114217_, float p_114218_, float xOffset, float yOffset, float r, float g, float b) { + p_114215_.addVertex(p_114216_, -ACMath.HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(r, g, b, 0); } - private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, Matrix3f p_114092_, float p_114226_, float p_114227_, float xOffset, float yOffset, float r, float g, float b) { - p_114224_.addVertex(p_114225_, ACMath.HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(r, g, b, 0).setUv(xOffset + 1, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, float p_114226_, float p_114227_, float xOffset, float yOffset, float r, float g, float b) { + p_114224_.addVertex(p_114225_, ACMath.HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(r, g, b, 0); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/CorrodentRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/CorrodentRenderer.java index 7ccd87485..c10ae5da1 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/CorrodentRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/CorrodentRenderer.java @@ -70,11 +70,12 @@ public static void renderEntireBatch(LevelRenderer levelRenderer, PoseStack pose poseStack.translate((double) pos.getX(), (double) pos.getY(), (double) pos.getZ()); PoseStack.Pose posestack$pose1 = poseStack.last(); VertexConsumer vertexconsumer1 = new SheetedDecalTextureGenerator(multibuffersource$buffersource.getBuffer(ModelBakery.DESTROY_TYPES.get(progress)), posestack$pose1, 1.0F); - net.neoforged.neoforge.client.model.data.ModelData modelData = Minecraft.getInstance().level.getModelDataManager().getAt(pos); - Minecraft.getInstance().getBlockRenderer().renderBreakingTexture(Minecraft.getInstance().level.getBlockState(pos), pos, Minecraft.getInstance().level, poseStack, vertexconsumer1, modelData == null ? net.neoforged.neoforge.client.model.data.ModelData.EMPTY : modelData); + net.neoforged.neoforge.client.model.data.ModelData modelData = Minecraft.getInstance().level.getModelData(pos); + Minecraft.getInstance().getBlockRenderer().renderBreakingTexture(Minecraft.getInstance().level.getBlockState(pos), pos, Minecraft.getInstance().level, poseStack, vertexconsumer1, modelData); poseStack.popPose(); } } + multibuffersource$buffersource.endBatch(); poseStack.popPose(); } allDugBlocksOnScreen.clear(); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumWormRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumWormRenderer.java index 016be2a24..bf273324c 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumWormRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumWormRenderer.java @@ -31,7 +31,8 @@ protected float getFlipDegrees(GumWormEntity entity) { return 0.0F; } - protected void setupRotations(GumWormEntity entity, PoseStack poseStack, float bob, float yawIn, float partialTicks) { + @Override + protected void setupRotations(GumWormEntity entity, PoseStack poseStack, float bob, float yawIn, float partialTicks, float scale) { if (this.isShaking(entity)) { yawIn += (float)(Math.cos((double)entity.tickCount * 3.25D) * Math.PI * (double)0.4F); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumWormSegmentRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumWormSegmentRenderer.java index 9a91f21be..220c7bcfb 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumWormSegmentRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumWormSegmentRenderer.java @@ -2,7 +2,6 @@ import com.github.alexmodguy.alexscaves.AlexsCaves; import com.github.alexmodguy.alexscaves.client.model.GumWormSegmentModel; -import com.github.alexmodguy.alexscaves.client.render.ColorUtil; import com.github.alexmodguy.alexscaves.server.entity.living.GumWormEntity; import com.github.alexmodguy.alexscaves.server.entity.living.GumWormSegmentEntity; import com.mojang.blaze3d.vertex.PoseStack; @@ -19,7 +18,6 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; -import org.joml.Matrix3f; import org.joml.Matrix4f; public class GumWormSegmentRenderer extends EntityRenderer { @@ -97,11 +95,10 @@ public static void renderGum(Vec3 to, PoseStack poseStack, VertexConsumer gumCon poseStack.translate(0, -length, 0); PoseStack.Pose posestack$pose = poseStack.last(); Matrix4f matrix4f = posestack$pose.pose(); - Matrix3f matrix3f = posestack$pose.normal(); - gumConsumer.addVertex(matrix4f, 0, 0, -0.5F).setColor(255, 255, 255, 255).setUv((float) 0, (float) 0).setOverlay(overlayCoords).setLight(packedLightIn).setNormal(0.0F, -1.0F, 0.0F); - gumConsumer.addVertex(matrix4f, 0, 0, 0.5F).setColor(255, 255, 255, 255).setUv((float) 1, (float) 0).setOverlay(overlayCoords).setLight(packedLightIn).setNormal(0.0F, -1.0F, 0.0F); - gumConsumer.addVertex(matrix4f, 0, length, 0.5F).setColor(255, 255, 255, 255).setUv((float) 1, (float)1).setOverlay(overlayCoords).setLight(packedLightIn).setNormal(0.0F, -1.0F, 0.0F); - gumConsumer.addVertex(matrix4f, 0, length, -0.5F).setColor(255, 255, 255, 255).setUv((float) 0, (float)1).setOverlay(overlayCoords).setLight(packedLightIn).setNormal(0.0F, -1.0F, 0.0F); + gumConsumer.addVertex(matrix4f, 0, 0, -0.5F).setColor(255, 255, 255, 255).setUv(0, 0).setOverlay(overlayCoords).setLight(packedLightIn).setNormal(0.0F, -1.0F, 0.0F); + gumConsumer.addVertex(matrix4f, 0, 0, 0.5F).setColor(255, 255, 255, 255).setUv(1, 0).setOverlay(overlayCoords).setLight(packedLightIn).setNormal(0.0F, -1.0F, 0.0F); + gumConsumer.addVertex(matrix4f, 0, length, 0.5F).setColor(255, 255, 255, 255).setUv(1, 1).setOverlay(overlayCoords).setLight(packedLightIn).setNormal(0.0F, -1.0F, 0.0F); + gumConsumer.addVertex(matrix4f, 0, length, -0.5F).setColor(255, 255, 255, 255).setUv(0, 1).setOverlay(overlayCoords).setLight(packedLightIn).setNormal(0.0F, -1.0F, 0.0F); poseStack.popPose(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumballRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumballRenderer.java index f0442575f..f4b8f0591 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumballRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/GumballRenderer.java @@ -16,6 +16,7 @@ import net.minecraft.world.entity.projectile.DragonFireball; import org.joml.Matrix3f; import org.joml.Matrix4f; +import org.joml.Vector3f; public class GumballRenderer extends EntityRenderer { private static final ResourceLocation TEXTURE_0 = ResourceLocation.fromNamespaceAndPath(AlexsCaves.MODID, "textures/entity/gumball/gumball_0.png"); @@ -45,7 +46,7 @@ public void render(GumballEntity entity, float entityYaw, float partialTicks, Po PoseStack.Pose posestack$pose = poseStack.last(); Matrix4f matrix4f = posestack$pose.pose(); Matrix3f matrix3f = posestack$pose.normal(); - VertexConsumer vertexconsumer = multiBufferSource.getBuffer(RenderType.entityCutout(getTextureLocation(entity))); + VertexConsumer vertexconsumer = multiBufferSource.getBuffer(RenderType.entityCutoutNoCull(getTextureLocation(entity))); vertex(vertexconsumer, matrix4f, matrix3f, packedLight, 0.0F, 0, 0, 1, 1F); vertex(vertexconsumer, matrix4f, matrix3f, packedLight, 1.0F, 0, 1, 1, 1F); vertex(vertexconsumer, matrix4f, matrix3f, packedLight, 1.0F, 1, 1, 0, 1F); @@ -63,7 +64,9 @@ public void render(GumballEntity entity, float entityYaw, float partialTicks, Po } private static void vertex(VertexConsumer vertexConsumer, Matrix4f matrix4f, Matrix3f matrix3f, int p_253829_, float x, int y, int u, int v, float alpha) { - vertexConsumer.addVertex(matrix4f, x - 0.5F, (float)y - 0.25F, 0.0F).setColor(1F, 1F, 1F, alpha).setUv((float)u, (float)v).setOverlay(OverlayTexture.NO_OVERLAY).setLight(p_253829_).setNormal(0.0F, 1.0F, 0.0F); + Vector3f vector3f = new Vector3f(0.0F, 1.0F, 0.0F); + vector3f.mul(matrix3f); + vertexConsumer.addVertex(matrix4f, x - 0.5F, (float)y - 0.25F, 0.0F).setColor(1F, 1F, 1F, alpha).setUv((float)u, (float)v).setOverlay(OverlayTexture.NO_OVERLAY).setLight(p_253829_).setNormal(vector3f.x, vector3f.y, vector3f.z); } public ResourceLocation getTextureLocation(GumballEntity gumballEntity) { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/MineGuardianRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/MineGuardianRenderer.java index 432db3c81..ac1774ff5 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/MineGuardianRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/MineGuardianRenderer.java @@ -42,16 +42,16 @@ public ResourceLocation getTextureLocation(MineGuardianEntity entity) { return entity.isEyeClosed() ? TEXTURE_SLEEPING : TEXTURE; } - private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, Matrix3f p_114092_, float xOffset, float yOffset) { - p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(230, 0, 0, 230).setUv(xOffset + 0.5F, yOffset).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, float xOffset, float yOffset) { + p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(230, 0, 0, 230); } - private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, Matrix3f p_114092_, float p_114217_, float p_114218_, float xOffset, float yOffset) { - p_114215_.addVertex(p_114216_, -ACMath.HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(255, 0, 0, 0).setUv(xOffset, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, float p_114217_, float p_114218_, float xOffset, float yOffset) { + p_114215_.addVertex(p_114216_, -ACMath.HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(255, 0, 0, 0); } - private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, Matrix3f p_114092_, float p_114226_, float p_114227_, float xOffset, float yOffset) { - p_114224_.addVertex(p_114225_, ACMath.HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(255, 0, 0, 0).setUv(xOffset + 1, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, float p_114226_, float p_114227_, float xOffset, float yOffset) { + p_114224_.addVertex(p_114225_, ACMath.HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(255, 0, 0, 0); } @@ -76,12 +76,11 @@ public void render(MineGuardianEntity entityIn, float entityYaw, float partialTi poseStack.translate(0F, -0.5F, 0F); PoseStack.Pose posestack$pose = poseStack.last(); Matrix4f matrix4f1 = posestack$pose.pose(); - Matrix3f matrix3f1 = posestack$pose.normal(); VertexConsumer lightConsumer = bufferIn.getBuffer(ACRenderTypes.getSubmarineLights()); - shineOriginVertex(lightConsumer, matrix4f1, matrix3f1, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); - shineRightCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); + shineOriginVertex(lightConsumer, matrix4f1, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); + shineRightCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); poseStack.popPose(); poseStack.popPose(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/NotorRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/NotorRenderer.java index c6ed444da..6d25b4cd7 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/NotorRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/NotorRenderer.java @@ -98,13 +98,12 @@ public void render(NotorEntity entity, float entityYaw, float partialTicks, Pose } PoseStack.Pose posestack$pose = poseStack.last(); Matrix4f matrix4f1 = posestack$pose.pose(); - Matrix3f matrix3f1 = posestack$pose.normal(); PostEffectRegistry.renderEffectForNextTick(ClientProxy.HOLOGRAM_SHADER); VertexConsumer lightConsumer = source.getBuffer(ACRenderTypes.getHologramLights()); - shineOriginVertex(lightConsumer, matrix4f1, matrix3f1, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); - shineRightCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); + shineOriginVertex(lightConsumer, matrix4f1, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); + shineRightCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); poseStack.popPose(); } } @@ -236,16 +235,16 @@ public static void renderEntityInHologram(E entityIn, double } } - private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, Matrix3f p_114092_, float xOffset, float yOffset) { - p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(255, 255, 255, 230).setUv(xOffset + 0.5F, yOffset).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, float xOffset, float yOffset) { + p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(255, 255, 255, 230); } - private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, Matrix3f p_114092_, float p_114217_, float p_114218_, float xOffset, float yOffset) { - p_114215_.addVertex(p_114216_, -ACMath.HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(0, 0, 255, 0).setUv(xOffset, yOffset + 1).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, float p_114217_, float p_114218_, float xOffset, float yOffset) { + p_114215_.addVertex(p_114216_, -ACMath.HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(0, 0, 255, 0); } - private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, Matrix3f p_114092_, float p_114226_, float p_114227_, float xOffset, float yOffset) { - p_114224_.addVertex(p_114225_, ACMath.HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(0, 0, 255, 0).setUv(xOffset + 1, yOffset + 1).setOverlay(OverlayTexture.NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, float p_114226_, float p_114227_, float xOffset, float yOffset) { + p_114224_.addVertex(p_114225_, ACMath.HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(0, 0, 255, 0); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/NucleeperRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/NucleeperRenderer.java index 453d0566b..3984f2b97 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/NucleeperRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/NucleeperRenderer.java @@ -47,16 +47,16 @@ public ResourceLocation getTextureLocation(NucleeperEntity entity) { return TEXTURE; } - private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, Matrix3f p_114092_, float xOffset, float yOffset) { - p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(0, 255, 0, 230).setUv(xOffset + 0.5F, yOffset).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, float xOffset, float yOffset) { + p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(0, 255, 0, 230); } - private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, Matrix3f p_114092_, float p_114217_, float p_114218_, float xOffset, float yOffset) { - p_114215_.addVertex(p_114216_, -ACMath.HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(0, 255, 0, 0).setUv(xOffset, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, float p_114217_, float p_114218_, float xOffset, float yOffset) { + p_114215_.addVertex(p_114216_, -ACMath.HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(0, 255, 0, 0); } - private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, Matrix3f p_114092_, float p_114226_, float p_114227_, float xOffset, float yOffset) { - p_114224_.addVertex(p_114225_, ACMath.HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(0, 255, 0, 0).setUv(xOffset + 1, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, float p_114226_, float p_114227_, float xOffset, float yOffset) { + p_114224_.addVertex(p_114225_, ACMath.HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(0, 255, 0, 0); } @@ -74,19 +74,17 @@ public void render(NucleeperEntity entityIn, float entityYaw, float partialTicks poseStack.mulPose(Axis.ZN.rotationDegrees(90)); PoseStack.Pose posestack$pose = poseStack.last(); Matrix4f matrix4f1 = posestack$pose.pose(); - Matrix3f matrix3f1 = posestack$pose.normal(); VertexConsumer lightConsumer = bufferIn.getBuffer(ACRenderTypes.getNucleeperLights()); - shineOriginVertex(lightConsumer, matrix4f1, matrix3f1, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); - shineRightCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); + shineOriginVertex(lightConsumer, matrix4f1, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); + shineRightCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); Matrix4f matrix4f2 = posestack$pose.pose(); - Matrix3f matrix3f2 = posestack$pose.normal(); poseStack.mulPose(Axis.ZN.rotationDegrees(180)); - shineOriginVertex(lightConsumer, matrix4f2, matrix3f2, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f2, matrix3f2, length, width, 0, 0); - shineRightCornerVertex(lightConsumer, matrix4f2, matrix3f2, length, width, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f2, matrix3f2, length, width, 0, 0); + shineOriginVertex(lightConsumer, matrix4f2, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f2, length, width, 0, 0); + shineRightCornerVertex(lightConsumer, matrix4f2, length, width, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f2, length, width, 0, 0); poseStack.popPose(); poseStack.popPose(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/RaycatRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/RaycatRenderer.java index e9a522d8e..c17052049 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/RaycatRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/RaycatRenderer.java @@ -51,16 +51,16 @@ protected RenderType getRenderType(RaycatEntity raycatEntity, boolean normal, bo } } - private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, Matrix3f p_114092_, float xOffset, float yOffset) { - p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(0, 255, 0, 255).setUv(xOffset + 0.5F, yOffset).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, float xOffset, float yOffset) { + p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(0, 255, 0, 255); } - private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, Matrix3f p_114092_, float p_114217_, float p_114218_, float xOffset, float yOffset) { - p_114215_.addVertex(p_114216_, -HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(0, 255, 0, 0).setUv(xOffset, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, float p_114217_, float p_114218_, float xOffset, float yOffset) { + p_114215_.addVertex(p_114216_, -HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(0, 255, 0, 0); } - private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, Matrix3f p_114092_, float p_114226_, float p_114227_, float xOffset, float yOffset) { - p_114224_.addVertex(p_114225_, HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(0, 255, 0, 0).setUv(xOffset + 1, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, float p_114226_, float p_114227_, float xOffset, float yOffset) { + p_114224_.addVertex(p_114225_, HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(0, 255, 0, 0); } public void render(RaycatEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { @@ -85,12 +85,11 @@ public void render(RaycatEntity entityIn, float entityYaw, float partialTicks, P poseStack.mulPose(Axis.ZN.rotationDegrees(90)); PoseStack.Pose posestack$pose = poseStack.last(); Matrix4f matrix4f1 = posestack$pose.pose(); - Matrix3f matrix3f1 = posestack$pose.normal(); VertexConsumer lightConsumer = bufferIn.getBuffer(ACRenderTypes.getNucleeperLights()); - shineOriginVertex(lightConsumer, matrix4f1, matrix3f1, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); - shineRightCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); + shineOriginVertex(lightConsumer, matrix4f1, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); + shineRightCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); poseStack.popPose(); poseStack.popPose(); } @@ -114,9 +113,9 @@ public LayerGlow() { public void render(PoseStack matrixStackIn, MultiBufferSource bufferIn, int packedLightIn, RaycatEntity entitylivingbaseIn, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch) { VertexConsumer ivertexbuilder1 = bufferIn.getBuffer(RaycatRenderer.this.sepia ? ACRenderTypes.getBookWidget(TEXTURE, true) : RenderType.entityCutoutNoCull(TEXTURE)); - this.getParentModel().renderToBuffer(matrixStackIn, ivertexbuilder1, packedLightIn, LivingEntityRenderer.getOverlayCoords(entitylivingbaseIn, 0.0F), 1.0F, 1.0F, 1.0F, 1.0F); + this.getParentModel().renderToBuffer(matrixStackIn, ivertexbuilder1, packedLightIn, LivingEntityRenderer.getOverlayCoords(entitylivingbaseIn, 0.0F), -1); VertexConsumer ivertexbuilder2 = bufferIn.getBuffer(RaycatRenderer.this.sepia ? ACRenderTypes.getBookWidget(TEXTURE_EYES, true) : ACRenderTypes.getEyesAlphaEnabled(TEXTURE_EYES)); - this.getParentModel().renderToBuffer(matrixStackIn, ivertexbuilder2, packedLightIn, LivingEntityRenderer.getOverlayCoords(entitylivingbaseIn, 0.0F), 1.0F, 1.0F, 1.0F, 1.0F); + this.getParentModel().renderToBuffer(matrixStackIn, ivertexbuilder2, packedLightIn, LivingEntityRenderer.getOverlayCoords(entitylivingbaseIn, 0.0F), -1); } } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/SubmarineRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/SubmarineRenderer.java index 67dc4bab7..be1e143cb 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/SubmarineRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/SubmarineRenderer.java @@ -132,12 +132,11 @@ public static void renderSubmarine(SubmarineEntity entity, float partialTicks, P poseStack.translate(0, -1, 0F); PoseStack.Pose posestack$pose = poseStack.last(); Matrix4f matrix4f1 = posestack$pose.pose(); - Matrix3f matrix3f1 = posestack$pose.normal(); VertexConsumer lightConsumer = source.getBuffer(ACRenderTypes.getSubmarineLights()); - shineOriginVertex(lightConsumer, matrix4f1, matrix3f1, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); - shineRightCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); - shineLeftCornerVertex(lightConsumer, matrix4f1, matrix3f1, length, width, 0, 0); + shineOriginVertex(lightConsumer, matrix4f1, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); + shineRightCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); + shineLeftCornerVertex(lightConsumer, matrix4f1, length, width, 0, 0); poseStack.popPose(); } @@ -186,16 +185,16 @@ public static void renderPassenger(E entityIn, double x, doub } } - private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, Matrix3f p_114092_, float xOffset, float yOffset) { - p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(255, 255, 255, 255).setUv(xOffset + 0.5F, yOffset).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, 1.0F, 0.0F); + private static void shineOriginVertex(VertexConsumer p_114220_, Matrix4f p_114221_, float xOffset, float yOffset) { + p_114220_.addVertex(p_114221_, 0.0F, 0.0F, 0.0F).setColor(255, 255, 255, 255); } - private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, Matrix3f p_114092_, float p_114217_, float p_114218_, float xOffset, float yOffset) { - p_114215_.addVertex(p_114216_, -HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(200, 235, 255, 0).setUv(xOffset, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineLeftCornerVertex(VertexConsumer p_114215_, Matrix4f p_114216_, float p_114217_, float p_114218_, float xOffset, float yOffset) { + p_114215_.addVertex(p_114216_, -HALF_SQRT_3 * p_114218_, p_114217_, 0).setColor(200, 235, 255, 0); } - private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, Matrix3f p_114092_, float p_114226_, float p_114227_, float xOffset, float yOffset) { - p_114224_.addVertex(p_114225_, HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(200, 235, 255, 0).setUv(xOffset + 1, yOffset + 1).setOverlay(NO_OVERLAY).setLight(240).setNormal(0.0F, -1.0F, 0.0F); + private static void shineRightCornerVertex(VertexConsumer p_114224_, Matrix4f p_114225_, float p_114226_, float p_114227_, float xOffset, float yOffset) { + p_114224_.addVertex(p_114225_, HALF_SQRT_3 * p_114227_, p_114226_, 0).setColor(200, 235, 255, 0); } private static ResourceLocation getSubmarineBaseTexture(SubmarineEntity entity) { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/TremorzillaRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/TremorzillaRenderer.java index 0405330b8..c7ed618bc 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/TremorzillaRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/TremorzillaRenderer.java @@ -5,6 +5,7 @@ import com.github.alexmodguy.alexscaves.client.model.TremorzillaBeamModel; import com.github.alexmodguy.alexscaves.client.model.TremorzillaModel; import com.github.alexmodguy.alexscaves.client.render.ACRenderTypes; +import com.github.alexmodguy.alexscaves.client.render.ColorUtil; import com.github.alexmodguy.alexscaves.client.render.entity.layer.TremorzillaRiderLayer; import com.github.alexmodguy.alexscaves.server.entity.living.TremorzillaEntity; import com.github.alexthe666.citadel.client.shader.PostEffectRegistry; @@ -242,7 +243,7 @@ public void render(PoseStack matrixStackIn, MultiBufferSource bufferIn, int pack float normalAlpha = ((float) (Math.sin(ageInTicks * 0.2F)) * 0.15F + 0.5F); float spikeDownAmount = tremorzilla.getClientSpikeDownAmount(partialTicks); VertexConsumer normalGlowConsumer = bufferIn.getBuffer(ACRenderTypes.getEyesAlphaEnabled(tremorzilla.isPowered() ? tremorzilla.getAltSkin() == 2 ? TEXTURE_TECTONIC_GLOW_POWERED : tremorzilla.getAltSkin() == 1 ? TEXTURE_RETRO_GLOW_POWERED : TEXTURE_GLOW_POWERED : tremorzilla.getAltSkin() == 2 ? TEXTURE_TECTONIC_GLOW : tremorzilla.getAltSkin() == 1 ? TEXTURE_RETRO_GLOW : TEXTURE_GLOW)); - this.getParentModel().renderToBuffer(matrixStackIn, normalGlowConsumer, packedLightIn, LivingEntityRenderer.getOverlayCoords(tremorzilla, 0.0F), 1.0F, 1.0F, 1.0F, normalAlpha); + this.getParentModel().renderToBuffer(matrixStackIn, normalGlowConsumer, packedLightIn, LivingEntityRenderer.getOverlayCoords(tremorzilla, 0.0F), ColorUtil.packColor(1.0F, 1.0F, 1.0F, normalAlpha)); if (spikeDownAmount > 0) { VertexConsumer spikeGlowConsumer; if (AlexsCaves.CLIENT_CONFIG.radiationGlowEffect.get()) { @@ -252,7 +253,7 @@ public void render(PoseStack matrixStackIn, MultiBufferSource bufferIn, int pack spikeGlowConsumer = normalGlowConsumer; } this.getParentModel().showSpikesBasedOnProgress(spikeDownAmount, 0.0F); - this.getParentModel().renderToBuffer(matrixStackIn, spikeGlowConsumer, packedLightIn, LivingEntityRenderer.getOverlayCoords(tremorzilla, 0.0F), 1.0F, 1.0F, 1.0F, 1.0F); + this.getParentModel().renderToBuffer(matrixStackIn, spikeGlowConsumer, packedLightIn, LivingEntityRenderer.getOverlayCoords(tremorzilla, 0.0F), -1); this.getParentModel().showAllSpikes(); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/layer/ACPotionEffectLayer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/layer/ACPotionEffectLayer.java index 73e120397..db7410f15 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/layer/ACPotionEffectLayer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/entity/layer/ACPotionEffectLayer.java @@ -101,10 +101,11 @@ public void render(PoseStack poseStack, MultiBufferSource bufferIn, int packedLi float alpha = level >= IrradiatedEffect.BLUE_LEVEL ? 0.9F : Math.min(level * 0.33F, 1F); poseStack.pushPose(); this.getParentModel().renderToBuffer(poseStack, ivertexbuilder, packedLightIn, - LivingEntityRenderer.getOverlayCoords((LivingEntity) entity, 0), ColorUtil.packColor(alpha, 1.0F, 1.0F, 1.0F)); + LivingEntityRenderer.getOverlayCoords((LivingEntity) entity, 0), ColorUtil.packColor(1.0F, 1.0F, 1.0F, alpha)); poseStack.popPose(); } - if (living.hasEffect(ACEffectRegistry.BUBBLED) && living.isAlive()) { + // Check both the MobEffect (for local player) and client-side visual tracker (for remote entities) + if ((living.hasEffect(ACEffectRegistry.BUBBLED) || AlexsCaves.PROXY.hasBubbledEffectVisual(living.getId())) && living.isAlive()) { float bodyYaw = Mth.rotLerp(partialTicks, living.yBodyRotO, living.yBodyRot); poseStack.pushPose(); float size = (float) Math.ceil(Math.max(living.getBbHeight(), living.getBbWidth())); @@ -127,7 +128,7 @@ public void render(PoseStack poseStack, MultiBufferSource bufferIn, int packedLi poseStack.pushPose(); float alpha = DarknessIncarnateEffect.getIntensity(living, partialTicks, 25F); this.getParentModel().renderToBuffer(poseStack, ivertexbuilder, 0, - LivingEntityRenderer.getOverlayCoords((LivingEntity) entity, 0), ColorUtil.packColor(alpha, 0.0F, 0.0F, 0.0F)); + LivingEntityRenderer.getOverlayCoords((LivingEntity) entity, 0), ColorUtil.packColor(0.0F, 0.0F, 0.0F, alpha)); poseStack.popPose(); } if (living.hasEffect(ACEffectRegistry.SUGAR_RUSH) && getParentModel() instanceof HumanoidModel) { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/ACArmorRenderProperties.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/ACArmorRenderProperties.java index e16d570ea..69215d6bf 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/ACArmorRenderProperties.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/ACArmorRenderProperties.java @@ -69,12 +69,13 @@ public HumanoidModel getHumanoidArmorModel(LivingEntity entityLiving, ItemSta } public static void renderCustomArmor(PoseStack poseStack, MultiBufferSource multiBufferSource, int light, ItemStack itemStack, ArmorItem armorItem, Model armorModel, boolean legs, ResourceLocation texture) { - if(armorItem.getMaterial() == ACItemRegistry.DARKNESS_ARMOR_MATERIAL){ + // In 1.21, armorItem.getMaterial() returns Holder, so compare with .getHolder() + if(armorItem.getMaterial() == ACItemRegistry.DARKNESS_ARMOR_MATERIAL.getHolder()){ VertexConsumer vertexconsumer1 = itemStack.hasFoil() ? VertexMultiConsumer.create(multiBufferSource.getBuffer(RenderType.entityGlintDirect()), multiBufferSource.getBuffer(RenderType.entityTranslucent(texture))) : multiBufferSource.getBuffer(RenderType.entityTranslucent(texture)); armorModel.renderToBuffer(poseStack, vertexconsumer1, light, OverlayTexture.NO_OVERLAY, -1); VertexConsumer vertexconsumer2 = multiBufferSource.getBuffer(ACRenderTypes.getEyesAlphaEnabled(DARKNESS_ARMOR_GLOW)); armorModel.renderToBuffer(poseStack, vertexconsumer2, 240, OverlayTexture.NO_OVERLAY, -1); - }else if(armorItem.getMaterial() == ACItemRegistry.RAINBOUNCE_ARMOR_MATERIAL){ + }else if(armorItem.getMaterial() == ACItemRegistry.RAINBOUNCE_ARMOR_MATERIAL.getHolder()){ VertexConsumer vertexconsumer1 = itemStack.hasFoil() ? VertexMultiConsumer.create(multiBufferSource.getBuffer(RenderType.entityGlintDirect()), multiBufferSource.getBuffer(ACRenderTypes.getTeslaBulb(texture))) : multiBufferSource.getBuffer(ACRenderTypes.getTeslaBulb(texture)); armorModel.renderToBuffer(poseStack, vertexconsumer1, 240, OverlayTexture.NO_OVERLAY, -1); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/ACItemstackRenderer.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/ACItemstackRenderer.java index d640e8750..43179302e 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/ACItemstackRenderer.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/ACItemstackRenderer.java @@ -136,13 +136,13 @@ public void renderByItem(ItemStack itemStackIn, ItemDisplayContext transformType if (left || transformType == ItemDisplayContext.GUI) { GALENA_GAUNTLET_LEFT_MODEL.setupAnim(null, openAmount, 0, ageInTicks, 0, 0); GALENA_GAUNTLET_LEFT_MODEL.renderToBuffer(poseStack, getVertexConsumerFoil(bufferIn, RenderType.entityCutoutNoCull(GALENA_GAUNTLET_TEXTURE), GALENA_GAUNTLET_TEXTURE, itemStackIn.hasFoil()), combinedLightIn, combinedOverlayIn, -1); - GALENA_GAUNTLET_LEFT_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(GALENA_GAUNTLET_BLUE_TEXTURE), GALENA_GAUNTLET_BLUE_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(openAmount, 1.0F, 1.0F, 1.0F)); - GALENA_GAUNTLET_LEFT_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(GALENA_GAUNTLET_RED_TEXTURE), GALENA_GAUNTLET_RED_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(closeAmount, 1.0F, 1.0F, 1.0F)); + GALENA_GAUNTLET_LEFT_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(GALENA_GAUNTLET_BLUE_TEXTURE), GALENA_GAUNTLET_BLUE_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(1.0F, 1.0F, 1.0F, openAmount)); + GALENA_GAUNTLET_LEFT_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(GALENA_GAUNTLET_RED_TEXTURE), GALENA_GAUNTLET_RED_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(1.0F, 1.0F, 1.0F, closeAmount)); } else { GALENA_GAUNTLET_RIGHT_MODEL.setupAnim(null, openAmount, 0, ageInTicks, 0, 0); GALENA_GAUNTLET_RIGHT_MODEL.renderToBuffer(poseStack, getVertexConsumerFoil(bufferIn, RenderType.entityCutoutNoCull(GALENA_GAUNTLET_TEXTURE), GALENA_GAUNTLET_TEXTURE, itemStackIn.hasFoil()), combinedLightIn, combinedOverlayIn, -1); - GALENA_GAUNTLET_RIGHT_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(GALENA_GAUNTLET_BLUE_TEXTURE), GALENA_GAUNTLET_BLUE_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(openAmount, 1.0F, 1.0F, 1.0F)); - GALENA_GAUNTLET_RIGHT_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(GALENA_GAUNTLET_RED_TEXTURE), GALENA_GAUNTLET_RED_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(closeAmount, 1.0F, 1.0F, 1.0F)); + GALENA_GAUNTLET_RIGHT_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(GALENA_GAUNTLET_BLUE_TEXTURE), GALENA_GAUNTLET_BLUE_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(1.0F, 1.0F, 1.0F, openAmount)); + GALENA_GAUNTLET_RIGHT_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(GALENA_GAUNTLET_RED_TEXTURE), GALENA_GAUNTLET_RED_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(1.0F, 1.0F, 1.0F, closeAmount)); } poseStack.popPose(); } @@ -167,8 +167,8 @@ public void renderByItem(ItemStack itemStackIn, ItemDisplayContext transformType poseStack.mulPose(Axis.XP.rotationDegrees(-180)); RESISTOR_SHIELD_MODEL.setupAnim(null, useProgress, switchProgress, 0, 0, 0); RESISTOR_SHIELD_MODEL.renderToBuffer(poseStack, getVertexConsumerFoil(bufferIn, RenderType.entityCutoutNoCull(RESISTOR_SHIELD_TEXTURE), RESISTOR_SHIELD_TEXTURE, itemStackIn.hasFoil()), combinedLightIn, combinedOverlayIn, -1); - RESISTOR_SHIELD_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(RESISTOR_SHIELD_RED_TEXTURE), RESISTOR_SHIELD_RED_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(switchProgress, 1.0F, 1.0F, 1.0F)); - RESISTOR_SHIELD_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(RESISTOR_SHIELD_BLUE_TEXTURE), RESISTOR_SHIELD_BLUE_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(1.0F - switchProgress, 1.0F, 1.0F, 1.0F)); + RESISTOR_SHIELD_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(RESISTOR_SHIELD_RED_TEXTURE), RESISTOR_SHIELD_RED_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(1.0F, 1.0F, 1.0F, switchProgress)); + RESISTOR_SHIELD_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(RESISTOR_SHIELD_BLUE_TEXTURE), RESISTOR_SHIELD_BLUE_TEXTURE), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(1.0F, 1.0F, 1.0F, 1.0F - switchProgress)); poseStack.popPose(); } @@ -269,7 +269,7 @@ public void renderByItem(ItemStack itemStackIn, ItemDisplayContext transformType ResourceLocation texture = gamma ? RAYGUN_BLUE_TEXTURE : RAYGUN_TEXTURE; ResourceLocation textureActive = gamma ? RAYGUN_BLUE_ACTIVE_TEXTURE : RAYGUN_ACTIVE_TEXTURE; RAYGUN_MODEL.renderToBuffer(poseStack, getVertexConsumerFoil(bufferIn, RenderType.entityCutoutNoCull(texture), texture, itemStackIn.hasFoil()), combinedLightIn, combinedOverlayIn, -1); - RAYGUN_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(textureActive), textureActive), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(pulseAlpha, 1.0F, 1.0F, 1.0F)); + RAYGUN_MODEL.renderToBuffer(poseStack, getVertexConsumer(bufferIn, ACRenderTypes.getEyesAlphaEnabled(textureActive), textureActive), combinedLightIn, combinedOverlayIn, ColorUtil.packColor(1.0F, 1.0F, 1.0F, pulseAlpha)); poseStack.popPose(); poseStack.popPose(); } @@ -335,6 +335,11 @@ public void renderByItem(ItemStack itemStackIn, ItemDisplayContext transformType if (itemStackIn.is(ACItemRegistry.DREADBOW.get())) { float ageInTicks = Minecraft.getInstance().player == null ? 0F : Minecraft.getInstance().player.tickCount + partialTick; float pullAmount = DreadbowItem.getPullingAmount(Minecraft.getInstance().level, itemStackIn, partialTick); + // Only show pulled state when player is actively using a dreadbow + boolean isPlayerUsingDreadbow = Minecraft.getInstance().player != null && Minecraft.getInstance().player.isUsingItem() && Minecraft.getInstance().player.getUseItem().is(ACItemRegistry.DREADBOW.get()); + if (!isPlayerUsingDreadbow) { + pullAmount = 0; + } poseStack.translate(0.5F, 0.5F, 0.5F); ItemStack spriteItem = new ItemStack(pullAmount >= 0.8F ? ACItemRegistry.DREADBOW_PULLING_2_SPRITE.get() : pullAmount >= 0.5F ? ACItemRegistry.DREADBOW_PULLING_1_SPRITE.get() : pullAmount > 0.0F ? ACItemRegistry.DREADBOW_PULLING_0_SPRITE.get() : ACItemRegistry.DREADBOW_SPRITE.get()); spriteItem.applyComponents(itemStackIn.getComponents()); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/tooltip/ClientSackOfSatingTooltip.java b/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/tooltip/ClientSackOfSatingTooltip.java index 4c8124206..e19fd1e5b 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/tooltip/ClientSackOfSatingTooltip.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/client/render/item/tooltip/ClientSackOfSatingTooltip.java @@ -9,7 +9,9 @@ public class ClientSackOfSatingTooltip implements ClientTooltipComponent { - private static final ResourceLocation GUI_ICONS_LOCATION = ResourceLocation.withDefaultNamespace("textures/gui/icons.png"); + private static final ResourceLocation FOOD_EMPTY_SPRITE = ResourceLocation.withDefaultNamespace("hud/food_empty"); + private static final ResourceLocation FOOD_HALF_SPRITE = ResourceLocation.withDefaultNamespace("hud/food_half"); + private static final ResourceLocation FOOD_FULL_SPRITE = ResourceLocation.withDefaultNamespace("hud/food_full"); private final SackOfSatingTooltip tooltipComponent; public ClientSackOfSatingTooltip(SackOfSatingTooltip tooltipComponent) { @@ -30,15 +32,15 @@ public void renderImage(Font font, int x, int y, GuiGraphics guiGraphics) { int hungerValue = tooltipComponent.getHungerValue(); int shanks = (int) Math.ceil(hungerValue / 2.0D); if (isTruncated()) { - guiGraphics.blit(GUI_ICONS_LOCATION, x, y, 16, 27, 9, 9); - guiGraphics.blit(GUI_ICONS_LOCATION, x, y, 52, 27, 9, 9); + guiGraphics.blitSprite(FOOD_EMPTY_SPRITE, x, y, 9, 9); + guiGraphics.blitSprite(FOOD_FULL_SPRITE, x, y, 9, 9); font.drawInBatch(getHungerValueMultiplierText(), (float)x + 10, (float)y + 1, 0XA8A8A8, true, guiGraphics.pose().last().pose(), guiGraphics.bufferSource(), Font.DisplayMode.NORMAL, 0, 15728880); } else { for (int i = 0; i < shanks; i++) { boolean halfShank = i == 0 && hungerValue % 2 == 1; //background outline - guiGraphics.blit(GUI_ICONS_LOCATION, x + i * 9, y, 16, 27, 9, 9); - guiGraphics.blit(GUI_ICONS_LOCATION, x + i * 9, y, halfShank ? 61 : 52, 27, 9, 9); + guiGraphics.blitSprite(FOOD_EMPTY_SPRITE, x + i * 9, y, 9, 9); + guiGraphics.blitSprite(halfShank ? FOOD_HALF_SPRITE : FOOD_FULL_SPRITE, x + i * 9, y, 9, 9); } } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/mixin/CorrodentCollisionMixin.java b/src/main/java/com/github/alexmodguy/alexscaves/mixin/CorrodentCollisionMixin.java new file mode 100644 index 000000000..ed7a0f3f8 --- /dev/null +++ b/src/main/java/com/github/alexmodguy/alexscaves/mixin/CorrodentCollisionMixin.java @@ -0,0 +1,31 @@ +package com.github.alexmodguy.alexscaves.mixin; + +import com.github.alexmodguy.alexscaves.server.entity.living.CorrodentEntity; +import com.github.alexthe666.citadel.server.entity.collision.ICustomCollisions; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * Mixin to replicate 1.20 Corrodent collision logic: + * - When NOT digging: use vanilla collision (super.collide) + * - When digging: use ICustomCollisions.getAllowedMovementForEntity + */ +@Mixin(value = Entity.class, priority = 900) +public abstract class CorrodentCollisionMixin { + + @Inject(method = "collide", at = @At("HEAD"), cancellable = true) + private void alexscaves_corrodentCollide(Vec3 vec, CallbackInfoReturnable cir) { + Entity self = (Entity) (Object) this; + if (self instanceof CorrodentEntity corrodent) { + if (corrodent.isDigging()) { + // 1.20 logic: when digging, use custom collision + cir.setReturnValue(ICustomCollisions.getAllowedMovementForEntity(self, vec)); + } + // when not digging, don't cancel - use vanilla collision (like super.collide in 1.20) + } + } +} diff --git a/src/main/java/com/github/alexmodguy/alexscaves/mixin/EntityMixin.java b/src/main/java/com/github/alexmodguy/alexscaves/mixin/EntityMixin.java index 94545a5ba..5f0551475 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/mixin/EntityMixin.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/mixin/EntityMixin.java @@ -97,11 +97,22 @@ private MagneticEntityData getMagneticData() { } /** - * Sync the magnetic data attachment to clients + * Sync the magnetic data attachment to clients via network packet. + * This replaces 1.20's automatic SynchedEntityData sync. */ private void syncMagneticData() { - // Attachment sync is handled automatically by the AttachmentType's sync configuration - // No manual sync needed when using .sync() on the AttachmentType builder + if (!supportsMagneticData()) { + return; + } + Entity thisEntity = (Entity) (Object) this; + // Only sync from server side + if (!thisEntity.level().isClientSide) { + MagneticEntityData data = thisEntity.getData(ACAttachmentRegistry.MAGNETIC_DATA); + // Send sync packet to all tracking players + com.github.alexmodguy.alexscaves.server.message.UpdateMagneticDataMessage msg = + new com.github.alexmodguy.alexscaves.server.message.UpdateMagneticDataMessage(thisEntity, data); + net.neoforged.neoforge.network.PacketDistributor.sendToPlayersTrackingEntityAndSelf(thisEntity, msg); + } } @Inject( @@ -167,9 +178,13 @@ public void ac_getEyePosition_lerp(float partialTick, CallbackInfoReturnable cir) { + Entity thisEntity = (Entity) (Object) this; + // Skip this mixin for ICustomCollisions entities - they have their own collide() override + if (thisEntity instanceof com.github.alexthe666.citadel.server.entity.collision.ICustomCollisions) { + return; + } AABB aabb = this.getBoundingBox(); - Entity thisEntity = (Entity) (Object) this; //AC CODE START List list; //fix infinity voxel collection crash for ItemEntity diff --git a/src/main/java/com/github/alexmodguy/alexscaves/mixin/GeodeFeatureMixin.java b/src/main/java/com/github/alexmodguy/alexscaves/mixin/GeodeFeatureMixin.java new file mode 100644 index 000000000..ccef1b8e7 --- /dev/null +++ b/src/main/java/com/github/alexmodguy/alexscaves/mixin/GeodeFeatureMixin.java @@ -0,0 +1,60 @@ +package com.github.alexmodguy.alexscaves.mixin; + +import com.github.alexmodguy.alexscaves.server.misc.ACTagRegistry; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; +import net.minecraft.world.level.levelgen.feature.GeodeFeature; +import net.minecraft.world.level.levelgen.feature.configurations.GeodeConfiguration; +import net.minecraft.world.level.levelgen.structure.StructureStart; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +/** + * Mixin to prevent geode (amethyst crystal) generation inside AlexsCaves protected structures. + * This fixes issues where crystals spawn inside structures like Underground Cabin. + */ +@Mixin(GeodeFeature.class) +public class GeodeFeatureMixin { + + /** + * Prevent geode generation if the origin is inside an ore-protected structure. + */ + @Inject(method = "place", at = @At("HEAD"), cancellable = true) + private void ac_preventGeodeInStructure(FeaturePlaceContext context, CallbackInfoReturnable cir) { + if (alexscaves$isInsideProtectedStructure(context.level(), context.origin())) { + cir.setReturnValue(false); + } + } + + /** + * Check if a position is inside an ore-protected structure. + */ + @Unique + private static boolean alexscaves$isInsideProtectedStructure(WorldGenLevel level, BlockPos pos) { + try { + StructureManager structureManager = null; + + if (level instanceof WorldGenRegion worldGenRegion) { + ServerLevel serverLevel = worldGenRegion.getLevel(); + structureManager = serverLevel.structureManager().forWorldGenRegion(worldGenRegion); + } else if (level instanceof ServerLevel serverLevel) { + structureManager = serverLevel.structureManager(); + } + + if (structureManager != null) { + StructureStart structureStart = structureManager.getStructureWithPieceAt(pos, ACTagRegistry.ORE_PROTECTED); + return structureStart.isValid(); + } + } catch (Exception e) { + // Fail safely - if we can't check, allow geode generation + } + return false; + } +} diff --git a/src/main/java/com/github/alexmodguy/alexscaves/mixin/OreFeatureMixin.java b/src/main/java/com/github/alexmodguy/alexscaves/mixin/OreFeatureMixin.java new file mode 100644 index 000000000..a8da1ae37 --- /dev/null +++ b/src/main/java/com/github/alexmodguy/alexscaves/mixin/OreFeatureMixin.java @@ -0,0 +1,153 @@ +package com.github.alexmodguy.alexscaves.mixin; + +import com.github.alexmodguy.alexscaves.server.misc.ACTagRegistry; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.StructureManager; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; +import net.minecraft.world.level.levelgen.feature.OreFeature; +import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration; +import net.minecraft.world.level.levelgen.structure.StructureStart; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +/** + * Mixin to prevent ore generation inside AlexsCaves protected structures. + * This fixes issues where ores (coal, emerald, etc.) and crystals spawn inside + * structures like Underground Cabin, replacing functional blocks. + * + * Performance optimization: Caches structure check results per chunk section + * to avoid repeated expensive structure lookups during ore vein generation. + */ +@Mixin(OreFeature.class) +public class OreFeatureMixin { + + @Unique + private static final ThreadLocal alexscaves$currentLevel = new ThreadLocal<>(); + + /** + * Cache for structure check results. Key is the chunk section position (packed long), + * value is whether that section intersects with a protected structure. + * This dramatically reduces the number of structure lookups since ore veins + * typically span only 1-2 chunk sections. + */ + @Unique + private static final ThreadLocal> alexscaves$sectionCache = ThreadLocal.withInitial(HashMap::new); + + /** + * Capture the WorldGenLevel at the start of the place method. + */ + @Inject(method = "place", at = @At("HEAD")) + private void ac_captureLevel(FeaturePlaceContext context, CallbackInfoReturnable cir) { + alexscaves$currentLevel.set(context.level()); + alexscaves$sectionCache.get().clear(); // Clear cache for each new ore vein + } + + /** + * Clear the captured level after place method completes. + */ + @Inject(method = "place", at = @At("RETURN")) + private void ac_clearLevel(FeaturePlaceContext context, CallbackInfoReturnable cir) { + alexscaves$currentLevel.remove(); + alexscaves$sectionCache.get().clear(); + } + + /** + * Wrap canPlaceOre to check structure protection before allowing ore placement. + * This is called for each potential ore position with the actual BlockPos. + * canPlaceOre is a static method, so we use a static wrapper method. + */ + @WrapOperation( + method = "doPlace", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/level/levelgen/feature/OreFeature;canPlaceOre(Lnet/minecraft/world/level/block/state/BlockState;Ljava/util/function/Function;Lnet/minecraft/util/RandomSource;Lnet/minecraft/world/level/levelgen/feature/configurations/OreConfiguration;Lnet/minecraft/world/level/levelgen/feature/configurations/OreConfiguration$TargetBlockState;Lnet/minecraft/core/BlockPos$MutableBlockPos;)Z" + ) + ) + private boolean ac_wrapCanPlaceOre( + BlockState state, + Function adjacentStateAccessor, + RandomSource random, + OreConfiguration config, + OreConfiguration.TargetBlockState targetState, + BlockPos.MutableBlockPos mutablePos, + Operation original + ) { + // First check if the original would allow placement + boolean canPlace = original.call(state, adjacentStateAccessor, random, config, targetState, mutablePos); + + if (!canPlace) { + return false; + } + + // Check if inside protected structure (with caching) + WorldGenLevel level = alexscaves$currentLevel.get(); + if (level != null && alexscaves$isInsideProtectedStructureCached(level, mutablePos)) { + return false; + } + + return true; + } + + /** + * Check if a position is inside an ore-protected structure, with caching per chunk section. + * Chunk sections are 16x16x16 blocks, so positions within the same section share the cache. + */ + @Unique + private static boolean alexscaves$isInsideProtectedStructureCached(WorldGenLevel level, BlockPos pos) { + // Use chunk section position as cache key for better granularity + long sectionKey = SectionPos.asLong(pos); + Map cache = alexscaves$sectionCache.get(); + + Boolean cached = cache.get(sectionKey); + if (cached != null) { + return cached; + } + + // Perform the actual structure check + boolean result = alexscaves$isInsideProtectedStructure(level, pos); + cache.put(sectionKey, result); + return result; + } + + /** + * Check if a position is inside an ore-protected structure. + */ + @Unique + private static boolean alexscaves$isInsideProtectedStructure(WorldGenLevel level, BlockPos pos) { + try { + StructureManager structureManager = null; + + if (level instanceof WorldGenRegion worldGenRegion) { + ServerLevel serverLevel = worldGenRegion.getLevel(); + structureManager = serverLevel.structureManager().forWorldGenRegion(worldGenRegion); + } else if (level instanceof ServerLevel serverLevel) { + structureManager = serverLevel.structureManager(); + } + + if (structureManager != null) { + StructureStart structureStart = structureManager.getStructureWithPieceAt(pos, ACTagRegistry.ORE_PROTECTED); + return structureStart.isValid(); + } + } catch (Exception e) { + // Fail safely - if we can't check, allow ore generation + } + return false; + } +} + + diff --git a/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/CameraMixin.java b/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/CameraMixin.java index 5b3105e51..e0a252cad 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/CameraMixin.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/CameraMixin.java @@ -1,13 +1,20 @@ package com.github.alexmodguy.alexscaves.mixin.client; +import com.github.alexmodguy.alexscaves.AlexsCaves; +import com.github.alexmodguy.alexscaves.client.ClientProxy; import com.github.alexmodguy.alexscaves.server.entity.util.MagnetUtil; +import com.github.alexmodguy.alexscaves.server.entity.util.PossessesCamera; +import com.github.alexmodguy.alexscaves.server.entity.util.ShakesScreen; import com.github.alexmodguy.alexscaves.server.potion.ACEffectRegistry; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.Mob; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.material.FogType; +import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -50,6 +57,7 @@ private float getMaxZoom(float maxZoom) { at = @At(value = "TAIL") ) public void ac_onSyncedDataUpdated(BlockGetter level, Entity entity, boolean detatched, boolean mirrored, float partialTicks, CallbackInfo ci) { + // Handle magnetic attachment Direction dir = MagnetUtil.getEntityMagneticDirection(entity); if (dir != Direction.DOWN && dir != Direction.UP) { this.setPosition(MagnetUtil.getEyePositionForAttachment(entity, dir, partialTicks)); @@ -61,6 +69,46 @@ public void ac_onSyncedDataUpdated(BlockGetter level, Entity entity, boolean det this.move(-this.getMaxZoom(4.0F), 0.0F, 0.0F); } } + + // Handle screen shake - must be done at TAIL after setPosition() is called + // In ComputeCameraAngles event, move() effects are overwritten by subsequent setPosition() + Entity player = Minecraft.getInstance().getCameraEntity(); + if (player != null && AlexsCaves.CLIENT_CONFIG.screenShaking.get()) { + float tremorAmount = ClientProxy.renderNukeSkyDarkFor > 0 ? 1.5F : 0F; + if (player instanceof PossessesCamera watcherEntity) { + tremorAmount = watcherEntity.isPossessionBreakable() + ? AlexsCaves.PROXY.getPossessionStrengthAmount(partialTicks) + : 0F; + } + if (tremorAmount == 0) { + double shakeDistanceScale = 64; + double distance = Double.MAX_VALUE; + AABB aabb = player.getBoundingBox().inflate(shakeDistanceScale); + for (Mob screenShaker : Minecraft.getInstance().level.getEntitiesOfClass(Mob.class, aabb, + (mob -> mob instanceof ShakesScreen))) { + ShakesScreen shakesScreen = (ShakesScreen) screenShaker; + if (shakesScreen.canFeelShake(player) && screenShaker.distanceTo(player) < distance) { + distance = screenShaker.distanceTo(player); + tremorAmount = Math.min((1F - (float) Math.min(1, distance / shakesScreen.getShakeDistance())) + * Math.max(shakesScreen.getScreenShakeAmount(partialTicks), 0F), 2.0F); + } + } + } + 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.lastTremorTick = player.tickCount; + } + float intensity = (float) (tremorAmount * Minecraft.getInstance().options.screenEffectScale().get()); + this.move( + ClientProxy.randomTremorOffsets[0] * 0.2F * intensity, + ClientProxy.randomTremorOffsets[1] * 0.2F * intensity, + ClientProxy.randomTremorOffsets[2] * 0.5F * intensity); + } + } } @Inject( diff --git a/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/GameRendererMixin.java b/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/GameRendererMixin.java index 2656852ac..6a872930b 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/GameRendererMixin.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/GameRendererMixin.java @@ -8,6 +8,7 @@ import com.github.alexmodguy.alexscaves.server.entity.item.SubmarineEntity; import com.github.alexmodguy.alexscaves.server.potion.ACEffectRegistry; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Camera; import net.minecraft.client.DeltaTracker; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GameRenderer; @@ -16,6 +17,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.phys.Vec3; +import org.joml.Quaternionf; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -33,6 +35,10 @@ public abstract class GameRendererMixin { @Final private RenderBuffers renderBuffers; + @Shadow + @Final + private Camera mainCamera; + @Inject( method = {"Lnet/minecraft/client/renderer/GameRenderer;tick()V"}, remap = true, @@ -76,8 +82,11 @@ public void ac_renderLevel(DeltaTracker deltaTracker, CallbackInfo ci) { Entity player = Minecraft.getInstance().cameraEntity; if (player != null && player.isPassenger() && player.getVehicle() instanceof SubmarineEntity submarine && SubmarineRenderer.isFirstPersonFloodlightsMode(submarine)) { Vec3 offset = submarine.getPosition(partialTicks).subtract(player.getEyePosition(partialTicks)); - // In 1.21, we need to create our own PoseStack since it's no longer passed + // In 1.21, we need to create our own PoseStack with camera rotation applied PoseStack poseStack = new PoseStack(); + // Apply camera rotation (conjugate to get the view matrix rotation) + Quaternionf cameraRotation = mainCamera.rotation().conjugate(new Quaternionf()); + poseStack.mulPose(cameraRotation); poseStack.pushPose(); poseStack.translate(offset.x, offset.y, offset.z); SubmarineRenderer.renderSubFirstPerson(submarine, partialTicks, poseStack, renderBuffers.bufferSource()); @@ -97,7 +106,8 @@ public void ac_renderLevel(DeltaTracker deltaTracker, CallbackInfo ci) { public void ac_renderLevelAfterHand(DeltaTracker deltaTracker, CallbackInfo ci) { if (Minecraft.getInstance().getCameraEntity() instanceof LivingEntity living && living.hasEffect(ACEffectRegistry.BUBBLED) && Minecraft.getInstance().options.getCameraType().isFirstPerson()) { MultiBufferSource.BufferSource multibuffersource$buffersource = Minecraft.getInstance().renderBuffers().bufferSource(); - // In 1.21, we need to create our own PoseStack + // For first-person screen overlay effects, we don't apply camera rotation + // The effect should stay fixed on screen regardless of where the player looks PoseStack poseStack = new PoseStack(); ACPotionEffectLayer.renderBubbledFirstPerson(poseStack); multibuffersource$buffersource.endBatch(); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/HumanoidArmorLayerMixin.java b/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/HumanoidArmorLayerMixin.java index fe36e8a6f..699e1af89 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/HumanoidArmorLayerMixin.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/HumanoidArmorLayerMixin.java @@ -40,13 +40,14 @@ public HumanoidArmorLayerMixin(RenderLayerParent renderLayerParent) { super(renderLayerParent); } + // In 1.21, renderArmorPiece has 12 parameters (added 6 animation floats) @Inject( - method = {"Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;)V"}, + method = {"Lnet/minecraft/client/renderer/entity/layers/HumanoidArmorLayer;renderArmorPiece(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/entity/EquipmentSlot;ILnet/minecraft/client/model/HumanoidModel;FFFFFF)V"}, at = @At(value = "HEAD"), remap = true, cancellable = true ) - private void ac_renderArmorPiece(PoseStack poseStack, MultiBufferSource multiBufferSource, LivingEntity livingEntity, EquipmentSlot equipmentSlot, int light, HumanoidModel humanoidModel, CallbackInfo ci) { + private void ac_renderArmorPiece(PoseStack poseStack, MultiBufferSource multiBufferSource, LivingEntity livingEntity, EquipmentSlot equipmentSlot, int light, HumanoidModel humanoidModel, float limbSwing, float limbSwingAmount, float partialTick, float ageInTicks, float netHeadYaw, float headPitch, CallbackInfo ci) { ItemStack itemstack = livingEntity.getItemBySlot(equipmentSlot); if (itemstack.getItem() instanceof CustomArmorPostRender) { ci.cancel(); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/LocalPlayerMixin.java b/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/LocalPlayerMixin.java index 86c43d3eb..223ceae7a 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/LocalPlayerMixin.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/mixin/client/LocalPlayerMixin.java @@ -2,22 +2,35 @@ import com.github.alexmodguy.alexscaves.server.block.fluid.ACFluidRegistry; +import com.github.alexmodguy.alexscaves.server.item.ACItemRegistry; import com.github.alexmodguy.alexscaves.server.misc.ACSoundRegistry; import com.mojang.authlib.GameProfile; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.client.player.Input; import net.minecraft.client.player.LocalPlayer; import net.minecraft.sounds.SoundSource; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(LocalPlayer.class) public abstract class LocalPlayerMixin extends AbstractClientPlayer { + @Shadow + public Input input; + private boolean wasUnderAcid; private boolean wasUnderPurpleSoda; + + @Unique + private float ac_savedForwardImpulse; + @Unique + private float ac_savedLeftImpulse; public LocalPlayerMixin(ClientLevel clientLevel, GameProfile gameProfile) { super(clientLevel, gameProfile); @@ -45,4 +58,35 @@ private void ac_updateIsUnderwater(CallbackInfoReturnable cir) { wasUnderAcid = underAcid; wasUnderPurpleSoda = underPurpleSoda; } + + /** + * Save the original movement input values before vanilla applies the using-item slowdown. + * This is injected right after the MovementInputUpdateEvent is fired. + */ + @Inject(method = "aiStep", + at = @At(value = "INVOKE", + target = "Lnet/neoforged/neoforge/client/ClientHooks;onMovementInputUpdate(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/client/player/Input;)V", + shift = At.Shift.AFTER)) + private void ac_saveMovementInputBeforeSlowdown(CallbackInfo ci) { + // Save the original input values before vanilla applies the 0.2x slowdown for using items + ac_savedForwardImpulse = this.input.forwardImpulse; + ac_savedLeftImpulse = this.input.leftImpulse; + } + + /** + * Restore movement input when using Galena Gauntlet to prevent the vanilla using-item slowdown. + * The Galena Gauntlet is a combat item that shouldn't slow the player while being used. + * This is injected at the autoJumpTime check, which is right after the slowdown is applied. + */ + @Inject(method = "aiStep", + at = @At(value = "FIELD", + target = "Lnet/minecraft/client/player/LocalPlayer;autoJumpTime:I", + ordinal = 0)) + private void ac_restoreMovementInputForGalenaGauntlet(CallbackInfo ci) { + // If the player is using the Galena Gauntlet, restore the original movement speed + if (this.isUsingItem() && this.getUseItem().is(ACItemRegistry.GALENA_GAUNTLET.get())) { + this.input.forwardImpulse = ac_savedForwardImpulse; + this.input.leftImpulse = ac_savedLeftImpulse; + } + } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/CommonProxy.java b/src/main/java/com/github/alexmodguy/alexscaves/server/CommonProxy.java index f36bd024b..a8a8d78de 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/CommonProxy.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/CommonProxy.java @@ -156,4 +156,16 @@ public boolean isFarFromCamera(double x, double y, double z) { public void renderVanillaMapDecoration(MapDecoration mapDecoration, int index) { } + + // Bubbled effect visual methods - client-only implementation in ClientProxy + public boolean hasBubbledEffectVisual(int entityId) { + return false; + } + + public void setBubbledEffectTicks(int entityId, int ticks) { + } + + // Beholder sync handling - client-only implementation in ClientProxy + public void handleBeholderSync(int beholderId, boolean active, double x, double y, double z, float yRot, float xRot, UUID usingPlayerUUID) { + } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/block/ACBlockRegistry.java b/src/main/java/com/github/alexmodguy/alexscaves/server/block/ACBlockRegistry.java index 05e7ede07..e725462c0 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/block/ACBlockRegistry.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/block/ACBlockRegistry.java @@ -182,7 +182,7 @@ public class ACBlockRegistry { public static final DeferredHolder ARCHAIC_VINE = registerBlockAndItem("archaic_vine", () -> new ArchaicVineBlock()); public static final DeferredHolder ARCHAIC_VINE_PLANT = DEF_REG.register("archaic_vine_plant", () -> new ArchaicVinePlantBlock()); public static final DeferredHolder ANCIENT_LEAVES = registerBlockAndItem("ancient_leaves", () -> new LeavesBlock(BlockBehaviour.Properties.of().mapColor(MapColor.GRASS).strength(0.2F).randomTicks().sound(SoundType.GRASS).noOcclusion().isSuffocating((blockState, getter, pos) -> false))); - public static final DeferredHolder ANCIENT_SAPLING = registerBlockAndItem("ancient_sapling", () -> new SaplingBlock(AncientTreeGrower.GROWER, BlockBehaviour.Properties.of().mapColor(MapColor.GRASS).noCollission().randomTicks().instabreak().sound(SoundType.GRASS))); + public static final DeferredHolder ANCIENT_SAPLING = registerBlockAndItem("ancient_sapling", () -> new AncientSaplingBlock(AncientTreeGrower.GROWER, BlockBehaviour.Properties.of().mapColor(MapColor.GRASS).noCollission().randomTicks().instabreak().sound(SoundType.GRASS))); public static final DeferredHolder POTTED_ANCIENT_SAPLING = DEF_REG.register("potted_ancient_sapling", () -> new FlowerPotBlock(() -> (FlowerPotBlock) Blocks.FLOWER_POT, ANCIENT_SAPLING, BlockBehaviour.Properties.of().instabreak().noOcclusion().pushReaction(PushReaction.DESTROY))); public static final DeferredHolder TREE_STAR = registerBlockAndItem("tree_star", () -> new TreeStarBlock()); public static final DeferredHolder FERN_THATCH = registerBlockAndItem("fern_thatch", () -> new Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GREEN).strength(0.5F).sound(SoundType.GRASS).noOcclusion())); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/block/AcidBlock.java b/src/main/java/com/github/alexmodguy/alexscaves/server/block/AcidBlock.java index ecfdfc67a..c25d37705 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/block/AcidBlock.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/block/AcidBlock.java @@ -144,6 +144,26 @@ private static void initCorrosion() { map.put(Blocks.CUT_COPPER_STAIRS, Blocks.WEATHERED_CUT_COPPER_STAIRS); map.put(Blocks.WEATHERED_CUT_COPPER_STAIRS, Blocks.EXPOSED_CUT_COPPER_STAIRS); map.put(Blocks.EXPOSED_CUT_COPPER_STAIRS, Blocks.OXIDIZED_CUT_COPPER_STAIRS); + // Chiseled Copper + map.put(Blocks.CHISELED_COPPER, Blocks.WEATHERED_CHISELED_COPPER); + map.put(Blocks.WEATHERED_CHISELED_COPPER, Blocks.EXPOSED_CHISELED_COPPER); + map.put(Blocks.EXPOSED_CHISELED_COPPER, Blocks.OXIDIZED_CHISELED_COPPER); + // Copper Grate + map.put(Blocks.COPPER_GRATE, Blocks.WEATHERED_COPPER_GRATE); + map.put(Blocks.WEATHERED_COPPER_GRATE, Blocks.EXPOSED_COPPER_GRATE); + map.put(Blocks.EXPOSED_COPPER_GRATE, Blocks.OXIDIZED_COPPER_GRATE); + // Copper Bulb + map.put(Blocks.COPPER_BULB, Blocks.WEATHERED_COPPER_BULB); + map.put(Blocks.WEATHERED_COPPER_BULB, Blocks.EXPOSED_COPPER_BULB); + map.put(Blocks.EXPOSED_COPPER_BULB, Blocks.OXIDIZED_COPPER_BULB); + // Copper Door + map.put(Blocks.COPPER_DOOR, Blocks.WEATHERED_COPPER_DOOR); + map.put(Blocks.WEATHERED_COPPER_DOOR, Blocks.EXPOSED_COPPER_DOOR); + map.put(Blocks.EXPOSED_COPPER_DOOR, Blocks.OXIDIZED_COPPER_DOOR); + // Copper Trapdoor + map.put(Blocks.COPPER_TRAPDOOR, Blocks.WEATHERED_COPPER_TRAPDOOR); + map.put(Blocks.WEATHERED_COPPER_TRAPDOOR, Blocks.EXPOSED_COPPER_TRAPDOOR); + map.put(Blocks.EXPOSED_COPPER_TRAPDOOR, Blocks.OXIDIZED_COPPER_TRAPDOOR); map.put(ACBlockRegistry.SCRAP_METAL.get(), ACBlockRegistry.RUSTY_SCRAP_METAL.get()); map.put(ACBlockRegistry.SCRAP_METAL_PLATE.get(), ACBlockRegistry.RUSTY_SCRAP_METAL_PLATE.get()); map.put(ACBlockRegistry.METAL_BARREL.get(), ACBlockRegistry.RUSTY_BARREL.get()); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/block/AncientSaplingBlock.java b/src/main/java/com/github/alexmodguy/alexscaves/server/block/AncientSaplingBlock.java new file mode 100644 index 000000000..be619f4f3 --- /dev/null +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/block/AncientSaplingBlock.java @@ -0,0 +1,124 @@ +package com.github.alexmodguy.alexscaves.server.block; + +import com.github.alexmodguy.alexscaves.server.block.grower.AncientTreeGrower; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SaplingBlock; +import net.minecraft.world.level.block.grower.TreeGrower; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; + +/** + * Custom sapling block for Ancient Trees that supports 3x3 mega tree growth. + * When 9 saplings are placed in a 3x3 pattern and bonemealed, a giant ancient tree will grow. + */ +public class AncientSaplingBlock extends SaplingBlock { + + public AncientSaplingBlock(TreeGrower grower, Properties properties) { + super(grower, properties); + } + + @Override + public void advanceTree(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) { + if (state.getValue(STAGE) == 0) { + level.setBlock(pos, state.cycle(STAGE), 4); + } else { + // First, try to grow a 3x3 mega tree + if (!tryGrowThreeByThreeMegaTree(level, pos, state, random)) { + // If 3x3 pattern not found, fall back to normal tree growth + this.treeGrower.growTree(level, level.getChunkSource().getGenerator(), pos, state, random); + } + } + } + + /** + * Attempts to grow a 3x3 mega tree. Checks all 9 possible positions where + * this sapling could be part of a 3x3 pattern. + * + * @return true if a mega tree was successfully grown, false otherwise + */ + private boolean tryGrowThreeByThreeMegaTree(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) { + Holder> holder = level.registryAccess() + .registryOrThrow(Registries.CONFIGURED_FEATURE) + .getHolder(AncientTreeGrower.GIANT_ANCIENT_TREE) + .orElse(null); + + if (holder == null) { + return false; + } + + var event = net.neoforged.neoforge.event.EventHooks.fireBlockGrowFeature(level, random, pos, holder); + holder = event.getFeature(); + if (event.isCanceled()) { + return false; + } + + ChunkGenerator chunkGenerator = level.getChunkSource().getGenerator(); + + // Check all 9 possible corner positions where this sapling could be the origin + // The origin is the corner with the smallest x and z coordinates + for (int xOffset = 0; xOffset >= -2; xOffset--) { + for (int zOffset = 0; zOffset >= -2; zOffset--) { + if (isThreeByThreeSapling(state, level, pos, xOffset, zOffset)) { + BlockPos originPos = pos.offset(xOffset, 0, zOffset); + ConfiguredFeature configuredFeature = holder.value(); + + // Clear all 9 saplings + BlockState airState = Blocks.AIR.defaultBlockState(); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + level.setBlock(originPos.offset(i, 0, j), airState, 4); + } + } + + // Try to place the mega tree at the center of the 3x3 area + BlockPos treePos = originPos.offset(1, 0, 1); + if (configuredFeature.place(level, chunkGenerator, random, treePos)) { + return true; + } + + // If tree generation failed, restore all saplings + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + level.setBlock(originPos.offset(i, 0, j), state, 4); + } + } + return false; + } + } + } + + return false; + } + + /** + * Checks if there is a 3x3 pattern of the same sapling starting at the offset position. + * + * @param state The block state of the sapling + * @param level The block getter + * @param pos The position of the bonemealed sapling + * @param xOffset X offset to the potential origin corner + * @param zOffset Z offset to the potential origin corner + * @return true if a 3x3 pattern exists + */ + private static boolean isThreeByThreeSapling(BlockState state, BlockGetter level, BlockPos pos, int xOffset, int zOffset) { + Block block = state.getBlock(); + BlockPos originPos = pos.offset(xOffset, 0, zOffset); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (!level.getBlockState(originPos.offset(i, 0, j)).is(block)) { + return false; + } + } + } + return true; + } +} diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/block/BioluminescentTorch.java b/src/main/java/com/github/alexmodguy/alexscaves/server/block/BioluminescentTorch.java index 6936b407a..d46efce65 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/block/BioluminescentTorch.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/block/BioluminescentTorch.java @@ -42,7 +42,8 @@ public BlockState updateShape(BlockState state, Direction direction, BlockState public BlockState getStateForPlacement(BlockPlaceContext context) { LevelAccessor levelaccessor = context.getLevel(); BlockPos blockpos = context.getClickedPos(); - return super.getStateForPlacement(context).setValue(WATERLOGGED, Boolean.valueOf(levelaccessor.getFluidState(blockpos).getType() == Fluids.WATER)); + BlockState prev = super.getStateForPlacement(context); + return prev == null ? null : prev.setValue(WATERLOGGED, Boolean.valueOf(levelaccessor.getFluidState(blockpos).isSourceOfType(Fluids.WATER))); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/block/BioluminescentWallTorch.java b/src/main/java/com/github/alexmodguy/alexscaves/server/block/BioluminescentWallTorch.java index e98878846..a5020c816 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/block/BioluminescentWallTorch.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/block/BioluminescentWallTorch.java @@ -43,7 +43,7 @@ public BlockState getStateForPlacement(BlockPlaceContext context) { LevelAccessor levelaccessor = context.getLevel(); BlockPos blockpos = context.getClickedPos(); BlockState prev = super.getStateForPlacement(context); - return prev == null ? null : prev.setValue(WATERLOGGED, Boolean.valueOf(levelaccessor.getFluidState(blockpos).getType() == Fluids.WATER)); + return prev == null ? null : prev.setValue(WATERLOGGED, Boolean.valueOf(levelaccessor.getFluidState(blockpos).isSourceOfType(Fluids.WATER))); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/block/DinosaurEggBlock.java b/src/main/java/com/github/alexmodguy/alexscaves/server/block/DinosaurEggBlock.java index 6211c7742..30e2c165c 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/block/DinosaurEggBlock.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/block/DinosaurEggBlock.java @@ -64,11 +64,13 @@ public boolean canHatchAt(BlockGetter reader, BlockPos pos){ return isProperHabitat(reader, pos); } + @Override public void stepOn(Level worldIn, BlockPos pos, BlockState state, Entity entityIn) { this.tryTrample(worldIn, pos, entityIn, 100); super.stepOn(worldIn, pos, state, entityIn); } + @Override public void fallOn(Level worldIn, BlockState state, BlockPos pos, Entity entityIn, float fallDistance) { if (!(entityIn instanceof Zombie)) { this.tryTrample(worldIn, pos, entityIn, 3); @@ -95,9 +97,7 @@ private void tryTrample(Level worldIn, BlockPos pos, Entity trampler, int chance } BlockState blockstate = worldIn.getBlockState(pos); this.removeOneEgg(worldIn, pos, blockstate); - } - } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/block/FissurePrimalMagmaBlock.java b/src/main/java/com/github/alexmodguy/alexscaves/server/block/FissurePrimalMagmaBlock.java index 1406896d9..56c9cc1d0 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/block/FissurePrimalMagmaBlock.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/block/FissurePrimalMagmaBlock.java @@ -91,6 +91,11 @@ public VoxelShape getVisualShape(BlockState state, BlockGetter level, BlockPos b return Shapes.empty(); } + @Override + protected void randomTick(BlockState blockState, ServerLevel serverLevel, BlockPos blockPos, RandomSource randomSource) { + this.tick(blockState, serverLevel, blockPos, randomSource); + } + public void tick(BlockState blockState, ServerLevel serverLevel, BlockPos blockPos, RandomSource randomSource) { if(!PrimalMagmaBlock.isBossActive(serverLevel)){ int regenHeight = blockState.getValue(REGEN_HEIGHT); @@ -144,6 +149,13 @@ public BlockState updateShape(BlockState state, Direction direction, BlockState return newState; } + @Override + public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + super.onPlace(state, level, pos, oldState, movedByPiston); + // Schedule a tick to check for regeneration when the block is placed + level.scheduleTick(pos, this, 20 + level.random.nextInt(20)); + } + public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource randomSource) { Vec3 center = Vec3.upFromBottomCenterOf(pos, 1).add(randomSource.nextFloat() - 0.5F, 0, randomSource.nextFloat() - 0.5F); Vec3 delta = new Vec3(randomSource.nextFloat() - 0.5F, randomSource.nextFloat() - 0.5F, randomSource.nextFloat() - 0.5F); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/block/PrimalMagmaBlock.java b/src/main/java/com/github/alexmodguy/alexscaves/server/block/PrimalMagmaBlock.java index 179ea508f..a1d66b954 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/block/PrimalMagmaBlock.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/block/PrimalMagmaBlock.java @@ -91,6 +91,11 @@ public VoxelShape getVisualShape(BlockState state, BlockGetter level, BlockPos b return Shapes.empty(); } + @Override + protected void randomTick(BlockState blockState, ServerLevel serverLevel, BlockPos blockPos, RandomSource randomSource) { + this.tick(blockState, serverLevel, blockPos, randomSource); + } + public void tick(BlockState blockState, ServerLevel serverLevel, BlockPos blockPos, RandomSource randomSource) { if(blockState.getValue(ACTIVE)){ if(!blockState.getValue(PERMANENT) && !isBossActive(serverLevel)){ @@ -107,6 +112,13 @@ public BlockState updateShape(BlockState state, Direction direction, BlockState return newState; } + @Override + public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + super.onPlace(state, level, pos, oldState, movedByPiston); + // Schedule a tick to check for boss active state when the block is placed + level.scheduleTick(pos, this, 20 + level.random.nextInt(20)); + } + public static boolean isBossActive(Level level) { ACWorldData worldData = ACWorldData.get(level); if(worldData != null){ diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/block/blockentity/ConversionCrucibleBlockEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/block/blockentity/ConversionCrucibleBlockEntity.java index 52ca76d8b..664696a42 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/block/blockentity/ConversionCrucibleBlockEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/block/blockentity/ConversionCrucibleBlockEntity.java @@ -8,8 +8,10 @@ import com.github.alexmodguy.alexscaves.server.item.BiomeTreatItem; import com.github.alexmodguy.alexscaves.server.level.biome.ACBiomeRegistry; import com.github.alexmodguy.alexscaves.server.misc.ACAdvancementTriggerRegistry; +import com.github.alexmodguy.alexscaves.server.misc.ACDummyBiomeSource; import com.github.alexmodguy.alexscaves.server.misc.ACSoundRegistry; import com.github.alexmodguy.alexscaves.server.misc.ACTagRegistry; +import com.github.alexthe666.citadel.server.generation.SurfaceRulesManager; import net.minecraft.Util; import net.minecraft.core.*; import net.minecraft.core.HolderLookup; @@ -36,6 +38,8 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.levelgen.*; +import net.minecraft.world.level.levelgen.blending.Blender; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.phys.AABB; import org.apache.commons.lang3.mutable.MutableInt; @@ -44,6 +48,7 @@ import java.awt.*; import java.util.*; import java.util.List; +import java.util.function.Function; import java.util.stream.Collectors; public class ConversionCrucibleBlockEntity extends BlockEntity { @@ -130,6 +135,8 @@ public static void tick(Level level, BlockPos pos, BlockState state, ConversionC entity.markUpdated(); entity.conversionTime = 0; entity.setFilledLevel(0); + entity.convertingToBiome = null; + entity.biomeColor = -1; } entity.conversionProgress = (entity.conversionTime / (float) MAX_CONVERSION_TIME) * 20.0F; } else if (entity.conversionProgress > 0.0F) { @@ -233,21 +240,53 @@ private void updateTopAndBottomBlocks() { try { Registry registry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Optional> biomeHolder = registry.getHolder(convertingToBiome); + ChunkAccess chunkaccess = serverLevel.getChunk(this.getBlockPos()); + ResourceKey dimensionType = NoiseGeneratorSettings.OVERWORLD; if (biomeHolder.isPresent()) { if (biomeHolder.get().is(BiomeTags.IS_NETHER)) { - // Nether biome + dimensionType = NoiseGeneratorSettings.NETHER; } else if (biomeHolder.get().is(BiomeTags.IS_END)) { - // End biome + dimensionType = NoiseGeneratorSettings.END; } topBlockForBiome = getFallbackTopBlock(biomeHolder.get()); middleBlockForBiome = getFallbackMiddleBlock(biomeHolder.get()); bottomBlockForBiome = getFallbackBottomBlock(biomeHolder.get()); } - // Note: Complex surface rule generation was removed due to NeoForge 1.21 API changes: - // - WorldGenRegion constructor signature changed - // - NoiseBasedChunkGenerator.createNoiseChunk is now private - // - SurfaceRules.Context.updateXZ/updateY are protected - // Using fallback blocks based on biome type instead. + Holder settings = serverLevel.registryAccess().registryOrThrow(Registries.NOISE_SETTINGS).getHolderOrThrow(dimensionType); + //for compat with other world types, like flat worlds, we cannot assume the chunk generator of the world is noise-based so we must create a new one + NoiseBasedChunkGenerator noiseBasedChunkGenerator = new NoiseBasedChunkGenerator(new ACDummyBiomeSource(), settings); + //get or create a dummy noise chunk + NoiseChunk noisechunk = chunkaccess.getOrCreateNoiseChunk((chunkAccess) -> { + return noiseBasedChunkGenerator.createNoiseChunk(chunkAccess, serverLevel.structureManager(), Blender.empty(), serverLevel.getChunkSource().randomState()); + }); + //should ideally be merged when we get it, for some reason isn't. Idk why + SurfaceRules.RuleSource ruleSource = SurfaceRulesManager.mergeOverworldRules(noiseBasedChunkGenerator.generatorSettings().value().surfaceRule()); + WorldGenerationContext worldGenerationContext = new WorldGenerationContext(noiseBasedChunkGenerator, serverLevel); + Function> biomeRef = (blockPos -> biomeHolder.get()); + SurfaceRules.Context surfacerulesContext = new SurfaceRules.Context(serverLevel.getChunkSource().randomState().surfaceSystem(), serverLevel.getChunkSource().randomState(), chunkaccess, noisechunk, biomeRef, registry, worldGenerationContext); + SurfaceRules.SurfaceRule rule = ruleSource.apply(surfacerulesContext); + int x = this.getBlockPos().getX(); + int z = this.getBlockPos().getZ(); + //one over the top (grass condition) + int topHeight = serverLevel.getHeight(Heightmap.Types.OCEAN_FLOOR_WG, x, z) + 1; + surfacerulesContext.updateXZ(x, z); + surfacerulesContext.updateY(1, 1, topHeight, x, topHeight, z); + BlockState grass = rule.tryApply(x, topHeight, z); + if (grass != null && !grass.is(Blocks.BEDROCK)) { + topBlockForBiome = grass; + } + //tell it that there is a block about the top position + surfacerulesContext.updateY(1, 1, topHeight + 1, x, topHeight, z); + BlockState dirt = rule.tryApply(x, topHeight, z); + if (dirt != null && !dirt.is(Blocks.BEDROCK)) { + middleBlockForBiome = dirt; + } + //tell it that there is many blocks about the top position + surfacerulesContext.updateY(1, 1, topHeight + 20, x, topHeight, z); + BlockState stone = rule.tryApply(x, topHeight, z); + if (stone != null && !stone.is(Blocks.BEDROCK)) { + bottomBlockForBiome = stone; + } } catch (Exception e) { AlexsCaves.LOGGER.warn("Encountered error finding the surface blocks of a biome"); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/block/blockentity/GobthumperBlockEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/block/blockentity/GobthumperBlockEntity.java index 15a905ba6..9bccd3bcd 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/block/blockentity/GobthumperBlockEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/block/blockentity/GobthumperBlockEntity.java @@ -2,7 +2,6 @@ import com.github.alexmodguy.alexscaves.client.particle.ACParticleRegistry; import com.github.alexmodguy.alexscaves.server.entity.ACEntityRegistry; -import com.github.alexmodguy.alexscaves.server.entity.item.DinosaurSpiritEntity; import com.github.alexmodguy.alexscaves.server.entity.living.GumWormEntity; import com.github.alexmodguy.alexscaves.server.misc.ACSoundRegistry; import com.github.alexmodguy.alexscaves.server.misc.ACTagRegistry; @@ -61,6 +60,7 @@ private void thumpTick(Level level) { } if (closestWorm != null) { this.summonedWormId = closestWorm.getId(); + closestWorm.setGobthumperPos(this.getBlockPos()); }else{ boolean flag = false; BlockPos summonPos = null; @@ -80,6 +80,7 @@ private void thumpTick(Level level) { summonedWorm.setTempSummon(true); summonedWorm.finalizeSpawn((ServerLevel) level, level.getCurrentDifficultyAt(summonPos), MobSpawnType.MOB_SUMMONED, (SpawnGroupData) null); level.addFreshEntity(summonedWorm); + summonedWorm.setGobthumperPos(this.getBlockPos()); this.summonedWormId = summonedWorm.getId(); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/enchantment/ACEnchantmentHelper.java b/src/main/java/com/github/alexmodguy/alexscaves/server/enchantment/ACEnchantmentHelper.java index 74fbcb56d..67127223b 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/enchantment/ACEnchantmentHelper.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/enchantment/ACEnchantmentHelper.java @@ -2,11 +2,13 @@ import net.minecraft.core.Holder; import net.minecraft.core.RegistryAccess; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.ItemEnchantments; import net.minecraft.world.level.Level; /** @@ -63,4 +65,26 @@ public static int getEnchantmentLevel(RegistryAccess registryAccess, ResourceKey public static boolean hasEnchantment(Level level, ResourceKey enchantmentKey, ItemStack stack) { return getEnchantmentLevel(level, enchantmentKey, stack) > 0; } + + /** + * Gets the enchantment level directly from the ItemStack without needing a Level. + * This method iterates through the enchantments on the stack and matches by ResourceKey. + * Useful for methods like getDefaultAttributeModifiers where Level is not available. + * + * @param enchantmentKey The ResourceKey of the enchantment to check + * @param stack The item stack to check + * @return The enchantment level, or 0 if not present + */ + public static int getEnchantmentLevelFromStack(ResourceKey enchantmentKey, ItemStack stack) { + if (enchantmentKey == null || stack.isEmpty()) { + return 0; + } + ItemEnchantments enchantments = stack.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); + for (Holder holder : enchantments.keySet()) { + if (holder.is(enchantmentKey)) { + return enchantments.getLevel(holder); + } + } + return 0; + } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ACEntityRegistry.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ACEntityRegistry.java index 5f9a188bd..9c1dfa607 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ACEntityRegistry.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ACEntityRegistry.java @@ -160,12 +160,12 @@ public static void initializeAttributes(EntityAttributeCreationEvent event) { @SubscribeEvent public static void spawnPlacements(RegisterSpawnPlacementsEvent event) { - // Note: Custom spawn placement types (inAcid, inSoda) are no longer supported in 1.21. - // Using IN_WATER as fallback; actual fluid checks are handled in spawn predicates. - event.register(TELETOR.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, TeletorEntity::checkMonsterSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); - event.register(MAGNETRON.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, MagnetronEntity::checkMonsterSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); - event.register(BOUNDROID.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, BoundroidEntity::checkMonsterSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); - event.register(FERROUSLIME.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, FerrouslimeEntity::checkMonsterSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); + // Custom spawn placement types for acid and soda fluids are defined in ACSpawnPlacementTypes. + // Magnetic Caves monsters use checkMagneticCaveSpawnRules to allow spawning in lit areas (Tesla Bulbs etc.) + event.register(TELETOR.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, TeletorEntity::checkMagneticCaveSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); + event.register(MAGNETRON.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, MagnetronEntity::checkMagneticCaveSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); + event.register(BOUNDROID.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, BoundroidEntity::checkMagneticCaveSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); + event.register(FERROUSLIME.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, FerrouslimeEntity::checkMagneticCaveSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(NOTOR.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, NotorEntity::checkNotorSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(SUBTERRANODON.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, SubterranodonEntity::checkSubterranodonSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(VALLUMRAPTOR.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, VallumraptorEntity::checkPrehistoricSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); @@ -176,7 +176,7 @@ public static void spawnPlacements(RegisterSpawnPlacementsEvent event) { event.register(LUXTRUCTOSAURUS.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, LuxtructosaurusEntity::checkPrehistoricSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(ATLATITAN.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, AtlatitanEntity::checkPrehistoricPostBossSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(NUCLEEPER.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, NucleeperEntity::checkMonsterSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); - event.register(RADGILL.get(), SpawnPlacementTypes.IN_WATER, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, RadgillEntity::checkRadgillSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); + event.register(RADGILL.get(), ACSpawnPlacementTypes.IN_ACID, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, RadgillEntity::checkRadgillSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(BRAINIAC.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, BrainiacEntity::checkMonsterSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(GAMMAROACH.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, GammaroachEntity::checkGammaroachSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(RAYCAT.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, RaycatEntity::checkRaycatSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); @@ -195,7 +195,7 @@ public static void spawnPlacements(RegisterSpawnPlacementsEvent event) { event.register(CORRODENT.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, CorrodentEntity::checkCorrodentSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(VESPER.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, VesperEntity::checkVesperSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(FORSAKEN.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, ForsakenEntity::checkForsakenSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); - event.register(SWEETISH_FISH.get(), SpawnPlacementTypes.IN_WATER, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, SweetishFishEntity::checkSweetishFishSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); + event.register(SWEETISH_FISH.get(), ACSpawnPlacementTypes.IN_PURPLE_SODA, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, SweetishFishEntity::checkSweetishFishSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(CANIAC.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, CaniacEntity::checkCaniacSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(GUMBEEPER.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, GumbeeperEntity::checkGumbeeperSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); event.register(CANDICORN.get(), SpawnPlacementTypes.ON_GROUND, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, CandicornEntity::checkCandicornSpawnRules, RegisterSpawnPlacementsEvent.Operation.AND); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ACSpawnPlacementTypes.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ACSpawnPlacementTypes.java new file mode 100644 index 000000000..f48e63170 --- /dev/null +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ACSpawnPlacementTypes.java @@ -0,0 +1,45 @@ +package com.github.alexmodguy.alexscaves.server.entity; + +import com.github.alexmodguy.alexscaves.server.block.fluid.ACFluidRegistry; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.SpawnPlacementType; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.material.FluidState; + +import javax.annotation.Nullable; + +/** + * Custom spawn placement types for Alex's Caves fluids. + * These replace the 1.20 Forge-style custom SpawnPlacements that are no longer supported in 1.21. + */ +public class ACSpawnPlacementTypes { + + /** + * Spawn placement type for entities that spawn in acid fluid. + * Used by RadgillEntity in Toxic Caves. + */ + public static final SpawnPlacementType IN_ACID = (level, pos, entityType) -> { + if (entityType != null && level.getWorldBorder().isWithinBounds(pos)) { + FluidState fluidState = level.getFluidState(pos); + BlockPos blockpos = pos.above(); + return fluidState.getFluidType() == ACFluidRegistry.ACID_FLUID_TYPE.get() + && !level.getBlockState(blockpos).isRedstoneConductor(level, blockpos); + } + return false; + }; + + /** + * Spawn placement type for entities that spawn in purple soda fluid. + * Used by SweetishFishEntity in Candy Cavity. + */ + public static final SpawnPlacementType IN_PURPLE_SODA = (level, pos, entityType) -> { + if (entityType != null && level.getWorldBorder().isWithinBounds(pos)) { + FluidState fluidState = level.getFluidState(pos); + BlockPos blockpos = pos.above(); + return fluidState.getFluidType() == ACFluidRegistry.PURPLE_SODA_FLUID_TYPE.get() + && !level.getBlockState(blockpos).isRedstoneConductor(level, blockpos); + } + return false; + }; +} diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/GumWormDestroyGobthumperGoal.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/GumWormDestroyGobthumperGoal.java index 19a42c9d6..4dc619d13 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/GumWormDestroyGobthumperGoal.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/GumWormDestroyGobthumperGoal.java @@ -42,6 +42,8 @@ public void start() { public void stop() { entity.setBiting(false); entity.setLeaping(false); + // Set a dig-down period to prevent bounce-up behavior after leaping + entity.setForceDigDownTicks(60); } public void tick() { @@ -52,7 +54,7 @@ public void tick() { double distance2 = entity.distanceToSqr(leapFromPos.getX() + 0.5F, leapFromPos.getY() + 0.5F, leapFromPos.getZ() + 0.5F); if(entity.isLeaping()){ entity.getNavigation().stop(); - if(gobthumperPos.getY() + 2 > entity.getY() && entity.isInWall()){ + if(gobthumperPos.getY() + 2 > entity.getY()){ Vec3 extraDeltaHelp = Vec3.atCenterOf(gobthumperPos).subtract(entity.position()); if(extraDeltaHelp.length() > 1.0F){ extraDeltaHelp = extraDeltaHelp.normalize(); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/GumWormRidingGoal.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/GumWormRidingGoal.java index 2eba722aa..c967240af 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/GumWormRidingGoal.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/GumWormRidingGoal.java @@ -46,9 +46,15 @@ public void tick() { } else { entity.setLeaping(false); Vec3 forwardsVec = new Vec3(entity.isValidRider() ? ridingPlayer.xxa * 2.5F : 0.0F, 0, 10F).yRot((float) -Math.toRadians(entity.yBodyRot)).add(entity.position()); - this.entity.getMoveControl().setWantedPosition(forwardsVec.x, forwardsVec.y, forwardsVec.z, 3.0F); + this.entity.getMoveControl().setWantedPosition(forwardsVec.x, forwardsVec.y, forwardsVec.z, 4.5F); this.entity.setTargetDigPitch(this.entity.horizontalCollision ? -45.0F : 0.0F); leapRot = entity.getYRot(); + if (!entity.onGround() && !entity.isInWall() && !entity.isInFluidType() && !entity.horizontalCollision) { + // Only apply downward force if above the ground surface to prevent going underground + if (entity.getY() > entity.getSurfaceY()) { + this.entity.setDeltaMovement(this.entity.getDeltaMovement().add(0, -3.8F, 0)); + } + } } if (entity.isMouthOpen()) { entity.attackAllAroundMouth((float) entity.getAttribute(Attributes.ATTACK_DAMAGE).getValue(), 2.0F); @@ -57,7 +63,6 @@ public void tick() { entity.setBiting(true); }else{ entity.setBiting(false); - } } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/RelicheirusPushTreesGoal.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/RelicheirusPushTreesGoal.java index ddac0e617..285254839 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/RelicheirusPushTreesGoal.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/RelicheirusPushTreesGoal.java @@ -155,7 +155,7 @@ public void gatherAttachedBlocks(BlockPos origin, BlockPos pos, List l if (!list.contains(pos)) { list.add(pos); for (BlockPos blockpos1 : BlockPos.betweenClosed(pos.offset(-1, -1, -1), pos.offset(1, 1, 1))) { - if (!blockpos1.equals(pos) && pos.distToCenterSqr(origin.getX(), pos.getY(), origin.getZ()) < MAX_TREE_SPREAD) { + if (!blockpos1.equals(pos) && blockpos1.distToCenterSqr(origin.getX(), blockpos1.getY(), origin.getZ()) < MAX_TREE_SPREAD * MAX_TREE_SPREAD) { if (isTreePart(blockpos1)) { gatherAttachedBlocks(origin, blockpos1.immutable(), list); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/SubterranodonAttackGoal.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/SubterranodonAttackGoal.java new file mode 100644 index 000000000..12969ffce --- /dev/null +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/ai/SubterranodonAttackGoal.java @@ -0,0 +1,129 @@ +package com.github.alexmodguy.alexscaves.server.entity.ai; + +import com.github.alexmodguy.alexscaves.server.entity.living.SubterranodonEntity; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.goal.Goal; +import net.minecraft.world.phys.Vec3; + +import java.util.EnumSet; + +/** + * Custom attack goal for Subterranodon that handles both flying and ground attacks. + * When the entity has a target, it will take off and fly towards the target to attack. + */ +public class SubterranodonAttackGoal extends Goal { + + private final SubterranodonEntity entity; + private final double speedModifier; + private int ticksUntilNextAttack; + private int ticksUntilNextPathRecalculation; + private static final int ATTACK_INTERVAL = 20; + + public SubterranodonAttackGoal(SubterranodonEntity entity, double speedModifier) { + this.entity = entity; + this.speedModifier = speedModifier; + this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); + } + + @Override + public boolean canUse() { + LivingEntity target = entity.getTarget(); + if (target == null || !target.isAlive()) { + return false; + } + if (entity.isPassenger() || entity.isDancing() || entity.isInSittingPose()) { + return false; + } + return true; + } + + @Override + public boolean canContinueToUse() { + LivingEntity target = entity.getTarget(); + if (target == null || !target.isAlive()) { + return false; + } + if (entity.isPassenger() || entity.isDancing() || entity.isInSittingPose()) { + return false; + } + return true; + } + + @Override + public void start() { + // Take off when starting to attack + if (!entity.isFlying() && entity.onGround()) { + entity.setFlying(true); + // Give a small upward boost + entity.setDeltaMovement(entity.getDeltaMovement().add(0, 0.5, 0)); + } + this.ticksUntilNextPathRecalculation = 0; + this.ticksUntilNextAttack = 0; + } + + @Override + public void stop() { + entity.getNavigation().stop(); + } + + @Override + public void tick() { + LivingEntity target = entity.getTarget(); + if (target == null) { + return; + } + + // Ensure flying when attacking + if (!entity.isFlying() && !entity.onGround()) { + entity.setFlying(true); + } else if (!entity.isFlying() && entity.onGround()) { + // Take off from ground + entity.setFlying(true); + entity.setDeltaMovement(entity.getDeltaMovement().add(0, 0.4, 0)); + } + + // Look at target + entity.getLookControl().setLookAt(target, 30.0F, 30.0F); + + double distanceToTarget = entity.distanceToSqr(target); + double attackReach = getAttackReachSqr(target); + + // Recalculate path periodically + this.ticksUntilNextPathRecalculation = Math.max(this.ticksUntilNextPathRecalculation - 1, 0); + + if (this.ticksUntilNextPathRecalculation <= 0) { + this.ticksUntilNextPathRecalculation = 4 + entity.getRandom().nextInt(7); + + // Fly towards target - aim slightly above them for better attack angle + Vec3 targetPos = target.position().add(0, target.getBbHeight() * 0.5, 0); + + if (entity.isFlying()) { + // Use move control directly for flying movement + entity.getMoveControl().setWantedPosition(targetPos.x, targetPos.y, targetPos.z, speedModifier); + } else { + // Fallback to navigation for ground movement + entity.getNavigation().moveTo(target, speedModifier); + } + } + + // Attack when in range + this.ticksUntilNextAttack = Math.max(this.ticksUntilNextAttack - 1, 0); + + if (distanceToTarget <= attackReach && this.ticksUntilNextAttack <= 0) { + this.ticksUntilNextAttack = ATTACK_INTERVAL; + entity.swing(InteractionHand.MAIN_HAND); + entity.doHurtTarget(target); + } + } + + protected double getAttackReachSqr(LivingEntity target) { + float reach = entity.getBbWidth() * 2.0F + target.getBbWidth(); + return (double)(reach * reach); + } + + @Override + public boolean requiresUpdateEveryTick() { + return true; + } +} diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/AlexsCavesChestBoatEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/AlexsCavesChestBoatEntity.java index 555ed4035..21517e93b 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/AlexsCavesChestBoatEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/AlexsCavesChestBoatEntity.java @@ -49,11 +49,13 @@ protected void defineSynchedData(SynchedEntityData.Builder builder) { @Override protected void addAdditionalSaveData(CompoundTag nbt) { + super.addAdditionalSaveData(nbt); nbt.putString("ACBoatType", getACBoatType().getName()); } @Override protected void readAdditionalSaveData(CompoundTag nbt) { + super.readAdditionalSaveData(nbt); if (nbt.contains("ACBoatType")) { this.entityData.set(DATA_ID_AC_BOAT_TYPE, AlexsCavesBoat.Type.byName(nbt.getString("ACBoatType")).ordinal()); } 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 301a6a976..f313e49f3 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 @@ -110,7 +110,18 @@ 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)); + // Include entity spawn data so client can create the entity if it doesn't exist + // This is necessary when viewing from far away (unloaded chunks) + AlexsCaves.sendMSGToAll(new BeholderSyncMessage( + this.getId(), + turnOn, + this.getX(), + this.getY(), + this.getZ(), + this.getYRot(), + this.getXRot(), + this.getUsingPlayerUUID() + )); if (turnOn) { this.level().broadcastEntityEvent(this, (byte) 77); } else { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/BurrowingArrowEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/BurrowingArrowEntity.java index 440db0344..e847769bb 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/BurrowingArrowEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/BurrowingArrowEntity.java @@ -38,12 +38,12 @@ public BurrowingArrowEntity(EntityType entityType, Level level) { } public BurrowingArrowEntity(Level level, LivingEntity shooter) { - super(ACEntityRegistry.BURROWING_ARROW.get(), shooter, level, new ItemStack(ACItemRegistry.BURROWING_ARROW.get()), ItemStack.EMPTY); + super(ACEntityRegistry.BURROWING_ARROW.get(), shooter, level, new ItemStack(ACItemRegistry.BURROWING_ARROW.get()), null); this.setBaseDamage(3.5D); } public BurrowingArrowEntity(Level level, double x, double y, double z) { - super(ACEntityRegistry.BURROWING_ARROW.get(), x, y, z, level, new ItemStack(ACItemRegistry.BURROWING_ARROW.get()), ItemStack.EMPTY); + super(ACEntityRegistry.BURROWING_ARROW.get(), x, y, z, level, new ItemStack(ACItemRegistry.BURROWING_ARROW.get()), null); this.setBaseDamage(3.5D); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/CandyCaneHookEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/CandyCaneHookEntity.java index 8b87a513a..afb14810e 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/CandyCaneHookEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/CandyCaneHookEntity.java @@ -312,8 +312,9 @@ public void remove(Entity.RemovalReason removalReason) { super.remove(removalReason); } - public float getCustomGravity() { - return isReeling() || this.entityData.get(RESISTS_GRAVITY) && this.getDeltaMovement().horizontalDistance() > 0.05F ? 0 : 0.08F; + @Override + protected double getDefaultGravity() { + return isReeling() || this.entityData.get(RESISTS_GRAVITY) && this.getDeltaMovement().horizontalDistance() > 0.05F ? 0 : 0.08; } public InteractionHand getHandLaunchedFrom() { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/CinderBrickEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/CinderBrickEntity.java index df7c500a5..d5ade349f 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/CinderBrickEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/CinderBrickEntity.java @@ -58,6 +58,7 @@ protected void onHit(HitResult hitResult) { } + @Override protected Item getDefaultItem() { return ACItemRegistry.CINDER_BRICK.get(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/DarkArrowEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/DarkArrowEntity.java index 41634ed75..f6ceebcfb 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/DarkArrowEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/DarkArrowEntity.java @@ -29,11 +29,11 @@ public DarkArrowEntity(EntityType entityType, Level level) { } public DarkArrowEntity(Level level, LivingEntity shooter) { - super(ACEntityRegistry.DARK_ARROW.get(), shooter, level, ItemStack.EMPTY, ItemStack.EMPTY); + super(ACEntityRegistry.DARK_ARROW.get(), shooter, level, ItemStack.EMPTY, null); } public DarkArrowEntity(Level level, double x, double y, double z) { - super(ACEntityRegistry.DARK_ARROW.get(), x, y, z, level, ItemStack.EMPTY, ItemStack.EMPTY); + super(ACEntityRegistry.DARK_ARROW.get(), x, y, z, level, ItemStack.EMPTY, null); } @Override diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/DepthChargeEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/DepthChargeEntity.java index b0b1633c6..925d98b9f 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/DepthChargeEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/DepthChargeEntity.java @@ -91,6 +91,7 @@ private void explode() { } + @Override protected Item getDefaultItem() { return ACItemRegistry.DEPTH_CHARGE.get(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/ExtinctionSpearEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/ExtinctionSpearEntity.java index a26e7cf55..698e08c47 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/ExtinctionSpearEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/ExtinctionSpearEntity.java @@ -40,12 +40,12 @@ public ExtinctionSpearEntity(EntityType entityType, Level level) { } public ExtinctionSpearEntity(Level level, LivingEntity shooter, ItemStack itemStack) { - super(ACEntityRegistry.EXTINCTION_SPEAR.get(), shooter, level, itemStack.copy(), ItemStack.EMPTY); + super(ACEntityRegistry.EXTINCTION_SPEAR.get(), shooter, level, itemStack.copy(), null); this.spearItem = itemStack.copy(); } public ExtinctionSpearEntity(Level level, double x, double y, double z) { - super(ACEntityRegistry.EXTINCTION_SPEAR.get(), x, y, z, level, new ItemStack(ACItemRegistry.EXTINCTION_SPEAR.get()), ItemStack.EMPTY); + super(ACEntityRegistry.EXTINCTION_SPEAR.get(), x, y, z, level, new ItemStack(ACItemRegistry.EXTINCTION_SPEAR.get()), null); } @Override diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/FrostmintSpearEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/FrostmintSpearEntity.java index 99c3a0976..263b97527 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/FrostmintSpearEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/FrostmintSpearEntity.java @@ -37,11 +37,11 @@ public FrostmintSpearEntity(EntityType entityType, Level level) { } public FrostmintSpearEntity(Level level, LivingEntity shooter, ItemStack itemStack) { - super(ACEntityRegistry.FROSTMINT_SPEAR.get(), shooter, level, new ItemStack(ACItemRegistry.FROSTMINT_SPEAR.get()), ItemStack.EMPTY); + super(ACEntityRegistry.FROSTMINT_SPEAR.get(), shooter, level, new ItemStack(ACItemRegistry.FROSTMINT_SPEAR.get()), null); } public FrostmintSpearEntity(Level level, double x, double y, double z) { - super(ACEntityRegistry.FROSTMINT_SPEAR.get(), x, y, z, level, new ItemStack(ACItemRegistry.FROSTMINT_SPEAR.get()), ItemStack.EMPTY); + super(ACEntityRegistry.FROSTMINT_SPEAR.get(), x, y, z, level, new ItemStack(ACItemRegistry.FROSTMINT_SPEAR.get()), null); } @Override diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/GuanoEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/GuanoEntity.java index 3bea2f2ad..088e63a12 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/GuanoEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/GuanoEntity.java @@ -49,6 +49,7 @@ protected void onHit(HitResult hitResult) { } + @Override protected Item getDefaultItem() { return ACItemRegistry.GUANO.get(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/InkBombEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/InkBombEntity.java index 6d0bf08a2..7be5b34a0 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/InkBombEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/InkBombEntity.java @@ -116,7 +116,8 @@ public void setGlowingBomb(boolean bool) { this.entityData.set(GLOWING_BOMB, bool); } + @Override protected Item getDefaultItem() { - return isGlowingBomb() ? ACItemRegistry.GLOW_INK_BOMB.get() : ACItemRegistry.INK_BOMB.get(); + return ACItemRegistry.INK_BOMB.get(); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/LimestoneSpearEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/LimestoneSpearEntity.java index d642ea462..8fac5ca50 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/LimestoneSpearEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/LimestoneSpearEntity.java @@ -24,11 +24,11 @@ public LimestoneSpearEntity(EntityType entityType, Level level) { } public LimestoneSpearEntity(Level level, LivingEntity shooter, ItemStack itemStack) { - super(ACEntityRegistry.LIMESTONE_SPEAR.get(), shooter, level, new ItemStack(ACItemRegistry.LIMESTONE_SPEAR.get()), ItemStack.EMPTY); + super(ACEntityRegistry.LIMESTONE_SPEAR.get(), shooter, level, new ItemStack(ACItemRegistry.LIMESTONE_SPEAR.get()), null); } public LimestoneSpearEntity(Level level, double x, double y, double z) { - super(ACEntityRegistry.LIMESTONE_SPEAR.get(), x, y, z, level, new ItemStack(ACItemRegistry.LIMESTONE_SPEAR.get()), ItemStack.EMPTY); + super(ACEntityRegistry.LIMESTONE_SPEAR.get(), x, y, z, level, new ItemStack(ACItemRegistry.LIMESTONE_SPEAR.get()), null); } @Override diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/NuclearBombEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/NuclearBombEntity.java index 8d38fb0d7..70c4bdaa2 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/NuclearBombEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/NuclearBombEntity.java @@ -94,13 +94,14 @@ private void explode() { } @Override - public void resetFallDistance() { - if (this.fallDistance > 20.0F) { + protected void checkFallDamage(double y, boolean onGround, net.minecraft.world.level.block.state.BlockState state, BlockPos pos) { + if (onGround && this.fallDistance > 20.0F) { this.discard(); if (!this.level().isClientSide) { this.explode(); } } + super.checkFallDamage(y, onGround, state, pos); } private Stream getNearbySirens(ServerLevel world, int range) { @@ -176,7 +177,8 @@ public void positionRider(Entity passenger, MoveFunction moveFunction) { float expandScale = 1F + (float) Math.sin(progress * progress * Math.PI) * 0.5F; float f1 = -(this.getXRot() / 40F); float j = expandScale - progress * 0.3F; - double d0 = this.getY() + j + 0.5F - 0.2F; + Vec3 attachPoint = passenger.getVehicleAttachmentPoint(this); + double d0 = this.getY() + j - attachPoint.y; moveFunction.accept(passenger, this.getX(), d0, this.getZ()); passenger.fallDistance = 0.0F; } else { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/NuclearExplosionEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/NuclearExplosionEntity.java index b03f4a298..475c8f13f 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/NuclearExplosionEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/NuclearExplosionEntity.java @@ -40,7 +40,10 @@ public class NuclearExplosionEntity extends Entity { public static final TicketController TICKET_CONTROLLER = new TicketController(ResourceLocation.fromNamespaceAndPath(AlexsCaves.MODID, "nuclear_explosion")); + private static final int TREMORZILLA_EGG_HATCH_RADIUS = 36; + private boolean spawnedParticle = false; + private boolean hatchedTremorzillaEggs = false; private Stack destroyingChunks = new Stack<>(); private static final EntityDataAccessor SIZE = SynchedEntityData.defineId(NuclearExplosionEntity.class, EntityDataSerializers.FLOAT); private static final EntityDataAccessor NO_GRIEFING = SynchedEntityData.defineId(NuclearExplosionEntity.class, EntityDataSerializers.BOOLEAN); @@ -73,6 +76,10 @@ public void tick() { loadingChunks = true; loadChunksAround(true); } + if (!hatchedTremorzillaEggs) { + hatchedTremorzillaEggs = true; + hatchNearbyTremorzillaEggs(); + } if (destroyingChunks.isEmpty()) { BlockPos center = this.blockPosition(); int chunks = chunksAffected; @@ -202,6 +209,25 @@ private boolean isDestroyable(BlockState state) { return (!state.is(ACTagRegistry.NUKE_PROOF) && state.getBlock().getExplosionResistance() < AlexsCaves.COMMON_CONFIG.nukeMaxBlockExplosionResistance.get()) || state.is(ACBlockRegistry.TREMORZILLA_EGG.get()); } + private void hatchNearbyTremorzillaEggs() { + BlockPos center = this.blockPosition(); + BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); + for (int x = -TREMORZILLA_EGG_HATCH_RADIUS; x <= TREMORZILLA_EGG_HATCH_RADIUS; x++) { + for (int y = -TREMORZILLA_EGG_HATCH_RADIUS; y <= TREMORZILLA_EGG_HATCH_RADIUS; y++) { + for (int z = -TREMORZILLA_EGG_HATCH_RADIUS; z <= TREMORZILLA_EGG_HATCH_RADIUS; z++) { + mutablePos.set(center.getX() + x, center.getY() + y, center.getZ() + z); + if (mutablePos.distSqr(center) <= TREMORZILLA_EGG_HATCH_RADIUS * TREMORZILLA_EGG_HATCH_RADIUS) { + BlockState state = level().getBlockState(mutablePos); + if (state.is(ACBlockRegistry.TREMORZILLA_EGG.get()) && state.getBlock() instanceof TremorzillaEggBlock tremorzillaEggBlock) { + tremorzillaEggBlock.spawnDinosaurs(level(), mutablePos.immutable(), state); + level().removeBlock(mutablePos, false); + } + } + } + } + } + } + @Override protected void defineSynchedData(SynchedEntityData.Builder builder) { builder.define(SIZE, 1.0F); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SeekingArrowEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SeekingArrowEntity.java index ccc13ab6f..1558632bd 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SeekingArrowEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SeekingArrowEntity.java @@ -25,11 +25,11 @@ public SeekingArrowEntity(EntityType entityType, Level level) { } public SeekingArrowEntity(Level level, LivingEntity shooter) { - super(ACEntityRegistry.SEEKING_ARROW.get(), shooter, level, new ItemStack(ACItemRegistry.SEEKING_ARROW.get()), ItemStack.EMPTY); + super(ACEntityRegistry.SEEKING_ARROW.get(), shooter, level, new ItemStack(ACItemRegistry.SEEKING_ARROW.get()), null); } public SeekingArrowEntity(Level level, double x, double y, double z) { - super(ACEntityRegistry.SEEKING_ARROW.get(), x, y, z, level, new ItemStack(ACItemRegistry.SEEKING_ARROW.get()), ItemStack.EMPTY); + super(ACEntityRegistry.SEEKING_ARROW.get(), x, y, z, level, new ItemStack(ACItemRegistry.SEEKING_ARROW.get()), null); } @Override diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SodaBottleRocketEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SodaBottleRocketEntity.java index 173355446..06f945701 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SodaBottleRocketEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SodaBottleRocketEntity.java @@ -4,6 +4,8 @@ import com.github.alexmodguy.alexscaves.client.particle.ACParticleRegistry; import com.github.alexmodguy.alexscaves.server.entity.ACEntityRegistry; import com.github.alexmodguy.alexscaves.server.item.ACItemRegistry; +import net.minecraft.core.BlockPos; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; @@ -15,12 +17,21 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.FireworkRocketEntity; import net.minecraft.world.entity.projectile.ProjectileUtil; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.component.FireworkExplosion; +import net.minecraft.world.item.component.Fireworks; +import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; +import java.util.List; import net.neoforged.api.distmarker.Dist; import net.neoforged.api.distmarker.OnlyIn; @@ -75,6 +86,9 @@ public SodaBottleRocketEntity(Level level, ItemStack stack, LivingEntity livingE @Nullable private LivingEntity getAttachedToEntity() { + if(attachedToEntity != null){ + return attachedToEntity; + } OptionalInt optionalint = this.entityData.get(DATA_ATTACHED_TARGET); if (optionalint.isPresent()) { Entity entity = this.level().getEntity(optionalint.getAsInt()); @@ -84,15 +98,156 @@ private LivingEntity getAttachedToEntity() { } return null; } + + private boolean isAttachedToEntity() { + return this.entityData.get(DATA_ATTACHED_TARGET).isPresent(); + } + + @Override + public boolean isShotAtAngle() { + return this.entityData.get(DATA_SHOT_AT_ANGLE); + } + + @Override + public boolean shouldRenderAtSqrDistance(double distance) { + return distance < 4096.0 && !this.isAttachedToEntity(); + } + + @Override + public boolean shouldRender(double x, double y, double z) { + return super.shouldRender(x, y, z) && !this.isAttachedToEntity(); + } public void tick() { - super.tick(); + if (this.isAttachedToEntity()) { + if (this.attachedToEntity == null) { + this.attachedToEntity = getAttachedToEntity(); + } + + if (this.attachedToEntity != null) { + Vec3 vec3; + if (this.attachedToEntity.isFallFlying()) { + Vec3 vec31 = this.attachedToEntity.getLookAngle(); + double d0 = 1.5D; + double d1 = 0.1D; + Vec3 vec32 = this.attachedToEntity.getDeltaMovement(); + this.attachedToEntity.setDeltaMovement(vec32.add(vec31.x * 0.1D + (vec31.x * 1.5D - vec32.x) * 0.5D, vec31.y * 0.1D + (vec31.y * 1.5D - vec32.y) * 0.5D, vec31.z * 0.1D + (vec31.z * 1.5D - vec32.z) * 0.5D)); + vec3 = this.attachedToEntity.getHandHoldingItemAngle(ACItemRegistry.PURPLE_SODA_BOTTLE_ROCKET.get()); + } else { + vec3 = Vec3.ZERO; + } + + this.setPos(this.attachedToEntity.getX() + vec3.x, this.attachedToEntity.getY() + vec3.y, this.attachedToEntity.getZ() + vec3.z); + this.setDeltaMovement(this.attachedToEntity.getDeltaMovement()); + } + } else { + if (!this.isShotAtAngle()) { + double d2 = this.horizontalCollision ? 1.0D : 1.15D; + this.setDeltaMovement(this.getDeltaMovement().multiply(d2, 1.0D, d2).add(0.0D, 0.04D, 0.0D)); + } + + Vec3 vec33 = this.getDeltaMovement(); + this.move(MoverType.SELF, vec33); + this.setDeltaMovement(vec33); + } + + HitResult hitresult = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); + if (!this.noPhysics) { + this.hitTargetOrDeflectSelf(hitresult); + this.hasImpulse = true; + } + + this.updateRotation(); + if (this.life == 0 && !this.isSilent()) { + this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.FIREWORK_ROCKET_LAUNCH, SoundSource.AMBIENT, 3.0F, 1.0F); + } + + ++this.life; ++this.phageAge; + if (this.level().isClientSide && this.life % 2 < 2) { + this.level().addParticle(ParticleTypes.FIREWORK, this.getX(), this.getY(), this.getZ(), this.random.nextGaussian() * 0.05D, -this.getDeltaMovement().y * 0.5D, this.random.nextGaussian() * 0.05D); + } if (this.level().isClientSide) { for(int i = 0; i < 5; i++){ this.level().addParticle(ACParticleRegistry.PURPLE_SODA_BUBBLE.get(), this.getX(), this.getY() - 0.3D, this.getZ(), this.random.nextGaussian() * 0.25D, -this.getDeltaMovement().y * 0.5D, this.random.nextGaussian() * 0.25D); } } + if (!this.level().isClientSide && this.life > this.lifetime) { + this.explode(); + } + } + + private void explode() { + this.level().broadcastEntityEvent(this, (byte)17); + this.gameEvent(GameEvent.EXPLODE, this.getOwner()); + this.dealExplosionDamage(); + this.discard(); + } + + @Override + protected void onHitEntity(EntityHitResult result) { + super.onHitEntity(result); + if (!this.level().isClientSide) { + this.explode(); + } + } + + @Override + protected void onHitBlock(BlockHitResult result) { + BlockPos blockpos = new BlockPos(result.getBlockPos()); + this.level().getBlockState(blockpos).entityInside(this.level(), blockpos, this); + if (!this.level().isClientSide() && this.hasExplosion()) { + this.explode(); + } + + super.onHitBlock(result); + } + + private boolean hasExplosion() { + return !this.getExplosions().isEmpty(); + } + + private List getExplosions() { + ItemStack itemstack = this.entityData.get(DATA_FIREWORKS_ITEM); + Fireworks fireworks = itemstack.get(DataComponents.FIREWORKS); + return fireworks != null ? fireworks.explosions() : List.of(); + } + + private void dealExplosionDamage() { + float f = 0.0F; + List list = this.getExplosions(); + if (!list.isEmpty()) { + f = 5.0F + (float)(list.size() * 2); + } + + if (f > 0.0F) { + if (this.attachedToEntity != null) { + this.attachedToEntity.hurt(this.damageSources().fireworks(this, this.getOwner()), 5.0F + (float)(list.size() * 2)); + } + + double d0 = 5.0; + Vec3 vec3 = this.position(); + + for (LivingEntity livingentity : this.level().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox().inflate(5.0))) { + if (livingentity != this.attachedToEntity && !(this.distanceToSqr(livingentity) > 25.0)) { + boolean flag = false; + + for (int i = 0; i < 2; i++) { + Vec3 vec31 = new Vec3(livingentity.getX(), livingentity.getY(0.5 * (double)i), livingentity.getZ()); + HitResult hitresult = this.level().clip(new ClipContext(vec3, vec31, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)); + if (hitresult.getType() == HitResult.Type.MISS) { + flag = true; + break; + } + } + + if (flag) { + float f1 = f * (float)Math.sqrt((5.0 - (double)this.distanceTo(livingentity)) / 5.0); + livingentity.hurt(this.damageSources().fireworks(this, this.getOwner()), f1); + } + } + } + } } @OnlyIn(Dist.CLIENT) diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SubmarineEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SubmarineEntity.java index 370151035..7cb3357b8 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SubmarineEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/SubmarineEntity.java @@ -31,6 +31,8 @@ import net.neoforged.neoforge.common.ItemAbilities; import net.neoforged.neoforge.fluids.FluidType; +import javax.annotation.Nullable; + public class SubmarineEntity extends Entity implements KeybindUsingMount { private static final EntityDataAccessor RIGHT_PROPELLER_ROT = SynchedEntityData.defineId(SubmarineEntity.class, EntityDataSerializers.FLOAT); private static final EntityDataAccessor LEFT_PROPELLER_ROT = SynchedEntityData.defineId(SubmarineEntity.class, EntityDataSerializers.FLOAT); @@ -128,7 +130,9 @@ public void tick() { damageSustained--; } this.xRotO = this.getXRot(); - this.yRotO = Mth.wrapDegrees(this.getYRot()); + // Wrap yRot to [-180, 180] range to prevent continuous spinning during interpolation + this.setYRot(Mth.wrapDegrees(this.getYRot())); + this.yRotO = this.getYRot(); this.prevSonarFlashAmount = sonarFlashAmount; if(this.getDangerAlertTicks() > 0 && sonarFlashAmount < 1.0F){ sonarFlashAmount += 0.25F; @@ -146,18 +150,10 @@ public void tick() { } } float acceleration = this.getAcceleration(); + // Handle lerp interpolation for non-local controlled entities + this.tickLerp(); + if (this.level().isClientSide) { - if (this.lSteps > 0) { - double d5 = this.getX() + (this.lx - this.getX()) / (double) this.lSteps; - double d6 = this.getY() + (this.ly - this.getY()) / (double) this.lSteps; - double d7 = this.getZ() + (this.lz - this.getZ()) / (double) this.lSteps; - this.setYRot(Mth.wrapDegrees((float) this.lyr)); - this.setXRot(this.getXRot() + (float) (this.lxr - (double) this.getXRot()) / (float) this.lSteps); - --this.lSteps; - this.setPos(d5, d6, d7); - } else { - this.reapplyPosition(); - } Player player = AlexsCaves.PROXY.getClientSidePlayer(); if (player != null && player.isPassengerOfSameVehicle(this)) { if (AlexsCaves.PROXY.isKeyDown(0) && controlUpTicks < 2) { @@ -176,7 +172,16 @@ public void tick() { if (this.isVehicle() && this.isInWaterOrBubble() && this.isAlive()) { AlexsCaves.PROXY.playWorldSound(this, (byte) 15); } - } else { + } + + // Movement logic runs on both sides when controlled by local instance, or server-side only otherwise + if (this.isControlledByLocalInstance()) { + // Handle player control input (steering and acceleration) + if (this.getControllingPassenger() instanceof Player player) { + this.tickController(player); + } + // Re-fetch acceleration after tickController may have modified it + acceleration = this.getAcceleration(); if (acceleration < 0.0F) { this.setAcceleration(Math.min(0F, acceleration + 0.01F)); } @@ -195,6 +200,12 @@ public void tick() { this.move(MoverType.SELF, this.getDeltaMovement().scale(0.9F)); this.setDeltaMovement(this.getDeltaMovement().multiply(0.1F, 0.3F, 0.1F)); } + } else { + this.setDeltaMovement(Vec3.ZERO); + } + + // Server-side only: oxidization and danger alert + if (!this.level().isClientSide) { if (!isWaxed() && this.getOxidizationLevel() < 3) { if (oxidizeTime > 0) { oxidizeTime--; @@ -273,10 +284,22 @@ public void lerpTo(double x, double y, double z, float yr, float xr, int steps, this.lz = z; this.lyr = yr; this.lxr = xr; - this.lSteps = steps; + this.lSteps = 10; this.setDeltaMovement(this.lxd, this.lyd, this.lzd); } + private void tickLerp() { + if (this.isControlledByLocalInstance()) { + this.lSteps = 0; + this.syncPacketPositionCodec(this.getX(), this.getY(), this.getZ()); + } + + if (this.lSteps > 0) { + this.lerpPositionAndRotationStep(this.lSteps, this.lx, this.ly, this.lz, this.lyr, this.lxr); + --this.lSteps; + } + } + @Override public void lerpMotion(double lerpX, double lerpY, double lerpZ) { this.lxd = lerpX; @@ -330,6 +353,13 @@ public boolean canBeRiddenUnderFluidType(FluidType type, Entity rider) { return type.supportsBoating(null); } + @Nullable + @Override + public LivingEntity getControllingPassenger() { + Entity entity = this.getFirstPassenger(); + return entity instanceof LivingEntity livingEntity ? livingEntity : null; + } + @Override protected Entity.MovementEmission getMovementEmission() { return MovementEmission.EVENTS; @@ -344,12 +374,10 @@ public boolean shouldRender(double x, double y, double z) { public void positionRider(Entity passenger, MoveFunction moveFunction) { if (this.isPassengerOfSameVehicle(passenger) && passenger instanceof LivingEntity living && !this.touchingUnloadedChunk()) { clampRotation(living); - if (passenger instanceof Player) { - tickController((Player) passenger); - } float f1 = -(this.getXRot() / 40F); Vec3 seatOffset = new Vec3(0F, -0.2F, 0.8F + f1).xRot((float) Math.toRadians(this.getXRot())).yRot((float) Math.toRadians(-this.getYRot())); - double d0 = this.getY() + this.getBbHeight() * 0.5F + seatOffset.y; + Vec3 attachPoint = passenger.getVehicleAttachmentPoint(this); + double d0 = this.getY() + this.getBbHeight() * 0.5F + seatOffset.y - attachPoint.y; moveFunction.accept(passenger, this.getX() + seatOffset.x, d0, this.getZ() + seatOffset.z); living.setAirSupply(Math.min(living.getAirSupply() + 2, living.getMaxAirSupply())); } else { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/ThrownIceCreamScoopEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/ThrownIceCreamScoopEntity.java index 895e61c52..2c694b102 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/ThrownIceCreamScoopEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/ThrownIceCreamScoopEntity.java @@ -3,10 +3,13 @@ import com.github.alexmodguy.alexscaves.server.entity.ACEntityRegistry; import com.github.alexmodguy.alexscaves.server.item.ACItemRegistry; import com.github.alexmodguy.alexscaves.server.misc.ACTagRegistry; +import com.github.alexmodguy.alexscaves.server.potion.ACEffectRegistry; import net.minecraft.core.particles.ItemParticleOption; import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.ThrowableItemProjectile; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -17,6 +20,9 @@ import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.HitResult; +import java.util.ArrayList; +import java.util.List; + public class ThrownIceCreamScoopEntity extends ThrowableItemProjectile { public ThrownIceCreamScoopEntity(EntityType entityType, Level level) { @@ -44,7 +50,11 @@ protected void onHitEntity(EntityHitResult hitResult) { super.onHitEntity(hitResult); hitResult.getEntity().hurt(damageSources().thrown(this, this.getOwner()), 0.0F); if(hitResult.getEntity() instanceof LivingEntity living){ - living.removeAllEffects(); + for (MobEffectInstance mobEffectInstance : new ArrayList<>(living.getActiveEffects())) { + if (mobEffectInstance.getEffect().value() != ACEffectRegistry.IRRADIATED.value() && mobEffectInstance.getEffect().value() != ACEffectRegistry.DARKNESS_INCARNATE.value() && mobEffectInstance.getEffect().value() != ACEffectRegistry.BUBBLED.value()){ + living.removeEffect(mobEffectInstance.getEffect()); + } + } } } @@ -57,6 +67,7 @@ protected void onHit(HitResult hitResult) { } + @Override protected Item getDefaultItem() { return ACItemRegistry.VANILLA_ICE_CREAM_SCOOP.get(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/WaterBoltEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/WaterBoltEntity.java index c2239e530..1866d6a7d 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/WaterBoltEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/item/WaterBoltEntity.java @@ -1,10 +1,8 @@ package com.github.alexmodguy.alexscaves.server.entity.item; -import com.github.alexmodguy.alexscaves.AlexsCaves; import com.github.alexmodguy.alexscaves.client.particle.ACParticleRegistry; import com.github.alexmodguy.alexscaves.server.entity.ACEntityRegistry; import com.github.alexmodguy.alexscaves.server.entity.living.DeepOneBaseEntity; -import com.github.alexmodguy.alexscaves.server.message.UpdateEffectVisualityEntityMessage; import com.github.alexmodguy.alexscaves.server.misc.ACSoundRegistry; import com.github.alexmodguy.alexscaves.server.potion.ACEffectRegistry; import net.minecraft.core.BlockPos; @@ -207,11 +205,9 @@ private void damageMobs() { for (LivingEntity entity : this.level().getEntitiesOfClass(LivingEntity.class, bashBox)) { if (!isAlliedTo(entity) && !(entity instanceof DeepOneBaseEntity) && (owner == null || !entity.is(owner) && !entity.isAlliedTo(owner))) { lastHitMob = entity; - if (entity.hurt(source, 3.0F) && this.isBubbling()) { + entity.hurt(source, 3.0F); + if (this.isBubbling() && !entity.hasEffect(ACEffectRegistry.BUBBLED)) { entity.addEffect(new MobEffectInstance(ACEffectRegistry.BUBBLED, 200)); - if (!entity.level().isClientSide) { - AlexsCaves.sendMSGToAll(new UpdateEffectVisualityEntityMessage(entity.getId(), this.getId(), 1, 200)); - } } } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/BoundroidEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/BoundroidEntity.java index 6a8c703fb..2a44eae79 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/BoundroidEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/BoundroidEntity.java @@ -30,8 +30,11 @@ import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.player.Player; +import net.minecraft.util.RandomSource; import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; @@ -65,6 +68,10 @@ public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 5.0D).add(Attributes.ARMOR, 20.0D).add(Attributes.MOVEMENT_SPEED, 0.2D).add(Attributes.FOLLOW_RANGE, 32.0D).add(Attributes.MAX_HEALTH, 20.0D); } + public static boolean checkMagneticCaveSpawnRules(EntityType entityType, ServerLevelAccessor levelAccessor, MobSpawnType mobSpawnType, BlockPos blockPos, RandomSource randomSource) { + return checkAnyLightMonsterSpawnRules(entityType, levelAccessor, mobSpawnType, blockPos, randomSource); + } + protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); this.goalSelector.addGoal(1, new LookAtPlayerGoal(this, Player.class, 15.0F)); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CaniacEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CaniacEntity.java index e2ecda71b..8c0d8d0b4 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CaniacEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CaniacEntity.java @@ -73,7 +73,7 @@ public static AttributeSupplier.Builder createAttributes() { } public static boolean checkCaniacSpawnRules(EntityType entityType, ServerLevelAccessor levelAccessor, MobSpawnType mobSpawnType, BlockPos blockPos, RandomSource randomSource) { - return checkMonsterSpawnRules(entityType, levelAccessor, mobSpawnType, blockPos, randomSource) && randomSource.nextInt(10) == 0; + return checkAnyLightMonsterSpawnRules(entityType, levelAccessor, mobSpawnType, blockPos, randomSource) && randomSource.nextInt(10) == 0; } protected void registerGoals() { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CaramelCubeEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CaramelCubeEntity.java index f232cc1b6..2c404ab23 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CaramelCubeEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CaramelCubeEntity.java @@ -65,7 +65,7 @@ public static AttributeSupplier.Builder createAttributes() { } public static boolean checkCaramelCubeSpawnRules(EntityType entityType, ServerLevelAccessor levelAccessor, MobSpawnType mobSpawnType, BlockPos blockPos, RandomSource randomSource) { - return checkMonsterSpawnRules(entityType, levelAccessor, mobSpawnType, blockPos, randomSource); + return checkAnyLightMonsterSpawnRules(entityType, levelAccessor, mobSpawnType, blockPos, randomSource); } protected void registerGoals() { diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CorrodentEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CorrodentEntity.java index 004829197..0fb45afc4 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CorrodentEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/CorrodentEntity.java @@ -326,10 +326,9 @@ public float getTrailTransformation(int pointer, int index, float partialTick) { return d0 + d1 * partialTick; } - public Vec3 collide(Vec3 vec3) { - // super.collide() removed in 1.21, use ICustomCollisions for both cases - return ICustomCollisions.getAllowedMovementForEntity(this, vec3); - } + // Collision is handled by CorrodentCollisionMixin which injects into Entity.collide() + // When digging: uses ICustomCollisions.getAllowedMovementForEntity() to pass through blocks + // When not digging: uses vanilla collision logic public void remove(Entity.RemovalReason removalReason) { AlexsCaves.PROXY.clearSoundCacheFor(this); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/FerrouslimeEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/FerrouslimeEntity.java index 25911c89b..2e54f6265 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/FerrouslimeEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/FerrouslimeEntity.java @@ -30,6 +30,7 @@ import net.minecraft.world.entity.ai.navigation.PathNavigation; import net.minecraft.world.entity.monster.Monster; import net.minecraft.world.entity.player.Player; +import net.minecraft.util.RandomSource; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ServerLevelAccessor; @@ -83,6 +84,10 @@ public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 2.0D).add(Attributes.MOVEMENT_SPEED, 0.35D).add(Attributes.MAX_HEALTH, 10.0D); } + public static boolean checkMagneticCaveSpawnRules(EntityType entityType, ServerLevelAccessor levelAccessor, MobSpawnType mobSpawnType, BlockPos blockPos, RandomSource randomSource) { + return checkAnyLightMonsterSpawnRules(entityType, levelAccessor, mobSpawnType, blockPos, randomSource); + } + public boolean isNoGravity() { return true; } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumWormEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumWormEntity.java index dd5933063..7f583cba8 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumWormEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumWormEntity.java @@ -52,8 +52,6 @@ import net.minecraft.world.phys.shapes.BooleanOp; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; -import net.neoforged.neoforge.common.NeoForgeMod; -import net.neoforged.neoforge.entity.PartEntity; import javax.annotation.Nullable; import java.util.Collection; @@ -76,6 +74,7 @@ public class GumWormEntity extends Monster implements ICustomCollisions, KaijuMo private static final EntityDataAccessor RIDER_LEAP_TIME_MAX = SynchedEntityData.defineId(GumWormEntity.class, EntityDataSerializers.INT); private static final EntityDataAccessor DIGGING = SynchedEntityData.defineId(GumWormEntity.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor VALID_RIDER = SynchedEntityData.defineId(GumWormEntity.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor RETURNING_TO_GROUND = SynchedEntityData.defineId(GumWormEntity.class, EntityDataSerializers.BOOLEAN); private int lSteps; private double lx; private double ly; @@ -106,6 +105,17 @@ public class GumWormEntity extends Monster implements ICustomCollisions, KaijuMo private int stopDiggingNoiseCooldown; private boolean wasDiggingLastTick; private int outOfGroundTime = 0; + private int postRidingDigDownTicks = 0; // Time after riding ends to force digging down + private int stuckAboveGobthumperTicks = 0; // Fallback counter when stuck above gobthumper position + private int stuckInAirTicks = 0; // Fallback counter when stuck motionless in air + private Vec3 lastTickPosition = null; // Track position to detect if stuck + // returningToGround is now synced via RETURNING_TO_GROUND EntityDataAccessor + private boolean returnNeedsInitialBurst = false; // Whether we need to give initial strong push + private double returnTargetX = 0; // Target X to return to (20+ blocks from gobthumper) + private double returnTargetY = 0; // Target Y level to return to + private double returnTargetZ = 0; // Target Z to return to (20+ blocks from gobthumper) + private Vec3 returnMoveDirection = null; // Fixed movement direction during return mode + private boolean detectedStuckState = false; // Once we detect stuck state, don't reset counter public GumWormEntity(EntityType type, Level level) { super(type, level); @@ -147,6 +157,7 @@ protected void defineSynchedData(SynchedEntityData.Builder builder) { builder.define(RIDER_LEAP_TIME, 0); builder.define(DIGGING, false); builder.define(VALID_RIDER, false); + builder.define(RETURNING_TO_GROUND, false); } protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { @@ -180,6 +191,16 @@ public void tick() { prevScreenShakeAmount = screenShakeAmount; prevMouthOpenProgress = mouthOpenProgress; + // Check if the riding player is no longer riding the segment - if so, immediately clear riding mode + if (ridingPlayer != null && ridingModeTicks > 0) { + Entity ridingSegment = this.getRidingSegment(); + if (ridingSegment == null || ridingPlayer.getVehicle() != ridingSegment) { + ridingPlayer = null; + ridingModeTicks = 0; + postRidingDigDownTicks = 40; // Force digging down for 2 seconds after dismount + } + } + if (isMoving() || surfacePosition == null) { surfacePosition = calculateLightAbovePosition(); } @@ -195,13 +216,15 @@ public void tick() { this.yBodyRot = this.getYRot(); this.yHeadRot = this.getYRot(); Entity target = this.getTarget(); - if(!level().isClientSide && (!this.isLeaping() || (target == null || !target.isAlive())) && !this.isRidingMode()){ + if(!level().isClientSide && (!this.isLeaping() || (target == null || !target.isAlive())) && !this.isRidingMode() && !isReturningToGround()){ this.setTargetDigPitch((float) (-(Mth.atan2(this.getDeltaMovement().y, this.getDeltaMovement().horizontalDistance()) * (180F / (float) Math.PI)))); } if (screenShakeAmount > 0) { screenShakeAmount = Math.max(0, screenShakeAmount - 0.34F); } - this.digPitch = Mth.approachDegrees(digPitch, getTargetDigPitch(), 5); + // During return mode, rotate pitch faster (20 degrees/tick instead of 5) + float pitchSpeed = isReturningToGround() ? 20 : 5; + this.digPitch = Mth.approachDegrees(digPitch, getTargetDigPitch(), pitchSpeed); if (this.isMoving()) { this.zRot += (this.entityData.get(Z_ROT_DIRECTION) ? -10 : 10); if (random.nextInt(300) == 0 && !level().isClientSide) { @@ -235,16 +258,219 @@ public void tick() { boolean flag = false; BlockState centralState = level().getBlockState(this.blockPosition()); BlockState centralStateBelow = level().getBlockState(this.blockPosition().below()); - if ((!isSafeDig(level(), this.blockPosition())) && !this.isLeaping()) { + + // Fallback mechanism: detect if GumWorm is stuck and needs to return to ground + // When triggered, GumWorm will phase through all blocks until reaching target Y level + boolean forcingReturnToGobthumper = false; + + // Handle active "return to ground" mode - phase through blocks until reaching underground + // Head leads, body follows - like a diving worm + if (isReturningToGround()) { + forcingReturnToGobthumper = true; + // Enable phasing through blocks + this.noPhysics = true; + // Clear leaping state when returning to ground + this.setLeaping(false); + + // CLIENT SIDE: Force digPitch to match the synced targetDigPitch immediately + // Don't use local deltaMovement as it may not match server's direction + if (level().isClientSide) { + // Directly set digPitch to targetDigPitch (synced from server) + this.digPitch = getTargetDigPitch(); + } + + // SERVER SIDE: Handle the actual movement logic + if (!level().isClientSide) { + // Target is FIXED at returnTargetX/Y/Z - calculated when return mode started + int targetWorldHeight = level().getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, (int) returnTargetX, (int) returnTargetZ); + double horizontalDistance = Math.sqrt((returnTargetX - this.getX()) * (returnTargetX - this.getX()) + (returnTargetZ - this.getZ()) * (returnTargetZ - this.getZ())); + + // INITIAL BURST: Calculate and LOCK the movement direction at this moment + if (returnNeedsInitialBurst) { + returnNeedsInitialBurst = false; + + // Calculate FIXED direction from current position to target - this will be used for entire return + Vec3 targetPos = new Vec3(returnTargetX, returnTargetY, returnTargetZ); + Vec3 directionToTarget = targetPos.subtract(this.position()); + double distanceToTarget = directionToTarget.length(); + returnMoveDirection = distanceToTarget > 0.1 ? directionToTarget.normalize() : new Vec3(0, -1, 0); + + // Calculate and LOCK target pitch and yaw based on fixed direction + float targetPitch = (float) (-(Mth.atan2(returnMoveDirection.y, returnMoveDirection.horizontalDistance()) * (180F / (float) Math.PI))); + float targetYaw = -((float) Mth.atan2(returnMoveDirection.x, returnMoveDirection.z)) * (180F / (float) Math.PI); + + // Strong initial velocity - directly SET the movement + this.setDeltaMovement(returnMoveDirection.scale(1.8F)); + // Immediately face the target - SET directly, no gradual approach + this.setYRot(targetYaw); + // Directly set digPitch for instant head rotation + this.digPitch = targetPitch; + this.setTargetDigPitch(targetPitch); + } + + // CONTINUOUS MOVEMENT: Use the FIXED direction calculated at initial burst + // Don't recalculate direction - keep heading in the same direction + if (returnMoveDirection != null) { + // DIRECT velocity set using FIXED direction + double speed = 1.2; // Fast constant speed + this.setDeltaMovement(returnMoveDirection.scale(speed)); + + // FORCE the head pitch to stay locked - override the approachDegrees that ran earlier in tick() + float lockedPitch = (float) (-(Mth.atan2(returnMoveDirection.y, returnMoveDirection.horizontalDistance()) * (180F / (float) Math.PI))); + this.digPitch = lockedPitch; + this.setTargetDigPitch(lockedPitch); + } + + // Check if we've reached the target (close enough horizontally AND underground) + if (horizontalDistance <= 5 && this.getY() <= targetWorldHeight - 5) { + // Successfully reached target underground, exit return mode and let normal AI take over + setReturningToGround(false); + returnMoveDirection = null; // Clear fixed direction + this.noPhysics = false; + stuckAboveGobthumperTicks = 0; + stuckInAirTicks = 0; + forcingReturnToGobthumper = false; + detectedStuckState = false; + // Set postRidingDigDownTicks to ensure we stay underground initially + postRidingDigDownTicks = 60; // 3 seconds of staying underground before AI can move + } + } + + flag = true; + } else if (!level().isClientSide && !isRidingMode() && postRidingDigDownTicks <= 0 && !isLeaping()) { + // Only detect stuck state when NOT leaping - leaping worms are under Goal control and will naturally fall + // IMPORTANT: Don't detect stuck state during postRidingDigDownTicks - worm is intentionally staying underground + BlockPos gobthumperPos = getGobthumperPos(); + + // Check if stuck motionless (position hasn't changed significantly) + Vec3 currentPos = this.position(); + boolean isMotionless = false; + if (lastTickPosition != null) { + double movement = currentPos.distanceToSqr(lastTickPosition); + // Consider motionless if moved less than 0.01 blocks squared + isMotionless = movement < 0.01; + } + lastTickPosition = currentPos; + + // Check world surface height at current position + int worldHeight = level().getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, (int) this.getX(), (int) this.getZ()); + + // Determine if GumWorm is in an abnormal position + boolean isAboveSurface = this.getY() > worldHeight; + boolean isInUnsafePosition = !isSafeDig(level(), this.blockPosition()); + + // Calculate target Y for return (gobthumper Y or 10 blocks below surface) + double targetY = gobthumperPos != null ? gobthumperPos.getY() : (worldHeight - 10); + + if (gobthumperPos != null) { + double heightAboveGobthumper = this.getY() - gobthumperPos.getY(); + // Detect stuck state if above gobthumper AND either: + // 1. Above the world surface (in open air above ground) + // 2. Inside a solid block (stuck in ceiling in a cave) + // This ensures worms stuck on cave ceilings above the gobthumper are also detected + boolean isInsideSolidBlock = centralState.isSolid(); + if (heightAboveGobthumper > 8.0 && (isAboveSurface || isInsideSolidBlock)) { + detectedStuckState = true; + } + + // Keep counting if we've ever detected stuck state (don't reset when worm moves down) + if (detectedStuckState) { + stuckAboveGobthumperTicks++; + // After 3 seconds (60 ticks) of being in stuck state, activate return to ground mode + if (stuckAboveGobthumperTicks > 60) { + // Calculate return target: 20-25 blocks away from gobthumper in random direction + double angle = random.nextDouble() * Math.PI * 2; + double distance = 20 + random.nextDouble() * 5; // 20-25 blocks + returnTargetX = gobthumperPos.getX() + Math.cos(angle) * distance; + returnTargetZ = gobthumperPos.getZ() + Math.sin(angle) * distance; + // Calculate target Y: 10 blocks below ground at target location + int targetGroundHeight = level().getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, (int) returnTargetX, (int) returnTargetZ); + returnTargetY = targetGroundHeight - 10; + + setReturningToGround(true); + returnNeedsInitialBurst = true; // Give strong initial push + forcingReturnToGobthumper = true; + this.setLeaping(false); + } + } + } else { + // No gobthumper position - check if above surface + if (isAboveSurface) { + detectedStuckState = true; + } + + if (detectedStuckState) { + stuckAboveGobthumperTicks++; + if (stuckAboveGobthumperTicks > 60) { + // No gobthumper, just go straight down at current position + returnTargetX = this.getX(); + returnTargetZ = this.getZ(); + // Target: 10 blocks below ground at current location + returnTargetY = worldHeight - 10; + + setReturningToGround(true); + returnNeedsInitialBurst = true; // Give strong initial push + forcingReturnToGobthumper = true; + this.setLeaping(false); + } + } + } + + // Additional fallback: if stuck motionless anywhere for too long (regardless of position) + // This is the ultimate safety net + if (isMotionless && !forcingReturnToGobthumper) { + stuckInAirTicks++; + // After 3 seconds (60 ticks) of being completely stuck, activate return mode + if (stuckInAirTicks > 60) { + if (gobthumperPos != null) { + // Calculate return target: 20-25 blocks away from gobthumper + double angle = random.nextDouble() * Math.PI * 2; + double distance = 20 + random.nextDouble() * 5; + returnTargetX = gobthumperPos.getX() + Math.cos(angle) * distance; + returnTargetZ = gobthumperPos.getZ() + Math.sin(angle) * distance; + } else { + returnTargetX = this.getX(); + returnTargetZ = this.getZ(); + } + // Target: 10 blocks below ground at target location + int targetGroundHeight = level().getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, (int) returnTargetX, (int) returnTargetZ); + returnTargetY = targetGroundHeight - 10; + + setReturningToGround(true); + returnNeedsInitialBurst = true; // Give strong initial push + forcingReturnToGobthumper = true; + detectedStuckState = true; + // Also clear leaping state + this.setLeaping(false); + } + } else if (!isMotionless) { + // Don't fully reset counter - reduce by half so occasional small movements don't prevent trigger + stuckInAirTicks = Math.max(0, stuckInAirTicks - 10); + } + } else { + stuckAboveGobthumperTicks = 0; + stuckInAirTicks = 0; + detectedStuckState = false; + } + + // After dismounting, force dig down into the ground instead of bouncing up + if (postRidingDigDownTicks > 0) { + postRidingDigDownTicks--; + if (canDigBlock(centralStateBelow) || centralStateBelow.isAir()) { + this.setDeltaMovement(this.getDeltaMovement().scale(0.8).add(0, -0.6, 0)); + flag = true; + } + } else if (!forcingReturnToGobthumper && (!isSafeDig(level(), this.blockPosition())) && !this.isLeaping()) { + // Skip the bounce-up logic if we're forcing return to gobthumper if (!canDigBlock(centralStateBelow)) { this.setDeltaMovement(random.nextFloat() - 0.5F, 0.8F, random.nextFloat() - 0.5F); flag = true; + } else if((surfaceY < this.getEyeY() || centralStateBelow.isAir() || this.isInFluidType()) && isSafeDig(level(), this.blockPosition().below()) && !isRidingMode()){ + if(outOfGroundTime++ > 10){ + this.setDeltaMovement(this.getDeltaMovement().add(0, -0.5, 0)); + } } - }else if((surfaceY < this.getEyeY() || centralStateBelow.isAir() || this.isInFluidType()) && isSafeDig(level(), this.blockPosition().below()) && !isRidingMode() && !this.isLeaping()){ - if(outOfGroundTime++ > 10){ - this.setDeltaMovement(this.getDeltaMovement().add(0, -0.5, 0)); - } - }else{ + }else if (!forcingReturnToGobthumper) { outOfGroundTime = 0; } if(isRidingMode()){ @@ -276,7 +502,10 @@ public void tick() { attemptPlayStopDiggingNoise(); } } - this.setNoGravity(!this.getNavigation().isDone() && !this.isLeaping() && !flag && !this.isInWall()); + // When forcing return to gobthumper or flag is set, always enable gravity to allow falling + // Also enable gravity if above the ground surface (in the air) to prevent floating after leap ends + boolean isAboveGroundLevel = this.getY() > surfaceY; + this.setNoGravity(!forcingReturnToGobthumper && !isAboveGroundLevel && !this.getNavigation().isDone() && !this.isLeaping() && !flag && !this.isInWall()); if (timeBetweenAttacks > 0) { timeBetweenAttacks--; } @@ -348,8 +577,9 @@ public boolean isDigging() { return this.entityData.get(DIGGING); } - public float getStepHeight() { - return isRidingMode() ? 5.0F : 1.0F; + @Override + public float maxUpStep() { + return isRidingMode() ? 5.0F : super.maxUpStep(); } public void remove(Entity.RemovalReason removalReason) { @@ -357,23 +587,20 @@ public void remove(Entity.RemovalReason removalReason) { super.remove(removalReason); } - protected void dropAllDeathLoot(DamageSource damageSource) { - Entity entity = damageSource.getEntity(); - - // In 1.21, getLootingLevel is removed from CommonHooks + @Override + protected void dropAllDeathLoot(ServerLevel serverLevel, DamageSource damageSource) { this.captureDrops(new java.util.ArrayList<>()); boolean flag = this.lastHurtByPlayerTime > 0; - if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { + if (this.shouldDropLoot() && serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { this.dropFromLootTable(damageSource, flag); - this.dropCustomDeathLoot((ServerLevel) this.level(), damageSource, flag); + this.dropCustomDeathLoot(serverLevel, damageSource, flag); } this.dropEquipment(); - this.dropExperience(entity); + this.dropExperience(damageSource.getEntity()); Collection drops = captureDrops(null); - // In 1.21, onLivingDrops takes 4 params: (entity, source, drops, recentlyHit) if (!net.neoforged.neoforge.common.CommonHooks.onLivingDrops(this, damageSource, drops, lastHurtByPlayerTime > 0)){ drops.forEach(e -> dropItemAtSurface(e)); } @@ -436,7 +663,8 @@ public void spawnDustParticles(boolean surface) { } } - public void lerpTo(double x, double y, double z, float yr, float xr, int steps, boolean b) { + @Override + public void lerpTo(double x, double y, double z, float yr, float xr, int steps) { this.lx = x; this.ly = y; this.lz = z; @@ -465,6 +693,14 @@ public void setLeaping(boolean leaping) { this.entityData.set(LEAPING, leaping); } + /** + * Set a forced dig-down period to prevent bounce-up behavior. + * Used after gobthumper destruction or dismounting. + */ + public void setForceDigDownTicks(int ticks) { + this.postRidingDigDownTicks = ticks; + } + public boolean isBiting() { return this.entityData.get(BITING); } @@ -489,6 +725,14 @@ public float getTargetDigPitch() { return this.entityData.get(TARGET_DIG_PITCH); } + public boolean isReturningToGround() { + return this.entityData.get(RETURNING_TO_GROUND); + } + + public void setReturningToGround(boolean returning) { + this.entityData.set(RETURNING_TO_GROUND, returning); + } + public BlockPos getGobthumperPos() { return this.entityData.get(GOBTHUMPER_POS).orElse(null); } @@ -585,6 +829,10 @@ private double calculateSurfaceY() { return 1D + mutableBlockPos.getY(); } + public double getSurfaceY() { + return surfaceY; + } + @javax.annotation.Nullable public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficultyIn, MobSpawnType reason, @javax.annotation.Nullable SpawnGroupData spawnDataIn) { @@ -638,9 +886,10 @@ public boolean canPassThrough(BlockPos blockPos, BlockState blockState, VoxelSha } public boolean isColliding(BlockPos pos, BlockState blockstate) { - return canDigBlock(blockstate) && super.isColliding(pos, blockstate); + return (!this.isDigging() || canDigBlock(blockstate)) && super.isColliding(pos, blockstate); } + @Override public Vec3 collide(Vec3 vec3) { return ICustomCollisions.getAllowedMovementForEntity(this, vec3); } @@ -685,7 +934,7 @@ public void push(Entity entity) { } public static boolean canDigBlock(BlockState state) { - return state.isAir() || !state.is(ACTagRegistry.GUM_WORM_BLOCKS_DIGGING); + return !state.is(ACTagRegistry.GUM_WORM_BLOCKS_DIGGING) && state.getFluidState().isEmpty() && state.canOcclude(); } public boolean isInvulnerableTo(DamageSource damageSource) { @@ -826,7 +1075,8 @@ public void tick() { float digSpeed = 0.25F; Vec3 vector3d1 = vector3d.scale(this.speedModifier * digSpeed / d0); boolean safeDig = isSafeDig(level(), BlockPos.containing(wantedX, Mth.clamp(this.wantedY, this.mob.getY() - 1.0, this.mob.getY() + 1.0), wantedZ)); - if (isSafeDig(level(), BlockPos.containing(wantedX, wantedY, wantedZ))) { + // In riding mode, allow movement even if destination is not safe to dig (surface travel) + if (isSafeDig(level(), BlockPos.containing(wantedX, wantedY, wantedZ)) || GumWormEntity.this.isRidingMode()) { mob.setDeltaMovement(mob.getDeltaMovement().add(vector3d1).scale(0.9F)); } else { mob.setDeltaMovement(mob.getDeltaMovement().add(0, 0.1, 0).scale(0.7F)); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumWormSegmentEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumWormSegmentEntity.java index 8e774edf5..2c7ee0812 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumWormSegmentEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumWormSegmentEntity.java @@ -309,10 +309,14 @@ public void tick() { Vec3 vec31 = distVec.length() > 1F ? distVec.normalize().scale(1F + extraLength) : distVec; Vec3 vec32 = this.position().add(vec31); riddenFlag = head instanceof GumWormEntity gumWorm && gumWorm.isRidingMode(); - if ((!front.isInWall() || riddenFlag) && !(head instanceof GumWormEntity gumWorm && gumWorm.isLeaping())) { + boolean isHeadReturning = head instanceof GumWormEntity gumWorm2 && gumWorm2.isReturningToGround(); + // Skip surface Y clamping if head is leaping OR returning to ground + if ((!front.isInWall() || riddenFlag) && !(head instanceof GumWormEntity gumWorm && gumWorm.isLeaping()) && !isHeadReturning) { float f = Mth.approach((float) this.getY(), riddenFlag ? (float) Math.max(surfaceY, ideal.y) : (float) Math.min(surfaceY, vec31.y), 1F); vec32 = new Vec3(vec32.x, f, vec32.z); } + // Also set noPhysics on segment when head is returning + this.noPhysics = isHeadReturning; this.setPos(vec32); Vec3 frontsBack = front.position().add(new Vec3(0F, 0F, 3F).xRot(-(float) Math.toRadians(front.getXRot())).yRot(-(float) Math.toRadians(front.getYRot()))); double d0 = frontsBack.x - this.getX(); @@ -430,6 +434,7 @@ public boolean isColliding(BlockPos pos, BlockState blockstate) { return GumWormEntity.canDigBlock(blockstate) && super.isColliding(pos, blockstate); } + @Override public Vec3 collide(Vec3 vec3) { return ICustomCollisions.getAllowedMovementForEntity(this, vec3); } @@ -476,7 +481,8 @@ public boolean isMoving() { return f > 0.1F; } - public void lerpTo(double x, double y, double z, float yr, float xr, int steps, boolean b) { + @Override + public void lerpTo(double x, double y, double z, float yr, float xr, int steps) { this.lx = x; this.ly = y; this.lz = z; @@ -511,7 +517,7 @@ public boolean shouldRiderSit() { return false; } public Vec3 getRiderPosition(Entity playerOwner) { - float f = (float) (this.getBbHeight() + 0.25F); + float f = (float) (this.getBbHeight() + 0.25F + playerOwner.getVehicleAttachmentPoint(this).y); Vec3 offset = new Vec3(0.0F, f, 0.15F).xRot((float) -Math.toRadians(this.getXRot())).yRot((float) -Math.toRadians(this.getYRot())); Vec3 position = this.position().add(offset); double setY = surfaceY; @@ -574,6 +580,12 @@ public boolean canBeCollidedWith() { return false; } + @Override + public Vec3 getDismountLocationForPassenger(LivingEntity passenger) { + // Return the surface position so the player dismounts on the ground instead of at the entity's bounding box top + return new Vec3(this.getX(), surfaceY, this.getZ()); + } + public boolean shouldBeSaved() { return (this.getRemovalReason() == null || this.getRemovalReason().shouldSave()) && !this.isPassenger(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumbeeperEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumbeeperEntity.java index a4308eb05..2303e313a 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumbeeperEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/GumbeeperEntity.java @@ -96,7 +96,7 @@ public static AttributeSupplier.Builder createAttributes() { } public static boolean checkGumbeeperSpawnRules(EntityType entityType, ServerLevelAccessor levelAccessor, MobSpawnType mobSpawnType, BlockPos blockPos, RandomSource randomSource) { - return checkMonsterSpawnRules(entityType, levelAccessor, mobSpawnType, blockPos, randomSource) && randomSource.nextInt(10) == 0; + return checkAnyLightMonsterSpawnRules(entityType, levelAccessor, mobSpawnType, blockPos, randomSource) && randomSource.nextInt(10) == 0; } @Override diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/LicowitchEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/LicowitchEntity.java index f302d35c5..3e1895da7 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/LicowitchEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/LicowitchEntity.java @@ -1,5 +1,6 @@ package com.github.alexmodguy.alexscaves.server.entity.living; +import com.github.alexmodguy.alexscaves.AlexsCaves; import com.github.alexmodguy.alexscaves.client.particle.ACParticleRegistry; import com.github.alexmodguy.alexscaves.server.block.ACBlockRegistry; import com.github.alexmodguy.alexscaves.server.entity.ACEntityDataRegistry; @@ -8,7 +9,6 @@ import com.github.alexmodguy.alexscaves.server.entity.ai.LicowitchUseCrucibleGoal; import com.github.alexmodguy.alexscaves.server.entity.util.PossessedByLicowitch; import com.github.alexmodguy.alexscaves.server.item.ACItemRegistry; -import com.github.alexmodguy.alexscaves.server.level.structure.ACStructureRegistry; import com.github.alexmodguy.alexscaves.server.misc.ACSoundRegistry; import com.github.alexmodguy.alexscaves.server.potion.ACEffectRegistry; import com.github.alexthe666.citadel.animation.Animation; @@ -23,6 +23,8 @@ import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundSource; @@ -113,11 +115,14 @@ public static boolean checkLicowitchSpawnRules(EntityType ent } public static boolean isWithinTowerSpawnBounds(ServerLevelAccessor level, BlockPos pos) { - Structure structure = level.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ACStructureRegistry.LICOWITCH_TOWER.getId()); - StructureStart structureStart = level.getLevel().structureManager().getStructureAt(pos, structure); - if (structure != null && structureStart.isValid()) { - //stop spawning on the roof and floor - return pos.getY() < structureStart.getBoundingBox().maxY() - 9 && pos.getY() > structureStart.getBoundingBox().minY() + 2; + ResourceKey structureKey = ResourceKey.create(Registries.STRUCTURE, ResourceLocation.fromNamespaceAndPath(AlexsCaves.MODID, "licowitch_tower")); + Structure structure = level.registryAccess().registryOrThrow(Registries.STRUCTURE).get(structureKey); + if (structure != null) { + StructureStart structureStart = level.getLevel().structureManager().getStructureAt(pos, structure); + if (structureStart.isValid()) { + //stop spawning on the roof and floor + return pos.getY() < structureStart.getBoundingBox().maxY() - 9 && pos.getY() > structureStart.getBoundingBox().minY() + 2; + } } return false; } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/MagnetronEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/MagnetronEntity.java index 045ca07d6..de3c54d08 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/MagnetronEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/MagnetronEntity.java @@ -34,9 +34,11 @@ import net.minecraft.world.entity.ai.navigation.PathNavigation; import net.minecraft.world.entity.item.FallingBlockEntity; import net.minecraft.world.entity.monster.Monster; +import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; @@ -127,6 +129,10 @@ public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 2.0D).add(Attributes.ARMOR, 6.0D).add(Attributes.MOVEMENT_SPEED, 0.2D).add(Attributes.FOLLOW_RANGE, 32.0D).add(Attributes.MAX_HEALTH, 30.0D); } + public static boolean checkMagneticCaveSpawnRules(EntityType entityType, ServerLevelAccessor levelAccessor, MobSpawnType mobSpawnType, BlockPos blockPos, RandomSource randomSource) { + return checkAnyLightMonsterSpawnRules(entityType, levelAccessor, mobSpawnType, blockPos, randomSource); + } + protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); this.goalSelector.addGoal(1, new MeleeGoal()); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/SubterranodonEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/SubterranodonEntity.java index 6b8b14ea9..c7d330eed 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/SubterranodonEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/SubterranodonEntity.java @@ -112,7 +112,7 @@ public static boolean checkSubterranodonSpawnRules(EntityType protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); this.goalSelector.addGoal(1, new SitWhenOrderedToGoal(this)); - this.goalSelector.addGoal(2, new MeleeAttackGoal(this, 1.4D, false)); + this.goalSelector.addGoal(2, new SubterranodonAttackGoal(this, 1.4D)); this.goalSelector.addGoal(3, new SubterranodonFollowOwnerGoal(this, 1.2D, 5.0F, 2.0F, true)); this.goalSelector.addGoal(4, new AnimalJoinPackGoal(this, 30, 5)); this.goalSelector.addGoal(5, new AnimalBreedEggsGoal(this, 1)); @@ -591,6 +591,7 @@ public void calculateEntityAnimation(boolean flying) { this.walkAnimation.update(f2, 0.4F); } + @Override public Vec3 collide(Vec3 movement) { if (this.flightCollisionBox != null && !touchingUnloadedChunk() && this.isVehicle()) { AABB aabb = this.flightCollisionBox; diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/TeletorEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/TeletorEntity.java index 24511ae50..d6fb01933 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/TeletorEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/TeletorEntity.java @@ -142,6 +142,10 @@ public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 2.0D).add(Attributes.FLYING_SPEED, 1F).add(Attributes.MOVEMENT_SPEED, 0.2D).add(Attributes.FOLLOW_RANGE, 32.0D).add(Attributes.MAX_HEALTH, 18.0D); } + public static boolean checkMagneticCaveSpawnRules(EntityType entityType, ServerLevelAccessor levelAccessor, MobSpawnType mobSpawnType, BlockPos blockPos, RandomSource randomSource) { + return checkAnyLightMonsterSpawnRules(entityType, levelAccessor, mobSpawnType, blockPos, randomSource); + } + protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) { return 0.55F * dimensions.height(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/VallumraptorEntity.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/VallumraptorEntity.java index 5aaabee00..c756a5af5 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/VallumraptorEntity.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/living/VallumraptorEntity.java @@ -563,6 +563,7 @@ public boolean isColliding(BlockPos pos, BlockState blockState) { return !(blockState.getBlock() instanceof DoorBlock && blockState.getValue(DoorBlock.OPEN)) && super.isColliding(pos, blockState); } + @Override public Vec3 collide(Vec3 vec3) { return ICustomCollisions.getAllowedMovementForEntity(this, vec3); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/ACAttachmentRegistry.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/ACAttachmentRegistry.java index 5980e38c5..c19d80920 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/ACAttachmentRegistry.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/ACAttachmentRegistry.java @@ -12,6 +12,9 @@ * Registry for NeoForge Attachment Types used by Alex's Caves. * Attachments are used to store custom data on entities without requiring * SynchedEntityData (which causes ID conflicts with vanilla entities in 1.21). + * + * Note: NeoForge 1.21.1 attachments don't have built-in sync - we handle sync + * manually via UpdateMagneticDataMessage. */ public class ACAttachmentRegistry { @@ -21,6 +24,7 @@ public class ACAttachmentRegistry { /** * Attachment for magnetic entity data (delta movement and attachment direction). * This replaces the old SynchedEntityData-based approach that caused ID conflicts. + * Sync is handled manually via network packets to match 1.20's SynchedEntityData behavior. */ public static final Supplier> MAGNETIC_DATA = DEF_REG.register( "magnetic_data", diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/FrostmintExplosion.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/FrostmintExplosion.java index b2b80001c..5b5bebf20 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/FrostmintExplosion.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/FrostmintExplosion.java @@ -42,6 +42,7 @@ import java.util.Set; public class FrostmintExplosion { + private Explosion dummyExplosion; private static final ExplosionDamageCalculator EXPLOSION_DAMAGE_CALCULATOR = new ExplosionDamageCalculator(); private final Explosion.BlockInteraction blockInteraction; private final RandomSource random = RandomSource.create(); @@ -200,9 +201,18 @@ public void explode() { this.hitPlayers.put(player, vec31); } } - if(entity instanceof LivingEntity living){ - living.setTicksFrozen(living.getTicksRequiredToFreeze() + 200); - ((FrostmintFreezableAccessor)living).setFrostmintFreezing(true); + if (entity instanceof LivingEntity living) { + boolean flag = false; + for (ItemStack itemstack : living.getArmorSlots()) { + if (itemstack.is(net.minecraft.tags.ItemTags.FREEZE_IMMUNE_WEARABLES)) { + flag = true; + break; + } + } + if (!flag) { + living.setTicksFrozen(living.getTicksRequiredToFreeze() + 200); + ((FrostmintFreezableAccessor) living).setFrostmintFreezing(true); + } } } } @@ -245,9 +255,10 @@ public void finalizeExplosion(boolean particles) { addBlockDrops(objectarraylist, p_46074_, blockpos1); }); } - if (blockstate.getFluidState().isEmpty()) { - level.setBlock(blockpos, Blocks.AIR.defaultBlockState(), 3); + if (dummyExplosion == null) { + dummyExplosion = new Explosion(level, null, this.x, this.y, this.z, this.radius, false, Explosion.BlockInteraction.KEEP); } + blockstate.onBlockExploded(level, blockpos, dummyExplosion); this.level.getProfiler().pop(); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/MagnetUtil.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/MagnetUtil.java index 16dd42a40..23b4ab629 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/MagnetUtil.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/MagnetUtil.java @@ -41,8 +41,8 @@ private static Stream getNearbyRepellingMagnets(BlockPos blockpos, Ser } public static void tickMagnetism(Entity entity) { - // All magnetism logic runs on server side only - // Client will receive position updates through normal entity sync + // Server side only: calculate magnetic delta from nearby magnets (POI detection requires ServerLevel) + // MagneticEntityData is now synced to clients via AttachmentType.syncToAll() if (!entity.level().isClientSide && entity.level() instanceof ServerLevel serverLevel) { int range = 5; Stream attracts = getNearbyAttractingMagnets(entity.blockPosition(), serverLevel, range); @@ -63,83 +63,69 @@ public static void tickMagnetism(Entity entity) { Vec3 pullScale = pullNorm.scale((1 - distance) * 0.25F); setEntityMagneticDelta(entity, getEntityMagneticDelta(entity).scale(0.9).add(pullScale)); }); - - Vec3 vec3 = getEntityMagneticDelta(entity); - Direction dir = getEntityMagneticDirection(entity); - MagneticEntityAccessor magneticAccessor = (MagneticEntityAccessor) entity; - boolean attatchesToMagnets = AlexsCaves.COMMON_CONFIG.walkingOnMagnets.get() && attachesToMagnets(entity); - float progress = magneticAccessor.getAttachmentProgress(1.0F); - if (vec3 != Vec3.ZERO) { - Direction standingOnDirection = getStandingOnMagnetSurface(entity); - float overrideByWalking = 1.0F; - if (entity instanceof LivingEntity living) { - boolean isJumping = isEntityJumping(living); - if (isJumping && standingOnDirection == dir) { - magneticAccessor.postMagnetJump(); + } + // Movement handling runs on both client and server (matching 1.20 behavior) + // Client receives magneticDelta via attachment sync + Vec3 vec3 = getEntityMagneticDelta(entity); + Direction dir = getEntityMagneticDirection(entity); + MagneticEntityAccessor magneticAccessor = (MagneticEntityAccessor) entity; + boolean attatchesToMagnets = AlexsCaves.COMMON_CONFIG.walkingOnMagnets.get() && attachesToMagnets(entity); + float progress = magneticAccessor.getAttachmentProgress(1.0F); + if (vec3 != Vec3.ZERO) { + Direction standingOnDirection = getStandingOnMagnetSurface(entity); + float overrideByWalking = 1.0F; + if (entity instanceof LivingEntity living) { + boolean isJumping = isEntityJumping(living); + if (isJumping && standingOnDirection == dir) { + if (entity.level().isClientSide) { + AlexsCaves.sendMSGToServer(new PlayerJumpFromMagnetMessage(living.getId(), isJumping)); } - float detract = living.xxa * living.xxa + living.yya * living.yya + living.zza * living.zza; - overrideByWalking -= Math.min(1.0F, Math.sqrt(detract) * 0.7F); + magneticAccessor.postMagnetJump(); } - if (!isEntityOnMovingMetal(entity)) { - if (attatchesToMagnets) { - Vec3 vec31; - if (dir == Direction.DOWN && standingOnDirection == null) { - vec31 = vec3.multiply(overrideByWalking, overrideByWalking, overrideByWalking); - entity.setDeltaMovement(entity.getDeltaMovement().add(vec31)); - entity.refreshDimensions(); - } else { - magneticAccessor.stepOnMagnetBlock(getSamplePosForDirection(entity, dir, 0.5F)); - float f1 = Math.abs(dir.getStepX()); - float f2 = Math.abs(dir.getStepY()); - float f3 = Math.abs(dir.getStepZ()); - vec31 = vec3.multiply(overrideByWalking * f1, overrideByWalking * f2, overrideByWalking * f3); - if (entity.getPose() == Pose.SWIMMING) { - entity.setPose(Pose.STANDING); - } - if (entity instanceof LivingEntity living) { - vec31 = processMovementControls(0, living, dir); - } - entity.setDeltaMovement(vec31); - } - Direction closest = calculateClosestDirection(entity); - if (closest != null && closest != Direction.DOWN) { - entity.fallDistance = 0.0F; - } - if (closest != dir && magneticAccessor.canChangeDirection() && (progress == 1.0F || closest == Direction.UP)) { - entity.setDeltaMovement(entity.getDeltaMovement().add(0, 0.4F, 0)); - setEntityMagneticDirection(entity, closest); - entity.refreshDimensions(); + float detract = living.xxa * living.xxa + living.yya * living.yya + living.zza * living.zza; + overrideByWalking -= Math.min(1.0F, Math.sqrt(detract) * 0.7F); + } + if (!isEntityOnMovingMetal(entity)) { + if (attatchesToMagnets) { + Vec3 vec31; + if (dir == Direction.DOWN && standingOnDirection == null) { + vec31 = vec3.multiply(overrideByWalking, overrideByWalking, overrideByWalking); + entity.setDeltaMovement(entity.getDeltaMovement().add(vec31)); + entity.refreshDimensions(); + } else { + magneticAccessor.stepOnMagnetBlock(getSamplePosForDirection(entity, dir, 0.5F)); + float f1 = Math.abs(dir.getStepX()); + float f2 = Math.abs(dir.getStepY()); + float f3 = Math.abs(dir.getStepZ()); + vec31 = vec3.multiply(overrideByWalking * f1, overrideByWalking * f2, overrideByWalking * f3); + if (entity.getPose() == Pose.SWIMMING) { entity.setPose(Pose.STANDING); } - } else { - entity.setDeltaMovement(entity.getDeltaMovement().add(vec3)); + if (entity instanceof LivingEntity living) { + vec31 = processMovementControls(0, living, dir); + } + entity.setDeltaMovement(vec31); } - } - setEntityMagneticDelta(entity, vec3.scale(0.08F)); - } - if (!attatchesToMagnets && dir != Direction.DOWN) { - setEntityMagneticDirection(entity, Direction.DOWN); - entity.refreshDimensions(); - entity.setPose(Pose.STANDING); - } - - // Force sync entity velocity to clients for players - if (entity instanceof net.minecraft.server.level.ServerPlayer player) { - player.hurtMarked = true; - } - } else if (entity.level().isClientSide) { - // Client-side: handle jump message only - Vec3 vec3 = getEntityMagneticDelta(entity); - Direction dir = getEntityMagneticDirection(entity); - MagneticEntityAccessor magneticAccessor = (MagneticEntityAccessor) entity; - if (vec3 != Vec3.ZERO && entity instanceof LivingEntity living) { - Direction standingOnDirection = getStandingOnMagnetSurface(entity); - boolean isJumping = isEntityJumping(living); - if (isJumping && standingOnDirection == dir) { - AlexsCaves.sendMSGToServer(new PlayerJumpFromMagnetMessage(living.getId(), isJumping)); - magneticAccessor.postMagnetJump(); + Direction closest = calculateClosestDirection(entity); + if (closest != null && closest != Direction.DOWN) { + entity.fallDistance = 0.0F; + } + if (closest != dir && magneticAccessor.canChangeDirection() && (progress == 1.0F || closest == Direction.UP)) { + entity.setDeltaMovement(entity.getDeltaMovement().add(0, 0.4F, 0)); + setEntityMagneticDirection(entity, closest); + entity.refreshDimensions(); + entity.setPose(Pose.STANDING); + } + } else { + entity.setDeltaMovement(entity.getDeltaMovement().add(vec3)); } } + setEntityMagneticDelta(entity, vec3.scale(0.08F)); + } + if (!attatchesToMagnets && dir != Direction.DOWN) { + setEntityMagneticDirection(entity, Direction.DOWN); + entity.refreshDimensions(); + entity.setPose(Pose.STANDING); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/MineExplosion.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/MineExplosion.java index 772c21912..f39d412a5 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/MineExplosion.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/MineExplosion.java @@ -39,6 +39,7 @@ import java.util.Set; public class MineExplosion { + private Explosion dummyExplosion; private static final ExplosionDamageCalculator EXPLOSION_DAMAGE_CALCULATOR = new ExplosionDamageCalculator(); private final Explosion.BlockInteraction blockInteraction; private final RandomSource random = RandomSource.create(); @@ -238,9 +239,10 @@ public void finalizeExplosion(boolean particles) { addBlockDrops(objectarraylist, p_46074_, blockpos1); }); } - if (blockstate.getFluidState().isEmpty()) { - level.setBlock(blockpos, Blocks.AIR.defaultBlockState(), 3); + if (dummyExplosion == null) { + dummyExplosion = new Explosion(level, null, this.x, this.y, this.z, this.radius, false, Explosion.BlockInteraction.KEEP); } + blockstate.onBlockExploded(level, blockpos, dummyExplosion); this.level.getProfiler().pop(); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/TephraExplosion.java b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/TephraExplosion.java index d52020f27..4064b6ff5 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/TephraExplosion.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/entity/util/TephraExplosion.java @@ -43,6 +43,7 @@ import java.util.Set; public class TephraExplosion { + private Explosion dummyExplosion; private static final ExplosionDamageCalculator EXPLOSION_DAMAGE_CALCULATOR = new ExplosionDamageCalculator(); private final Explosion.BlockInteraction blockInteraction; private final RandomSource random = RandomSource.create(); @@ -246,8 +247,15 @@ public void finalizeExplosion(boolean particles) { }); } } + if (dummyExplosion == null) { + dummyExplosion = new Explosion(level, null, this.x, this.y, this.z, this.radius, false, Explosion.BlockInteraction.KEEP); + } if (blockstate.getFluidState().isEmpty() && !blockstate.is(ACBlockRegistry.FISSURE_PRIMAL_MAGMA.get())) { - level.setBlock(blockpos, setToAir ? Blocks.AIR.defaultBlockState() : ACBlockRegistry.FISSURE_PRIMAL_MAGMA.get().defaultBlockState().setValue(FissurePrimalMagmaBlock.REGEN_HEIGHT, 0), 3); + if (setToAir) { + blockstate.onBlockExploded(level, blockpos, dummyExplosion); + } else { + level.setBlock(blockpos, ACBlockRegistry.FISSURE_PRIMAL_MAGMA.get().defaultBlockState().setValue(FissurePrimalMagmaBlock.REGEN_HEIGHT, 0), 3); + } } this.level.getProfiler().pop(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/event/CommonEvents.java b/src/main/java/com/github/alexmodguy/alexscaves/server/event/CommonEvents.java index b5d1bb381..036db60fb 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/event/CommonEvents.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/event/CommonEvents.java @@ -323,11 +323,11 @@ public void onEntityJoinWorld(FinalizeSpawnEvent event) { @SubscribeEvent public void livingRemoveEffect(MobEffectEvent.Remove event) { - if (event.getEffect() instanceof DarknessIncarnateEffect darknessIncarnateEffect) { + if (event.getEffect().value() instanceof DarknessIncarnateEffect darknessIncarnateEffect) { darknessIncarnateEffect.toggleFlight(event.getEntity(), false); event.getEntity().level().playSound(null, event.getEntity().getX(), event.getEntity().getY(), event.getEntity().getZ(), ACSoundRegistry.DARKNESS_INCARNATE_EXIT.get(), SoundSource.PLAYERS, 1.0F, 1.0F); } - if (event.getEffect() instanceof SugarRushEffect) { + if (event.getEffect().value() instanceof SugarRushEffect) { event.getEntity().level().playSound(null, event.getEntity().getX(), event.getEntity().getY(), event.getEntity().getZ(), ACSoundRegistry.SUGAR_RUSH_EXIT.get(), SoundSource.PLAYERS, 1.0F, 1.0F); } } @@ -335,14 +335,14 @@ public void livingRemoveEffect(MobEffectEvent.Remove event) { @SubscribeEvent public void livingAddEffect(MobEffectEvent.Added event) { - if (event.getEffectInstance().getEffect() instanceof DarknessIncarnateEffect) { + if (event.getEffectInstance().getEffect().value() instanceof DarknessIncarnateEffect) { event.getEntity().level().playSound(null, event.getEntity().getX(), event.getEntity().getY(), event.getEntity().getZ(), ACSoundRegistry.DARKNESS_INCARNATE_ENTER.get(), SoundSource.PLAYERS, 1.0F, 1.0F); } - if (event.getEffectInstance().getEffect() instanceof SugarRushEffect) { + if (event.getEffectInstance().getEffect().value() instanceof SugarRushEffect) { event.getEntity().level().playSound(null, event.getEntity().getX(), event.getEntity().getY(), event.getEntity().getZ(), ACSoundRegistry.SUGAR_RUSH_ENTER.get(), SoundSource.PLAYERS, 1.0F, 1.0F); } // In 1.21, isAddedToWorld() is removed - use isAlive() && level() != null - if (event.getEntity() instanceof Player player && player.isAlive() && player.level() != null && event.getEffectInstance().getEffect() instanceof SugarRushEffect && AlexsCaves.COMMON_CONFIG.sugarRushSlowsTime.get()) { + if (event.getEntity() instanceof Player player && player.isAlive() && player.level() != null && event.getEffectInstance().getEffect().value() instanceof SugarRushEffect && AlexsCaves.COMMON_CONFIG.sugarRushSlowsTime.get()) { float timeBetweenTicksIncrease = 2F; SugarRushEffect.enterSlowMotion(player, player.level(), Mth.ceil(event.getEffectInstance().getDuration() * timeBetweenTicksIncrease), timeBetweenTicksIncrease); } @@ -350,11 +350,11 @@ public void livingAddEffect(MobEffectEvent.Added event) { @SubscribeEvent public void livingExpireEffect(MobEffectEvent.Expired event) { - if (event.getEffectInstance().getEffect() instanceof DarknessIncarnateEffect darknessIncarnateEffect) { + if (event.getEffectInstance().getEffect().value() instanceof DarknessIncarnateEffect darknessIncarnateEffect) { darknessIncarnateEffect.toggleFlight(event.getEntity(), false); event.getEntity().playSound(ACSoundRegistry.DARKNESS_INCARNATE_EXIT.get()); } - if (event.getEntity() instanceof Player player && event.getEffectInstance().getEffect() instanceof SugarRushEffect && AlexsCaves.COMMON_CONFIG.sugarRushSlowsTime.get()) { + if (event.getEntity() instanceof Player player && event.getEffectInstance().getEffect().value() instanceof SugarRushEffect && AlexsCaves.COMMON_CONFIG.sugarRushSlowsTime.get()) { SugarRushEffect.leaveSlowMotion(player, player.level()); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/item/ACItemRegistry.java b/src/main/java/com/github/alexmodguy/alexscaves/server/item/ACItemRegistry.java index ea7ddc5e5..7f46ee82a 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/item/ACItemRegistry.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/item/ACItemRegistry.java @@ -29,7 +29,6 @@ import net.minecraft.world.level.Level; import net.minecraft.world.item.JukeboxSong; import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.ComposterBlock; import net.minecraft.world.level.block.DispenserBlock; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.material.Fluids; @@ -408,23 +407,7 @@ protected ItemStack execute(BlockSource blockSource, ItemStack itemStack) { DispenserBlock.registerBehavior(SWEETISH_FISH_YELLOW_BUCKET.get(), new FluidContainerDispenseItemBehavior()); DispenserBlock.registerBehavior(SWEETISH_FISH_PINK_BUCKET.get(), new FluidContainerDispenseItemBehavior()); LecternBooks.BOOKS.put(CAVE_BOOK.getId(), new LecternBooks.BookData(0X81301C, 0XFDF8EC)); - ComposterBlock.COMPOSTABLES.put(PINE_NUTS.get(), 0.5F); - ComposterBlock.COMPOSTABLES.put(PEWEN_SAP.get(), 0.2F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.PEWEN_SAPLING.get().asItem(), 0.3F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.PEWEN_PINES.get().asItem(), 0.3F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.PEWEN_BRANCH.get().asItem(), 0.3F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.ANCIENT_SAPLING.get().asItem(), 0.3F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.ANCIENT_LEAVES.get().asItem(), 0.3F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.FIDDLEHEAD.get().asItem(), 0.4F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.CURLY_FERN.get().asItem(), 0.3F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.FLYTRAP.get().asItem(), 0.65F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.CYCAD.get().asItem(), 0.65F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.TREE_STAR.get().asItem(), 0.65F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.ARCHAIC_VINE.get().asItem(), 0.5F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.FERN_THATCH.get().asItem(), 0.85F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.UNDERWEED.get().asItem(), 0.3F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.THORNWOOD_BRANCH.get().asItem(), 0.3F); - ComposterBlock.COMPOSTABLES.put(ACBlockRegistry.THORNWOOD_SAPLING.get().asItem(), 0.3F); + // Compostables are now registered via data map: data/neoforge/data_maps/item/compostables.json } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/item/BiomeTreatItem.java b/src/main/java/com/github/alexmodguy/alexscaves/server/item/BiomeTreatItem.java index 92f9186e2..22366b288 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/item/BiomeTreatItem.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/item/BiomeTreatItem.java @@ -27,7 +27,7 @@ public class BiomeTreatItem extends CaveInfoItem { public BiomeTreatItem() { - super(new Item.Properties().stacksTo(1), false); + super(new Item.Properties().stacksTo(1).food(ACFoods.BIOME_TREAT), false); } @Override @@ -67,7 +67,9 @@ public static int getBiomeTreatColorOf(Level level, ItemStack stack) { @Override public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity livingEntity) { if(getCaveBiome(stack) == null && (livingEntity instanceof Player player && (player.getFoodData().getFoodLevel() == 0 || player.isCreative()))){ - return create(this, level.getBiome(livingEntity.blockPosition()).unwrapKey().get()); + ItemStack map = create(this, level.getBiome(livingEntity.blockPosition()).unwrapKey().get()); + map.set(DataComponents.FOOD, ACFoods.BIOME_TREAT_DONE); + return map; } return super.finishUsingItem(stack, level, livingEntity); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/item/BurrowingArrowItem.java b/src/main/java/com/github/alexmodguy/alexscaves/server/item/BurrowingArrowItem.java index 55426a497..cfcaa4873 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/item/BurrowingArrowItem.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/item/BurrowingArrowItem.java @@ -7,12 +7,15 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import javax.annotation.Nullable; + public class BurrowingArrowItem extends ArrowItem { public BurrowingArrowItem() { super(new Properties()); } - public AbstractArrow createArrow(Level level, ItemStack itemStack, LivingEntity livingEntity) { - return new BurrowingArrowEntity(level, livingEntity); + @Override + public AbstractArrow createArrow(Level level, ItemStack ammo, LivingEntity shooter, @Nullable ItemStack weapon) { + return new BurrowingArrowEntity(level, shooter); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/item/GingerbreadArmorItem.java b/src/main/java/com/github/alexmodguy/alexscaves/server/item/GingerbreadArmorItem.java index adf413009..660faef02 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/item/GingerbreadArmorItem.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/item/GingerbreadArmorItem.java @@ -26,7 +26,7 @@ public class GingerbreadArmorItem extends ArmorItem { private final ACArmorMaterial acMaterial; public GingerbreadArmorItem(ACArmorMaterial armorMaterial, Type slot) { - super(armorMaterial.getHolder(), slot, new Properties().durability(armorMaterial.getDurabilityForType(slot)).attributes(createGingerbreadAttributes(armorMaterial, slot, MIN_SPEED_BOOST))); + super(armorMaterial.getHolder(), slot, new Properties().durability(armorMaterial.getDurabilityForType(slot))); this.acMaterial = armorMaterial; this.defaultItemAttributes = createGingerbreadAttributes(armorMaterial, slot, MIN_SPEED_BOOST); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/item/InkBombItem.java b/src/main/java/com/github/alexmodguy/alexscaves/server/item/InkBombItem.java index 765e1fb8d..fd6bc1be6 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/item/InkBombItem.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/item/InkBombItem.java @@ -20,9 +20,10 @@ public InkBombItem(Item.Properties properties, boolean glowing) { this.glowing = glowing; } + @Override public InteractionResultHolder use(Level level, Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); - level.playSound((Player) null, player.getX(), player.getY(), player.getZ(), SoundEvents.SNOWBALL_THROW, SoundSource.PLAYERS, 0.5F, (level.getRandom().nextFloat() * 0.7F + 0.25F) * 0.5F); + level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.SNOWBALL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F)); if (!level.isClientSide) { InkBombEntity bomb = new InkBombEntity(level, player); bomb.setItem(itemstack); @@ -31,9 +32,7 @@ public InteractionResultHolder use(Level level, Player player, Intera level.addFreshEntity(bomb); } player.awardStat(Stats.ITEM_USED.get(this)); - if (!player.getAbilities().instabuild) { - itemstack.shrink(1); - } + itemstack.consume(1, player); return InteractionResultHolder.sidedSuccess(itemstack, level.isClientSide()); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/item/JellyBeanItem.java b/src/main/java/com/github/alexmodguy/alexscaves/server/item/JellyBeanItem.java index 54eb394d5..8b70631b3 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/item/JellyBeanItem.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/item/JellyBeanItem.java @@ -108,16 +108,12 @@ public void appendHoverText(ItemStack itemStack, Item.TooltipContext context, Li } public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity living) { - Player player = living instanceof Player ? (Player)living : null; - if (player instanceof ServerPlayer) { - CriteriaTriggers.CONSUME_ITEM.trigger((ServerPlayer)player, stack); - } - if (!level.isClientSide) { PotionContents potionContents = stack.get(DataComponents.POTION_CONTENTS); if (potionContents != null) { for (MobEffectInstance mobeffectinstance : potionContents.getAllEffects()) { MobEffect mobeffect = mobeffectinstance.getEffect().value(); + Player player = living instanceof Player ? (Player)living : null; if (mobeffect.isInstantenous()) { mobeffect.applyInstantenousEffect(player, player, living, mobeffectinstance.getAmplifier(), 1.0D); } else { @@ -126,14 +122,6 @@ public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity livi } } } - - if (player != null) { - player.awardStat(Stats.ITEM_USED.get(this)); - if (!player.getAbilities().instabuild) { - stack.shrink(1); - } - } - living.gameEvent(GameEvent.EAT); - return stack; + return living.eat(level, stack); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/item/PrimitiveClubItem.java b/src/main/java/com/github/alexmodguy/alexscaves/server/item/PrimitiveClubItem.java index b0566ccf8..76fa7046b 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/item/PrimitiveClubItem.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/item/PrimitiveClubItem.java @@ -29,7 +29,7 @@ public class PrimitiveClubItem extends Item { public PrimitiveClubItem(Item.Properties properties) { - super(properties.attributes(createDefaultAttributes())); + super(properties); } private static ItemAttributeModifiers createDefaultAttributes() { @@ -62,7 +62,13 @@ public boolean hurtEnemy(ItemStack stack, LivingEntity hurtEntity, LivingEntity if (!hurtEntity.level().isClientSide) { SoundEvent soundEvent = ACSoundRegistry.PRIMITIVE_CLUB_MISS.get(); if (hurtEntity.getRandom().nextFloat() < 0.8F) { - MobEffectInstance instance = new MobEffectInstance(ACEffectRegistry.STUNNED, 150 + hurtEntity.getRandom().nextInt(150), 0, false, false); + int stunDuration = 150 + hurtEntity.getRandom().nextInt(150); + // If already stunned, add to remaining duration to ensure effect always extends + MobEffectInstance existingStun = hurtEntity.getEffect(ACEffectRegistry.STUNNED); + if (existingStun != null) { + stunDuration += existingStun.getDuration(); + } + MobEffectInstance instance = new MobEffectInstance(ACEffectRegistry.STUNNED, stunDuration, 0, false, false); if (hurtEntity.addEffect(instance)) { AlexsCaves.sendMSGToAll(new UpdateEffectVisualityEntityMessage(hurtEntity.getId(), player.getId(), 3, instance.getDuration())); soundEvent = ACSoundRegistry.PRIMITIVE_CLUB_HIT.get(); @@ -72,7 +78,12 @@ public boolean hurtEnemy(ItemStack stack, LivingEntity hurtEntity, LivingEntity AABB aabb = AABB.ofSize(hurtEntity.position(), f, f, f); for (Entity entity : hurtEntity.level().getEntities(player, aabb, Entity::canBeHitByProjectile)) { if (!entity.is(hurtEntity) && !entity.isAlliedTo(player) && entity.distanceTo(hurtEntity) <= f && entity instanceof LivingEntity inflict) { - MobEffectInstance instance2 = new MobEffectInstance(ACEffectRegistry.STUNNED, 80 + hurtEntity.getRandom().nextInt(80), 0, false, false); + int aoeStunDuration = 80 + hurtEntity.getRandom().nextInt(80); + MobEffectInstance existingAoeStun = inflict.getEffect(ACEffectRegistry.STUNNED); + if (existingAoeStun != null) { + aoeStunDuration += existingAoeStun.getDuration(); + } + MobEffectInstance instance2 = new MobEffectInstance(ACEffectRegistry.STUNNED, aoeStunDuration, 0, false, false); inflict.hurt(inflict.level().damageSources().mobAttack(player), 1.0F); if (inflict.addEffect(instance2)) { AlexsCaves.sendMSGToAll(new UpdateEffectVisualityEntityMessage(inflict.getId(), player.getId(), 3, instance2.getDuration())); @@ -103,11 +114,11 @@ public boolean isValidRepairItem(ItemStack item, ItemStack repairItem) { @Override public ItemAttributeModifiers getDefaultAttributeModifiers(ItemStack stack) { - int swift = ACEnchantmentHelper.getEnchantmentLevel((Level) null, ACEnchantmentRegistry.SWIFTWOOD, stack); + int swift = ACEnchantmentHelper.getEnchantmentLevelFromStack(ACEnchantmentRegistry.SWIFTWOOD, stack); if (swift > 0) { return createAttributesForSwiftwoodLevel(Mth.clamp(swift, 0, 3)); } - return super.getDefaultAttributeModifiers(stack); + return createDefaultAttributes(); } @Override diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/item/SeaStaffItem.java b/src/main/java/com/github/alexmodguy/alexscaves/server/item/SeaStaffItem.java index 71f64e021..25900a665 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/item/SeaStaffItem.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/item/SeaStaffItem.java @@ -51,7 +51,7 @@ public InteractionResultHolder use(Level level, Player player, Intera bolt.setPos(player.getX() - (double) (player.getBbWidth()) * 1.1F * (double) Mth.sin(rot * ((float) Math.PI / 180F)), player.getEyeY() - (double) 0.4F, player.getZ() + (double) (player.getBbWidth()) * 1.1F * (double) Mth.cos(rot * ((float) Math.PI / 180F))); bolt.shootFromRotation(player, player.getXRot(), player.getYRot() + shootRot, -20.0F, i > 0 ? 1F : 2F, 12F); if (ACEnchantmentHelper.getEnchantmentLevel(level, ACEnchantmentRegistry.ENVELOPING_BUBBLE, itemstack) > 0) { - bolt.setBubbling(player.getRandom().nextBoolean()); + bolt.setBubbling(true); } if (ACEnchantmentHelper.getEnchantmentLevel(level, ACEnchantmentRegistry.BOUNCING_BOLT, itemstack) > 0) { bolt.ricochet = true; diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/item/SeekingArrowItem.java b/src/main/java/com/github/alexmodguy/alexscaves/server/item/SeekingArrowItem.java index 69ca6e8ef..3d36f108e 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/item/SeekingArrowItem.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/item/SeekingArrowItem.java @@ -8,12 +8,15 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import javax.annotation.Nullable; + public class SeekingArrowItem extends ArrowItem { public SeekingArrowItem() { super(new Item.Properties()); } - public AbstractArrow createArrow(Level level, ItemStack itemStack, LivingEntity livingEntity) { - return new SeekingArrowEntity(level, livingEntity); + @Override + public AbstractArrow createArrow(Level level, ItemStack ammo, LivingEntity shooter, @Nullable ItemStack weapon) { + return new SeekingArrowEntity(level, shooter); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/level/storage/ACWorldData.java b/src/main/java/com/github/alexmodguy/alexscaves/server/level/storage/ACWorldData.java index 0d992feb4..161ea9537 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/level/storage/ACWorldData.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/level/storage/ACWorldData.java @@ -21,7 +21,6 @@ import javax.annotation.Nullable; import java.util.*; -import java.util.stream.Collectors; public class ACWorldData extends SavedData { @@ -62,7 +61,7 @@ public static ACWorldData load(CompoundTag nbt, HolderLookup.Provider provider) } data.primordialBossDefeatedOnce = nbt.getBoolean("PrimordialBossDefeatedOnce"); data.firstPrimordialBossDefeatTimestamp = nbt.getLong("FirstPrimordialBossDefeatTimestamp"); - data.trackedLuxtructosaurusIds = Arrays.stream(nbt.getIntArray("TrackedLuxtructosaurusIds")).boxed().collect(Collectors.toSet()); + // Note: trackedLuxtructosaurusIds is not persisted since entity IDs are runtime values return data; } @@ -80,7 +79,7 @@ public CompoundTag save(CompoundTag compound, HolderLookup.Provider provider) { } compound.putBoolean("PrimordialBossDefeatedOnce", primordialBossDefeatedOnce); compound.putLong("FirstPrimordialBossDefeatTimestamp", firstPrimordialBossDefeatTimestamp); - compound.putIntArray("TrackedLuxtructosaurusIds", trackedLuxtructosaurusIds.stream().mapToInt(Integer::intValue).toArray()); + // Note: trackedLuxtructosaurusIds is not persisted since entity IDs are runtime values return compound; } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/message/BeholderSyncMessage.java b/src/main/java/com/github/alexmodguy/alexscaves/server/message/BeholderSyncMessage.java index 9a578023b..ceba9c11c 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/message/BeholderSyncMessage.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/message/BeholderSyncMessage.java @@ -1,16 +1,13 @@ package com.github.alexmodguy.alexscaves.server.message; import com.github.alexmodguy.alexscaves.AlexsCaves; -import com.github.alexmodguy.alexscaves.server.entity.item.BeholderEyeEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; import net.neoforged.neoforge.network.handling.IPayloadContext; -import net.neoforged.neoforge.server.ServerLifecycleHooks; + +import java.util.UUID; public class BeholderSyncMessage implements CustomPacketPayload { @@ -20,49 +17,65 @@ public class BeholderSyncMessage implements CustomPacketPayload { public static final StreamCodec CODEC = StreamCodec.ofMember(BeholderSyncMessage::write, BeholderSyncMessage::read); - @Override - public Type type() { return TYPE; } - - public int beholderId; - public boolean active; + private final int beholderId; + private final boolean active; + private final double x, y, z; + private final float yRot, xRot; + private final UUID usingPlayerUUID; - public BeholderSyncMessage(int beholderId, boolean active) { + public BeholderSyncMessage(int beholderId, boolean active, double x, double y, double z, float yRot, float xRot, UUID usingPlayerUUID) { this.beholderId = beholderId; this.active = active; + this.x = x; + this.y = y; + this.z = z; + this.yRot = yRot; + this.xRot = xRot; + this.usingPlayerUUID = usingPlayerUUID; } - - public BeholderSyncMessage() { + public BeholderSyncMessage(int beholderId, boolean active) { + this(beholderId, active, 0, 0, 0, 0, 0, null); } + @Override + public Type type() { return TYPE; } + public static BeholderSyncMessage read(FriendlyByteBuf buf) { - return new BeholderSyncMessage(buf.readInt(), buf.readBoolean()); + int beholderId = buf.readInt(); + boolean active = buf.readBoolean(); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + float yRot = buf.readFloat(); + float xRot = buf.readFloat(); + UUID uuid = buf.readBoolean() ? buf.readUUID() : null; + return new BeholderSyncMessage(beholderId, active, x, y, z, yRot, xRot, uuid); } public static void write(BeholderSyncMessage message, FriendlyByteBuf buf) { buf.writeInt(message.beholderId); buf.writeBoolean(message.active); + buf.writeDouble(message.x); + buf.writeDouble(message.y); + buf.writeDouble(message.z); + buf.writeFloat(message.yRot); + buf.writeFloat(message.xRot); + buf.writeBoolean(message.usingPlayerUUID != null); + if (message.usingPlayerUUID != null) { + buf.writeUUID(message.usingPlayerUUID); + } } public static void handle(BeholderSyncMessage message, IPayloadContext context) { // This packet is sent from server to client if (context.flow().isClientbound()) { context.enqueueWork(() -> { - Player playerSided = AlexsCaves.PROXY.getClientSidePlayer(); - if (playerSided != null) { - Entity watcher = playerSided.level().getEntity(message.beholderId); - if (watcher instanceof BeholderEyeEntity beholderEye) { - Entity beholderEyePlayer = beholderEye.getUsingPlayer(); - beholderEye.hasTakenFullControlOfCamera = true; - if (beholderEyePlayer != null && beholderEyePlayer instanceof Player && beholderEyePlayer.equals(playerSided)) { - if (message.active) { - AlexsCaves.PROXY.setRenderViewEntity(playerSided, beholderEye); - } else { - AlexsCaves.PROXY.resetRenderViewEntity(playerSided); - } - } - } - } + AlexsCaves.PROXY.handleBeholderSync( + message.beholderId, message.active, + message.x, message.y, message.z, + message.yRot, message.xRot, message.usingPlayerUUID + ); }); } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/message/UpdateEffectVisualityEntityMessage.java b/src/main/java/com/github/alexmodguy/alexscaves/server/message/UpdateEffectVisualityEntityMessage.java index 5adaf0107..822cbe862 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/message/UpdateEffectVisualityEntityMessage.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/message/UpdateEffectVisualityEntityMessage.java @@ -16,6 +16,11 @@ import net.minecraft.world.entity.player.Player; import net.neoforged.neoforge.network.handling.IPayloadContext; +/** + * Message to sync effect visuals from server to client. + * For BUBBLED effect, uses a client-side tracking system instead of MobEffect + * to properly handle effect expiration timing. + */ public class UpdateEffectVisualityEntityMessage implements CustomPacketPayload { public static final CustomPacketPayload.Type TYPE = @@ -76,9 +81,18 @@ public static void handle(UpdateEffectVisualityEntityMessage message, IPayloadCo mobEffect = ACEffectRegistry.IRRADIATED; break; case 1: - mobEffect = ACEffectRegistry.BUBBLED; - entity.playSound(ACSoundRegistry.SEA_STAFF_BUBBLE.get()); - break; + // For BUBBLED effect, use the client-side visual tracking system + // This avoids the issue where client-side MobEffect doesn't sync with server expiration + boolean isNewEffect = !AlexsCaves.PROXY.hasBubbledEffectVisual(message.entityID); + if (message.remove) { + AlexsCaves.PROXY.setBubbledEffectTicks(message.entityID, 0); + } else { + AlexsCaves.PROXY.setBubbledEffectTicks(message.entityID, message.duration); + if (isNewEffect) { + entity.playSound(ACSoundRegistry.SEA_STAFF_BUBBLE.get()); + } + } + return; // Don't use the normal MobEffect system for BUBBLED case 2: mobEffect = ACEffectRegistry.MAGNETIZING; break; diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/message/UpdateMagneticDataMessage.java b/src/main/java/com/github/alexmodguy/alexscaves/server/message/UpdateMagneticDataMessage.java new file mode 100644 index 000000000..c3d2e6ee7 --- /dev/null +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/message/UpdateMagneticDataMessage.java @@ -0,0 +1,82 @@ +package com.github.alexmodguy.alexscaves.server.message; + +import com.github.alexmodguy.alexscaves.AlexsCaves; +import com.github.alexmodguy.alexscaves.server.entity.util.ACAttachmentRegistry; +import com.github.alexmodguy.alexscaves.server.entity.util.MagneticEntityData; +import net.minecraft.core.Direction; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +/** + * Message to sync magnetic entity data from server to client. + * This replaces the automatic SynchedEntityData sync from 1.20. + */ +public class UpdateMagneticDataMessage implements CustomPacketPayload { + + public static final CustomPacketPayload.Type TYPE = + new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(AlexsCaves.MODID, "update_magnetic_data")); + + public static final StreamCodec CODEC = + StreamCodec.ofMember(UpdateMagneticDataMessage::write, UpdateMagneticDataMessage::read); + + @Override + public Type type() { return TYPE; } + + private final int entityId; + private final float deltaX; + private final float deltaY; + private final float deltaZ; + private final Direction attachmentDirection; + + public UpdateMagneticDataMessage(int entityId, float deltaX, float deltaY, float deltaZ, Direction attachmentDirection) { + this.entityId = entityId; + this.deltaX = deltaX; + this.deltaY = deltaY; + this.deltaZ = deltaZ; + this.attachmentDirection = attachmentDirection; + } + + public UpdateMagneticDataMessage(Entity entity, MagneticEntityData data) { + this(entity.getId(), data.getDeltaX(), data.getDeltaY(), data.getDeltaZ(), data.getAttachmentDirection()); + } + + public static UpdateMagneticDataMessage read(FriendlyByteBuf buf) { + int entityId = buf.readInt(); + float deltaX = buf.readFloat(); + float deltaY = buf.readFloat(); + float deltaZ = buf.readFloat(); + Direction dir = buf.readEnum(Direction.class); + return new UpdateMagneticDataMessage(entityId, deltaX, deltaY, deltaZ, dir); + } + + public static void write(UpdateMagneticDataMessage message, FriendlyByteBuf buf) { + buf.writeInt(message.entityId); + buf.writeFloat(message.deltaX); + buf.writeFloat(message.deltaY); + buf.writeFloat(message.deltaZ); + buf.writeEnum(message.attachmentDirection); + } + + public static void handle(UpdateMagneticDataMessage message, IPayloadContext context) { + // This packet is sent from server to client + if (!context.flow().isClientbound()) { + return; + } + Player player = AlexsCaves.PROXY.getClientSidePlayer(); + if (player != null) { + Entity entity = player.level().getEntity(message.entityId); + if (entity != null) { + MagneticEntityData data = entity.getData(ACAttachmentRegistry.MAGNETIC_DATA); + data.setDeltaX(message.deltaX); + data.setDeltaY(message.deltaY); + data.setDeltaZ(message.deltaZ); + data.setAttachmentDirection(message.attachmentDirection); + } + } + } +} diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/misc/ACTagRegistry.java b/src/main/java/com/github/alexmodguy/alexscaves/server/misc/ACTagRegistry.java index 85e190546..00f18ab90 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/misc/ACTagRegistry.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/misc/ACTagRegistry.java @@ -91,6 +91,7 @@ public class ACTagRegistry { public static final TagKey> CANDY_MOBS = registerEntityTag("candy_mobs"); public static final TagKey ON_UNDERGROUND_CABIN_MAPS = registerStructureTag("on_underground_cabin_maps"); public static final TagKey GINGERBREAD_MEN_WANDER_THROUGH = registerStructureTag("gingerbread_men_wander_through"); + public static final TagKey ORE_PROTECTED = registerStructureTag("ore_protected"); public static final TagKey DEEP_ONE_IGNORES = registerDamageTypeTag("deep_one_ignores"); public static final TagKey DOES_NOT_FLOW_INTO_WATERLOGGABLE_BLOCKS = registerFluidTag("does_not_flow_into_waterloggable_blocks"); diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/potion/BubbledEffect.java b/src/main/java/com/github/alexmodguy/alexscaves/server/potion/BubbledEffect.java index 1d386c87e..65b79dd52 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/potion/BubbledEffect.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/potion/BubbledEffect.java @@ -1,9 +1,12 @@ package com.github.alexmodguy.alexscaves.server.potion; +import com.github.alexmodguy.alexscaves.AlexsCaves; +import com.github.alexmodguy.alexscaves.server.message.UpdateEffectVisualityEntityMessage; import com.github.alexmodguy.alexscaves.server.misc.ACTagRegistry; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; +import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffectUtil; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; @@ -19,7 +22,14 @@ protected BubbledEffect() { } @Override - public boolean applyEffectTick(LivingEntity entity, int tick) { + public boolean applyEffectTick(LivingEntity entity, int amplifier) { + // Periodically sync effect to clients to ensure visual stays in sync + if (!entity.level().isClientSide && entity.tickCount % 40 == 0) { + MobEffectInstance instance = entity.getEffect(ACEffectRegistry.BUBBLED); + if (instance != null) { + AlexsCaves.sendMSGToAll(new UpdateEffectVisualityEntityMessage(entity.getId(), entity.getId(), 1, instance.getDuration())); + } + } // In 1.21, MobType was removed, so we check canBreatheUnderwater instead if (entity.canBreatheUnderwater()) { if (!entity.getType().is(ACTagRegistry.RESISTS_BUBBLED)) { @@ -47,10 +57,22 @@ public boolean applyEffectTick(LivingEntity entity, int tick) { return true; } - public boolean isDurationEffectTick(int i, int j) { + @Override + public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) { return true; } + @Override + public void onEffectStarted(LivingEntity entity, int amplifier) { + // Send initial sync to clients when effect starts + if (!entity.level().isClientSide) { + MobEffectInstance instance = entity.getEffect(ACEffectRegistry.BUBBLED); + if (instance != null) { + AlexsCaves.sendMSGToAll(new UpdateEffectVisualityEntityMessage(entity.getId(), entity.getId(), 1, instance.getDuration())); + } + } + } + public List getCurativeItems() { return List.of(); } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/potion/DeepsightEffect.java b/src/main/java/com/github/alexmodguy/alexscaves/server/potion/DeepsightEffect.java index 06de18df8..d35b448ee 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/potion/DeepsightEffect.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/potion/DeepsightEffect.java @@ -7,57 +7,70 @@ import net.minecraft.world.entity.ai.attributes.AttributeMap; import net.minecraft.world.entity.player.Player; +import java.util.Map; +import java.util.WeakHashMap; + public class DeepsightEffect extends MobEffect { - private int lastDuration = -1; - private int firstDuration = -1; + private final Map entityStartDurations = new WeakHashMap<>(); protected DeepsightEffect() { super(MobEffectCategory.BENEFICIAL, 0X002972); } public int getActiveTime() { - return firstDuration - lastDuration; + return 0; } @Override public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) { - lastDuration = duration; - if (duration <= 0) { - lastDuration = -1; - firstDuration = -1; + return true; + } + + @Override + public boolean applyEffectTick(LivingEntity entity, int amplifier) { + if (!entity.level().isClientSide) { + return true; } - if (firstDuration == -1) { - firstDuration = duration; + MobEffectInstance instance = entity.getEffect(ACEffectRegistry.DEEPSIGHT); + if (instance != null) { + int duration = instance.getDuration(); + if (!entityStartDurations.containsKey(entity) || duration > entityStartDurations.get(entity)) { + entityStartDurations.put(entity, duration); + } } - return duration > 0; + return true; } @Override public void removeAttributeModifiers(AttributeMap map) { - lastDuration = -1; - firstDuration = -1; super.removeAttributeModifiers(map); } @Override public void onEffectStarted(LivingEntity entity, int amplifier) { - lastDuration = -1; - firstDuration = -1; + MobEffectInstance instance = entity.getEffect(ACEffectRegistry.DEEPSIGHT); + if (instance != null) { + entityStartDurations.put(entity, instance.getDuration()); + } } - public static float getIntensity(Player player, float partialTicks) { MobEffectInstance instance = player.getEffect(ACEffectRegistry.DEEPSIGHT); if (instance == null) { return 0.0F; - } else if(instance.isInfiniteDuration()) { + } else if (instance.isInfiniteDuration()) { return 1.0F; } else { DeepsightEffect deepsightEffect = (DeepsightEffect) instance.getEffect().value(); - float j = deepsightEffect.getActiveTime() + partialTicks; int duration = instance.getDuration(); - return Math.min(20, (Math.min(j, duration + partialTicks))) * 0.05F; + int maxDuration = deepsightEffect.entityStartDurations.getOrDefault(player, duration); + if (duration > maxDuration) { + maxDuration = duration; + deepsightEffect.entityStartDurations.put(player, maxDuration); + } + float activeTime = maxDuration - duration + partialTicks; + return Math.min(20, (Math.min(activeTime, duration + partialTicks))) * 0.05F; } } } diff --git a/src/main/java/com/github/alexmodguy/alexscaves/server/recipe/RecipeCaveMap.java b/src/main/java/com/github/alexmodguy/alexscaves/server/recipe/RecipeCaveMap.java index 174b77d90..4a1dedc79 100644 --- a/src/main/java/com/github/alexmodguy/alexscaves/server/recipe/RecipeCaveMap.java +++ b/src/main/java/com/github/alexmodguy/alexscaves/server/recipe/RecipeCaveMap.java @@ -80,6 +80,11 @@ public boolean canCraftInDimensions(int width, int height) { return width >= 3 && height >= 3; } + @Override + public ItemStack getResultItem(HolderLookup.Provider registries) { + return new ItemStack(ACItemRegistry.CAVE_MAP.get()); + } + @Override public NonNullList getDisplayIngredients() { return DISPLAY_INGREDIENTS; diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 0a1b3e783..c809b3585 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -2,6 +2,8 @@ public net.minecraft.world.entity.LivingEntity f_20899_ # jumping public net.minecraft.server.level.ChunkMap m_214914_()Lnet/minecraft/world/level/levelgen/RandomState; # randomState public-f net.minecraft.world.level.block.entity.BlockEntityType validBlocks public net.minecraft.world.entity.Entity m_20272_(Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3; # getAllowedMovement +# Make Entity.collide() public so GumWorm can override it +public net.minecraft.world.entity.Entity collide(Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/phys/Vec3; # collide public net.minecraft.world.level.chunk.LevelChunkSection f_187995_ # biomes public net.minecraft.client.Camera m_90568_(DDD)V # move public net.minecraft.client.Camera m_90572_(FF)V # setRotation @@ -33,11 +35,11 @@ public net.minecraft.world.item.crafting.SimpleCookingSerializer$CookieBaker public net.minecraft.client.sounds.SoundManager f_120349_ # soundEngine public net.minecraft.client.sounds.SoundEngine f_120228_ # tickingSounds public net.minecraft.client.sounds.SoundEngine f_120232_ # queuedTickableSounds -public net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator m_224256_(Lnet/minecraft/world/level/chunk/ChunkAccess;Lnet/minecraft/world/level/StructureManager;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/levelgen/RandomState;)Lnet/minecraft/world/level/levelgen/NoiseChunk; # createNoiseChunk -public net.minecraft.world.level.levelgen.SurfaceRules$Context (Lnet/minecraft/world/level/levelgen/SurfaceSystem;Lnet/minecraft/world/level/levelgen/RandomState;Lnet/minecraft/world/level/chunk/ChunkAccess;Lnet/minecraft/world/level/levelgen/NoiseChunk;Ljava/util/function/Function;Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/WorldGenerationContext;)V # Context +public net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator createNoiseChunk(Lnet/minecraft/world/level/chunk/ChunkAccess;Lnet/minecraft/world/level/StructureManager;Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/levelgen/RandomState;)Lnet/minecraft/world/level/levelgen/NoiseChunk; +public net.minecraft.world.level.levelgen.SurfaceRules$Context (Lnet/minecraft/world/level/levelgen/SurfaceSystem;Lnet/minecraft/world/level/levelgen/RandomState;Lnet/minecraft/world/level/chunk/ChunkAccess;Lnet/minecraft/world/level/levelgen/NoiseChunk;Ljava/util/function/Function;Lnet/minecraft/core/Registry;Lnet/minecraft/world/level/levelgen/WorldGenerationContext;)V public net.minecraft.world.level.levelgen.SurfaceRules$SurfaceRule -public net.minecraft.world.level.levelgen.SurfaceRules$Context m_189569_(II)V # updateXZ -public net.minecraft.world.level.levelgen.SurfaceRules$Context m_189576_(IIIIII)V # updateY +public net.minecraft.world.level.levelgen.SurfaceRules$Context updateXZ(II)V +public net.minecraft.world.level.levelgen.SurfaceRules$Context updateY(IIIIII)V public net.minecraft.client.multiplayer.ClientLevel f_104558_ # tintCaches public net.minecraft.world.entity.projectile.FireworkRocketEntity f_37023_ # lifetime public net.minecraft.world.entity.projectile.FireworkRocketEntity f_37019_ # DATA_ID_FIREWORKS_ITEM diff --git a/src/main/resources/alexscaves.mixins.json b/src/main/resources/alexscaves.mixins.json index fcb21972f..5c1f083fc 100644 --- a/src/main/resources/alexscaves.mixins.json +++ b/src/main/resources/alexscaves.mixins.json @@ -10,12 +10,14 @@ "BiomeSourceMixin", "ChunkStatusMixin", "CoralFeatureMixin", + "CorrodentCollisionMixin", "EnchantRandomlyFunctionMixin", "EntityMixin", "FallingBlockEntityMixin", "FlowingFluidMixin", "FoodDataMixin", "FrogMixin", + "GeodeFeatureMixin", "IllagerMixin", "ItemEntityMixin", "JigsawStructureMixin", @@ -28,6 +30,7 @@ "MultiNoiseBiomeSourceMixin", "NaturalSpawnerMixin", "OceanMonumentStructureMixin", + "OreFeatureMixin", "PlayerMixin", "PotionUtilsMixin", "SeagrassFeatureMixin", diff --git a/src/main/resources/assets/alexscaves/lang/en_us.json b/src/main/resources/assets/alexscaves/lang/en_us.json index 3cc49d6d3..6a9aaf083 100644 --- a/src/main/resources/assets/alexscaves/lang/en_us.json +++ b/src/main/resources/assets/alexscaves/lang/en_us.json @@ -446,6 +446,7 @@ "item.alexscaves.disc_fragment_fusion.desc": "Music Disc - Fusion", "item.alexscaves.music_disc_fusion": "Music Disc", "item.alexscaves.music_disc_fusion.desc": "Ninni - Fusion", + "jukebox_song.alexscaves.fusion": "Ninni - Fusion", "item.alexscaves.lanternfish_bucket": "Bucket of Lanternfish", "item.alexscaves.lanternfish": "Lanternfish", "item.alexscaves.cooked_lanternfish": "Cooked Lanternfish", @@ -568,6 +569,7 @@ "item.alexscaves.disc_fragment_tasty.desc": "Music Disc - Tasty", "item.alexscaves.music_disc_tasty": "Music Disc", "item.alexscaves.music_disc_tasty.desc": "Ninni - Tasty", + "jukebox_song.alexscaves.tasty": "Ninni - Tasty", "item.alexscaves.alex_meal": "Alex Meal", "item.alexscaves.alex_meal.desc": "You really live like this?", "item.alexscaves.biome_treat": "Biome Treat", diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.fsh b/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.fsh index a20e381d2..583ca624f 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.fsh +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.fsh @@ -14,6 +14,9 @@ void main() { float animation = GameTime * 2000.0; float animation1 = sin(animation) + 1; vec4 defaultColor = texture(Sampler0, texCoord0) * vertexColor; + if (defaultColor.a < 0.1) { + discard; + } vec4 color = vec4(0, animation1 * 0.15 + 0.85, animation1 * 0.15 + 0.85, defaultColor.a); fragColor = color * ColorModulator; } \ No newline at end of file diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.json b/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.json index 40b563225..368e279c0 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.json +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.json @@ -6,7 +6,7 @@ }, "vertex": "alexscaves:rendertype_blue_irradiated", "fragment": "alexscaves:rendertype_blue_irradiated", - "attributes": ["Position", "UV0", "Color"], + "attributes": ["Position", "Color", "UV0", "UV1", "UV2", "Normal"], "samplers": [{ "name": "Sampler0" }], "uniforms": [ { diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.vsh b/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.vsh index a23214475..c120b1716 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.vsh +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_blue_irradiated.vsh @@ -1,8 +1,11 @@ #version 150 in vec3 Position; -in vec2 UV0; in vec4 Color; +in vec2 UV0; +in ivec2 UV1; +in ivec2 UV2; +in vec3 Normal; uniform mat4 ModelViewMat; uniform mat4 ProjMat; @@ -14,4 +17,5 @@ void main() { gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); vertexColor = Color; texCoord0 = UV0; + // UV1, UV2, Normal are received but not used - we just need the glowing color effect } diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_hologram.json b/src/main/resources/assets/alexscaves/shaders/core/rendertype_hologram.json index bbf416386..e0866de70 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_hologram.json +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_hologram.json @@ -32,9 +32,6 @@ "type": "float", "count": 4, "values": [1.0, 1.0, 1.0, 1.0] - }, - { "name": "FogStart", "type": "float", "count": 1, "values": [0.0] }, - { "name": "FogEnd", "type": "float", "count": 1, "values": [1.0] }, - { "name": "FogShape", "type": "int", "count": 1, "values": [0] } + } ] } diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.fsh b/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.fsh index a599badde..14ee506cd 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.fsh +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.fsh @@ -14,6 +14,9 @@ void main() { float animation = GameTime * 2000.0; float animation1 = sin(animation) + 1; vec4 defaultColor = texture(Sampler0, texCoord0) * vertexColor; + if (defaultColor.a < 0.1) { + discard; + } vec4 color = vec4(0.15, animation1 * 0.15 + 0.65, 0, defaultColor.a); fragColor = color * ColorModulator; } \ No newline at end of file diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.json b/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.json index 755e33ce7..cecb25e39 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.json +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.json @@ -6,7 +6,7 @@ }, "vertex": "alexscaves:rendertype_irradiated", "fragment": "alexscaves:rendertype_irradiated", - "attributes": ["Position", "UV0", "Color"], + "attributes": ["Position", "Color", "UV0", "UV1", "UV2", "Normal"], "samplers": [{ "name": "Sampler0" }], "uniforms": [ { diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.vsh b/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.vsh index a23214475..c120b1716 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.vsh +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_irradiated.vsh @@ -1,8 +1,11 @@ #version 150 in vec3 Position; -in vec2 UV0; in vec4 Color; +in vec2 UV0; +in ivec2 UV1; +in ivec2 UV2; +in vec3 Normal; uniform mat4 ModelViewMat; uniform mat4 ProjMat; @@ -14,4 +17,5 @@ void main() { gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); vertexColor = Color; texCoord0 = UV0; + // UV1, UV2, Normal are received but not used - we just need the glowing color effect } diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.fsh b/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.fsh index 0da0c9b1d..0095e6f67 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.fsh +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.fsh @@ -12,7 +12,7 @@ out vec4 fragColor; void main() { vec4 color = texture(Sampler0, texCoord0); - if (color.a == 0.0) { + if (color.a < 0.1) { discard; } float animation = GameTime * 5000.0; @@ -20,3 +20,4 @@ void main() { vec3 purpleWitchColor = vec3(animation1 * 0.15 + 0.85, 0, animation1 * 0.15 + 0.85); fragColor = vec4(purpleWitchColor * ColorModulator.rgb * vertexColor.rgb, ColorModulator.a); } + diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.json b/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.json index 5a607a554..1f14214a6 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.json +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.json @@ -7,11 +7,7 @@ "vertex": "alexscaves:rendertype_purple_witch", "fragment": "alexscaves:rendertype_purple_witch", "attributes": ["Position", "Color", "UV0", "UV1", "UV2", "Normal"], - "samplers": [ - { "name": "Sampler0" }, - { "name": "Sampler1" }, - { "name": "Sampler2" } - ], + "samplers": [{ "name": "Sampler0" }], "uniforms": [ { "name": "ModelViewMat", @@ -37,27 +33,6 @@ "count": 4, "values": [1.0, 1.0, 1.0, 1.0] }, - { - "name": "Light0_Direction", - "type": "float", - "count": 3, - "values": [0.0, 0.0, 0.0] - }, - { - "name": "Light1_Direction", - "type": "float", - "count": 3, - "values": [0.0, 0.0, 0.0] - }, - { "name": "FogStart", "type": "float", "count": 1, "values": [0.0] }, - { "name": "FogEnd", "type": "float", "count": 1, "values": [1.0] }, - { - "name": "FogColor", - "type": "float", - "count": 4, - "values": [0.0, 0.0, 0.0, 0.0] - }, - { "name": "FogShape", "type": "int", "count": 1, "values": [0] }, { "name": "GameTime", "type": "float", "count": 1, "values": [0.0] } ] } diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.vsh b/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.vsh index b0036c0e1..fc4975c99 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.vsh +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_purple_witch.vsh @@ -1,8 +1,5 @@ #version 150 -#moj_import -#moj_import - in vec3 Position; in vec4 Color; in vec2 UV0; @@ -10,29 +7,16 @@ in ivec2 UV1; in ivec2 UV2; in vec3 Normal; -uniform sampler2D Sampler1; -uniform sampler2D Sampler2; - uniform mat4 ModelViewMat; uniform mat4 ProjMat; -uniform int FogShape; -uniform vec3 Light0_Direction; -uniform vec3 Light1_Direction; - -out float vertexDistance; out vec4 vertexColor; -out vec4 lightMapColor; -out vec4 overlayColor; out vec2 texCoord0; -out vec4 normal; void main() { gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); - vertexDistance = fog_distance((ModelViewMat * vec4(Position, 1.0)).xyz, FogShape); - vertexColor = minecraft_mix_light(Light0_Direction, Light1_Direction, Normal, Color); - lightMapColor = texelFetch(Sampler2, UV2 / 16, 0); - overlayColor = texelFetch(Sampler1, UV1, 0); + vertexColor = Color; texCoord0 = UV0; - normal = ProjMat * ModelViewMat * vec4(Normal, 0.0); + // UV1, UV2, Normal are received but not used - we just need the glowing color effect } + diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.fsh b/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.fsh index 48dc354fa..f19a55b21 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.fsh +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.fsh @@ -7,9 +7,11 @@ uniform sampler2D Sampler0; uniform vec4 ColorModulator; uniform float FogStart; uniform float FogEnd; +uniform vec4 FogColor; in float vertexDistance; in vec4 vertexColor; +in vec4 lightMapColor; in vec4 overlayColor; in vec2 texCoord0; in vec4 normal; @@ -17,25 +19,24 @@ in vec4 normal; out vec4 fragColor; void main() { - vec4 color = texture(Sampler0, texCoord0) * ColorModulator; + vec4 color = texture(Sampler0, texCoord0) * vertexColor * ColorModulator; if (color.a < 0.1) { discard; } - color *= vertexColor * ColorModulator; color.rgb = mix(overlayColor.rgb, color.rgb, overlayColor.a); - vec4 almostFinalColor = color * linear_fog_fade(vertexDistance, FogStart, FogEnd); + color *= lightMapColor; float targetR = .9; float targetG = .3; float targetB = .05; - float colorVal = almostFinalColor.r; - if(almostFinalColor.g > colorVal){ - colorVal = almostFinalColor.g; + float colorVal = color.r; + if(color.g > colorVal){ + colorVal = color.g; } - if(almostFinalColor.b > colorVal){ - colorVal = almostFinalColor.b; + if(color.b > colorVal){ + colorVal = color.b; } - fragColor = vec4(colorVal * targetR, colorVal * targetG, colorVal * targetB, almostFinalColor.a); - + vec4 ghostColor = vec4(colorVal * targetR, colorVal * targetG, colorVal * targetB, color.a); + fragColor = linear_fog(ghostColor, vertexDistance, FogStart, FogEnd, FogColor); } \ No newline at end of file diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.json b/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.json index f423f69b6..ed3d40e2f 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.json +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.json @@ -37,18 +37,6 @@ "count": 4, "values": [1.0, 1.0, 1.0, 1.0] }, - { - "name": "Light0_Direction", - "type": "float", - "count": 3, - "values": [0.0, 0.0, 0.0] - }, - { - "name": "Light1_Direction", - "type": "float", - "count": 3, - "values": [0.0, 0.0, 0.0] - }, { "name": "FogStart", "type": "float", "count": 1, "values": [0.0] }, { "name": "FogEnd", "type": "float", "count": 1, "values": [1.0] }, { @@ -56,7 +44,6 @@ "type": "float", "count": 4, "values": [0.0, 0.0, 0.0, 0.0] - }, - { "name": "FogShape", "type": "int", "count": 1, "values": [0] } + } ] } diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.vsh b/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.vsh index b0036c0e1..6ce597e23 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.vsh +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_red_ghost.vsh @@ -1,8 +1,5 @@ #version 150 -#moj_import -#moj_import - in vec3 Position; in vec4 Color; in vec2 UV0; @@ -15,10 +12,6 @@ uniform sampler2D Sampler2; uniform mat4 ModelViewMat; uniform mat4 ProjMat; -uniform int FogShape; - -uniform vec3 Light0_Direction; -uniform vec3 Light1_Direction; out float vertexDistance; out vec4 vertexColor; @@ -29,8 +22,9 @@ out vec4 normal; void main() { gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); - vertexDistance = fog_distance((ModelViewMat * vec4(Position, 1.0)).xyz, FogShape); - vertexColor = minecraft_mix_light(Light0_Direction, Light1_Direction, Normal, Color); + + vertexDistance = length((ModelViewMat * vec4(Position, 1.0)).xyz); + vertexColor = Color; lightMapColor = texelFetch(Sampler2, UV2 / 16, 0); overlayColor = texelFetch(Sampler1, UV1, 0); texCoord0 = UV0; diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_sepia.json b/src/main/resources/assets/alexscaves/shaders/core/rendertype_sepia.json index b21d43978..6fa8ed2fe 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_sepia.json +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_sepia.json @@ -4,14 +4,10 @@ "srcrgb": "srcalpha", "dstrgb": "1-srcalpha" }, - "vertex": "alexscaves:rendertype_sepia", + "vertex": "rendertype_entity_translucent", "fragment": "alexscaves:rendertype_sepia", "attributes": ["Position", "Color", "UV0", "UV1", "UV2", "Normal"], - "samplers": [ - { "name": "Sampler0" }, - { "name": "Sampler1" }, - { "name": "Sampler2" } - ], + "samplers": [{ "name": "Sampler0" }], "uniforms": [ { "name": "ModelViewMat", @@ -37,26 +33,8 @@ "count": 4, "values": [1.0, 1.0, 1.0, 1.0] }, - { - "name": "Light0_Direction", - "type": "float", - "count": 3, - "values": [0.0, 0.0, 0.0] - }, - { - "name": "Light1_Direction", - "type": "float", - "count": 3, - "values": [0.0, 0.0, 0.0] - }, { "name": "FogStart", "type": "float", "count": 1, "values": [0.0] }, { "name": "FogEnd", "type": "float", "count": 1, "values": [1.0] }, - { - "name": "FogColor", - "type": "float", - "count": 4, - "values": [0.0, 0.0, 0.0, 0.0] - }, { "name": "FogShape", "type": "int", "count": 1, "values": [0] } ] } diff --git a/src/main/resources/assets/alexscaves/shaders/core/rendertype_sepia.vsh b/src/main/resources/assets/alexscaves/shaders/core/rendertype_sepia.vsh index b0036c0e1..6ce597e23 100644 --- a/src/main/resources/assets/alexscaves/shaders/core/rendertype_sepia.vsh +++ b/src/main/resources/assets/alexscaves/shaders/core/rendertype_sepia.vsh @@ -1,8 +1,5 @@ #version 150 -#moj_import -#moj_import - in vec3 Position; in vec4 Color; in vec2 UV0; @@ -15,10 +12,6 @@ uniform sampler2D Sampler2; uniform mat4 ModelViewMat; uniform mat4 ProjMat; -uniform int FogShape; - -uniform vec3 Light0_Direction; -uniform vec3 Light1_Direction; out float vertexDistance; out vec4 vertexColor; @@ -29,8 +22,9 @@ out vec4 normal; void main() { gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0); - vertexDistance = fog_distance((ModelViewMat * vec4(Position, 1.0)).xyz, FogShape); - vertexColor = minecraft_mix_light(Light0_Direction, Light1_Direction, Normal, Color); + + vertexDistance = length((ModelViewMat * vec4(Position, 1.0)).xyz); + vertexColor = Color; lightMapColor = texelFetch(Sampler2, UV2 / 16, 0); overlayColor = texelFetch(Sampler1, UV1, 0); texCoord0 = UV0; diff --git a/src/main/resources/assets/alexscaves/shaders/post/hologram.json b/src/main/resources/assets/alexscaves/shaders/post/hologram.json index b62b5b8ec..e4cc7f257 100644 --- a/src/main/resources/assets/alexscaves/shaders/post/hologram.json +++ b/src/main/resources/assets/alexscaves/shaders/post/hologram.json @@ -1,36 +1,33 @@ { - "targets": [ - "swap", - "final" - ], + "targets": ["swap", "final"], "passes": [ { - "name": "blur", + "name": "citadel:blur", "intarget": "final", "outtarget": "swap", "uniforms": [ { "name": "BlurDir", - "values": [ 0.0, 1.0 ] + "values": [0.0, 1.0] }, { "name": "Radius", - "values": [ 2.0 ] + "values": [2.0] } ] }, { - "name": "blur", + "name": "citadel:blur", "intarget": "swap", "outtarget": "final", "uniforms": [ { "name": "BlurDir", - "values": [ 1.0, 0.0 ] + "values": [1.0, 0.0] }, { "name": "Radius", - "values": [ 2.0 ] + "values": [2.0] } ] }, diff --git a/src/main/resources/assets/alexscaves/shaders/post/irradiated.json b/src/main/resources/assets/alexscaves/shaders/post/irradiated.json index 55625d1d7..11c0916b0 100644 --- a/src/main/resources/assets/alexscaves/shaders/post/irradiated.json +++ b/src/main/resources/assets/alexscaves/shaders/post/irradiated.json @@ -1,41 +1,38 @@ { - "targets": [ - "swap", - "final" - ], + "targets": ["swap", "final"], "passes": [ { - "name": "blur", + "name": "citadel:blur", "intarget": "final", "outtarget": "swap", "uniforms": [ { "name": "BlurDir", - "values": [ 0.0, 1.0 ] + "values": [0.0, 1.0] }, { "name": "Radius", - "values": [ 32.0 ] + "values": [32.0] } ] }, { - "name": "blur", + "name": "citadel:blur", "intarget": "swap", "outtarget": "final", "uniforms": [ { "name": "BlurDir", - "values": [ 1.0, 0.0 ] + "values": [1.0, 0.0] }, { "name": "Radius", - "values": [ 32.0 ] + "values": [32.0] } ] }, { - "name": "bumpy", + "name": "citadel:bumpy", "intarget": "final", "outtarget": "swap" }, diff --git a/src/main/resources/assets/alexscaves/shaders/post/purple_witch.json b/src/main/resources/assets/alexscaves/shaders/post/purple_witch.json index a3d8373b4..e75c7d546 100644 --- a/src/main/resources/assets/alexscaves/shaders/post/purple_witch.json +++ b/src/main/resources/assets/alexscaves/shaders/post/purple_witch.json @@ -1,8 +1,5 @@ { - "targets": [ - "swap", - "final" - ], + "targets": ["swap", "final"], "passes": [ { "name": "entity_outline", @@ -10,32 +7,32 @@ "outtarget": "swap" }, { - "name": "blur", + "name": "citadel:blur", "intarget": "swap", "outtarget": "final", "uniforms": [ { "name": "BlurDir", - "values": [ 1.0, 0.0 ] + "values": [1.0, 0.0] }, { "name": "Radius", - "values": [ 12.0 ] + "values": [12.0] } ] }, { - "name": "blur", + "name": "citadel:blur", "intarget": "final", "outtarget": "swap", "uniforms": [ { "name": "BlurDir", - "values": [ 0.0, 1.0 ] + "values": [0.0, 1.0] }, { "name": "Radius", - "values": [ 12.0 ] + "values": [12.0] } ] }, diff --git a/src/main/resources/assets/alexscaves/shaders/post/sepia.json b/src/main/resources/assets/alexscaves/shaders/post/sepia.json index e53ff3dba..5c2d641a2 100644 --- a/src/main/resources/assets/alexscaves/shaders/post/sepia.json +++ b/src/main/resources/assets/alexscaves/shaders/post/sepia.json @@ -1,48 +1,45 @@ { - "targets": [ - "swap", - "final" - ], - "passes": [ + "targets": ["swap", "final"], + "passes": [ + { + "name": "entity_outline", + "intarget": "final", + "outtarget": "swap" + }, + { + "name": "citadel:blur", + "intarget": "swap", + "outtarget": "final", + "uniforms": [ { - "name": "entity_outline", - "intarget": "final", - "outtarget": "swap" + "name": "BlurDir", + "values": [1.0, 0.0] }, { - "name": "blur", - "intarget": "swap", - "outtarget": "final", - "uniforms": [ - { - "name": "BlurDir", - "values": [ 1.0, 0.0 ] - }, - { - "name": "Radius", - "values": [ 2.0 ] - } - ] - }, + "name": "Radius", + "values": [2.0] + } + ] + }, + { + "name": "citadel:blur", + "intarget": "final", + "outtarget": "swap", + "uniforms": [ { - "name": "blur", - "intarget": "final", - "outtarget": "swap", - "uniforms": [ - { - "name": "BlurDir", - "values": [ 0.0, 1.0 ] - }, - { - "name": "Radius", - "values": [ 2.0 ] - } - ] + "name": "BlurDir", + "values": [0.0, 1.0] }, { - "name": "blit", - "intarget": "swap", - "outtarget": "final" + "name": "Radius", + "values": [2.0] } - ] + ] + }, + { + "name": "blit", + "intarget": "swap", + "outtarget": "final" + } + ] } diff --git a/src/main/resources/assets/alexscaves/shaders/post/submarine_light.json b/src/main/resources/assets/alexscaves/shaders/post/submarine_light.json index 438035e74..1646703b4 100644 --- a/src/main/resources/assets/alexscaves/shaders/post/submarine_light.json +++ b/src/main/resources/assets/alexscaves/shaders/post/submarine_light.json @@ -1,30 +1,27 @@ { - "targets": [ - "minecraft:main", - "swap" - ], - "passes": [ + "targets": ["minecraft:main", "swap"], + "passes": [ + { + "name": "alexscaves:submarine_light", + "intarget": "minecraft:main", + "outtarget": "swap", + "auxtargets": [ { - "name": "alexscaves:submarine_light", - "intarget": "minecraft:main", - "outtarget": "swap", - "auxtargets": [ - { - "name": "DiffuseDepthSampler", - "id": "minecraft:main:depth" - } - ] - }, + "name": "DiffuseDepthSampler", + "id": "minecraft:main:depth" + } + ] + }, + { + "name": "blit", + "intarget": "swap", + "outtarget": "minecraft:main", + "auxtargets": [ { - "name": "blit", - "intarget": "swap", - "outtarget": "minecraft:main", - "auxtargets": [ - { - "name": "DiffuseDepthSampler", - "id": "minecraft:main:depth" - } - ] + "name": "DiffuseDepthSampler", + "id": "minecraft:main:depth" } - ] + ] + } + ] } diff --git a/src/main/resources/assets/alexscaves/shaders/post/sugar_rush.json b/src/main/resources/assets/alexscaves/shaders/post/sugar_rush.json index d80e67755..782d676ac 100644 --- a/src/main/resources/assets/alexscaves/shaders/post/sugar_rush.json +++ b/src/main/resources/assets/alexscaves/shaders/post/sugar_rush.json @@ -1,23 +1,21 @@ { - "targets": [ - "swap" - ], - "passes": [ + "targets": ["swap"], + "passes": [ + { + "name": "color_convolve", + "intarget": "minecraft:main", + "outtarget": "swap", + "uniforms": [ { - "name": "color_convolve", - "intarget": "minecraft:main", - "outtarget": "swap", - "uniforms": [ - { - "name": "Saturation", - "values": [ 1.65 ] - } - ] - }, - { - "name": "blit", - "intarget": "swap", - "outtarget": "minecraft:main" + "name": "Saturation", + "values": [1.65] } - ] + ] + }, + { + "name": "blit", + "intarget": "swap", + "outtarget": "minecraft:main" + } + ] } diff --git a/src/main/resources/assets/alexscaves/shaders/post/watcher_perspective.json b/src/main/resources/assets/alexscaves/shaders/post/watcher_perspective.json index c383fb34d..6400cc17a 100644 --- a/src/main/resources/assets/alexscaves/shaders/post/watcher_perspective.json +++ b/src/main/resources/assets/alexscaves/shaders/post/watcher_perspective.json @@ -1,62 +1,57 @@ { - "targets": [ - "swap", - "largeBlur", - "largeBlur2", - "temp" - ], - "passes": [ + "targets": ["swap", "largeBlur", "largeBlur2", "temp"], + "passes": [ + { + "name": "citadel:blur", + "intarget": "minecraft:main", + "outtarget": "swap", + "uniforms": [ { - "name": "blur", - "intarget": "minecraft:main", - "outtarget": "swap", - "uniforms": [ - { - "name": "BlurDir", - "values": [ 1.0, 0.0 ] - }, - { - "name": "Radius", - "values": [ 15.0 ] - } - ] + "name": "BlurDir", + "values": [1.0, 0.0] }, { - "name": "blur", - "intarget": "swap", - "outtarget": "largeBlur", - "uniforms": [ - { - "name": "BlurDir", - "values": [ 0.0, 1.0 ] - }, - { - "name": "Radius", - "values": [ 15.0 ] - } - ] - }, + "name": "Radius", + "values": [15.0] + } + ] + }, + { + "name": "citadel:blur", + "intarget": "swap", + "outtarget": "largeBlur", + "uniforms": [ { - "name": "alexscaves:watcher_blur", - "intarget": "minecraft:main", - "outtarget": "temp", - "auxtargets": [ - { - "name": "BlurSampler", - "id": "largeBlur" - } - ] + "name": "BlurDir", + "values": [0.0, 1.0] }, { - "name": "blit", - "intarget": "temp", - "outtarget": "minecraft:main", - "uniforms": [ - { - "name": "ColorModulate", - "values": [ 1.0, 0.6, 0.4, 1.0 ] - } - ] + "name": "Radius", + "values": [15.0] + } + ] + }, + { + "name": "alexscaves:watcher_blur", + "intarget": "minecraft:main", + "outtarget": "temp", + "auxtargets": [ + { + "name": "BlurSampler", + "id": "largeBlur" + } + ] + }, + { + "name": "blit", + "intarget": "temp", + "outtarget": "minecraft:main", + "uniforms": [ + { + "name": "ColorModulate", + "values": [1.0, 0.6, 0.4, 1.0] } - ] + ] + } + ] } diff --git a/src/main/resources/assets/alexscaves/shaders/program/submarine_light.json b/src/main/resources/assets/alexscaves/shaders/program/submarine_light.json index 66b021900..0923e0c63 100644 --- a/src/main/resources/assets/alexscaves/shaders/program/submarine_light.json +++ b/src/main/resources/assets/alexscaves/shaders/program/submarine_light.json @@ -1,19 +1,26 @@ { - "blend": { - "func": "add", - "srcrgb": "one", - "dstrgb": "zero" + "blend": { + "func": "add", + "srcrgb": "one", + "dstrgb": "zero" + }, + "vertex": "alexscaves:submarine_light", + "fragment": "alexscaves:submarine_light", + "attributes": ["Position"], + "samplers": [{ "name": "DiffuseDepthSampler" }, { "name": "DiffuseSampler" }], + "uniforms": [ + { + "name": "ProjMat", + "type": "matrix4x4", + "count": 16, + "values": [ + 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0 + ] }, - "vertex": "alexscaves:submarine_light", - "fragment": "alexscaves:submarine_light", - "attributes": [ "Position" ], - "samplers": [ - { "name": "DiffuseDepthSampler" }, - { "name": "DiffuseSampler" } - ], - "uniforms": [ - { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, - { "name": "ScreenSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, - { "name": "_FOV", "type": "float", "count": 1, "values": [ 70.0 ] } - ] + { "name": "InSize", "type": "float", "count": 2, "values": [1.0, 1.0] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [1.0, 1.0] }, + { "name": "ScreenSize", "type": "float", "count": 2, "values": [1.0, 1.0] }, + { "name": "_FOV", "type": "float", "count": 1, "values": [70.0] } + ] } diff --git a/src/main/resources/assets/alexscaves/shaders/program/submarine_light.vsh b/src/main/resources/assets/alexscaves/shaders/program/submarine_light.vsh index e726f3407..c04bcb3f3 100644 --- a/src/main/resources/assets/alexscaves/shaders/program/submarine_light.vsh +++ b/src/main/resources/assets/alexscaves/shaders/program/submarine_light.vsh @@ -4,6 +4,7 @@ in vec4 Position; uniform mat4 ProjMat; uniform vec2 InSize; +uniform vec2 OutSize; out vec2 texCoord; out vec2 oneTexel; @@ -13,5 +14,5 @@ void main() { gl_Position = vec4(outPos.xy, 0.2, 1.0); oneTexel = 1.0 / InSize; - texCoord = outPos.xy * 0.5 + 0.5; + texCoord = Position.xy / OutSize; } \ No newline at end of file diff --git a/src/main/resources/assets/alexscaves/shaders/program/watcher_blur.json b/src/main/resources/assets/alexscaves/shaders/program/watcher_blur.json index df4303bd2..a926aeb15 100644 --- a/src/main/resources/assets/alexscaves/shaders/program/watcher_blur.json +++ b/src/main/resources/assets/alexscaves/shaders/program/watcher_blur.json @@ -1,19 +1,26 @@ { - "blend": { - "func": "add", - "srcrgb": "one", - "dstrgb": "zero" + "blend": { + "func": "add", + "srcrgb": "one", + "dstrgb": "zero" + }, + "vertex": "alexscaves:watcher_blur", + "fragment": "alexscaves:watcher_blur", + "attributes": ["Position"], + "samplers": [{ "name": "DiffuseSampler" }, { "name": "BlurSampler" }], + "uniforms": [ + { + "name": "ProjMat", + "type": "matrix4x4", + "count": 16, + "values": [ + 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0 + ] }, - "vertex": "alexscaves:watcher_blur", - "fragment": "alexscaves:watcher_blur", - "attributes": [ "Position" ], - "samplers": [ - { "name": "DiffuseSampler" }, - { "name": "BlurSampler" } - ], - "uniforms": [ - { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, - { "name": "ScreenSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, - { "name": "_FOV", "type": "float", "count": 1, "values": [ 70.0 ] } - ] + { "name": "InSize", "type": "float", "count": 2, "values": [1.0, 1.0] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [1.0, 1.0] }, + { "name": "ScreenSize", "type": "float", "count": 2, "values": [1.0, 1.0] }, + { "name": "_FOV", "type": "float", "count": 1, "values": [70.0] } + ] } diff --git a/src/main/resources/assets/alexscaves/shaders/program/watcher_blur.vsh b/src/main/resources/assets/alexscaves/shaders/program/watcher_blur.vsh index e726f3407..c04bcb3f3 100644 --- a/src/main/resources/assets/alexscaves/shaders/program/watcher_blur.vsh +++ b/src/main/resources/assets/alexscaves/shaders/program/watcher_blur.vsh @@ -4,6 +4,7 @@ in vec4 Position; uniform mat4 ProjMat; uniform vec2 InSize; +uniform vec2 OutSize; out vec2 texCoord; out vec2 oneTexel; @@ -13,5 +14,5 @@ void main() { gl_Position = vec4(outPos.xy, 0.2, 1.0); oneTexel = 1.0 / InSize; - texCoord = outPos.xy * 0.5 + 0.5; + texCoord = Position.xy / OutSize; } \ No newline at end of file diff --git a/src/main/resources/data/alexscaves/enchantment/astral_transferring.json b/src/main/resources/data/alexscaves/enchantment/astral_transferring.json index 6fcf6b0b1..89b51cf72 100644 --- a/src/main/resources/data/alexscaves/enchantment/astral_transferring.json +++ b/src/main/resources/data/alexscaves/enchantment/astral_transferring.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.astral_transferring" }, + "exclusive_set": "#alexscaves:exclusive_totem_of_possession", "supported_items": "#alexscaves:totem_of_possession_enchantable", "weight": 2, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/bouncing_bolt.json b/src/main/resources/data/alexscaves/enchantment/bouncing_bolt.json index be53c95da..7a59bfe25 100644 --- a/src/main/resources/data/alexscaves/enchantment/bouncing_bolt.json +++ b/src/main/resources/data/alexscaves/enchantment/bouncing_bolt.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.bouncing_bolt" }, + "exclusive_set": "#alexscaves:exclusive_sea_staff", "supported_items": "#alexscaves:sea_staff_enchantable", "weight": 2, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/dark_nock.json b/src/main/resources/data/alexscaves/enchantment/dark_nock.json index c5b5aeb7f..fe14b121c 100644 --- a/src/main/resources/data/alexscaves/enchantment/dark_nock.json +++ b/src/main/resources/data/alexscaves/enchantment/dark_nock.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.dark_nock" }, + "exclusive_set": "#alexscaves:exclusive_with_relentless_darkness", "supported_items": "#alexscaves:dreadbow_enchantable", "weight": 2, "max_level": 3, diff --git a/src/main/resources/data/alexscaves/enchantment/detonating_death.json b/src/main/resources/data/alexscaves/enchantment/detonating_death.json index dcea62623..fc88e356c 100644 --- a/src/main/resources/data/alexscaves/enchantment/detonating_death.json +++ b/src/main/resources/data/alexscaves/enchantment/detonating_death.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.detonating_death" }, + "exclusive_set": "#alexscaves:exclusive_totem_of_possession", "supported_items": "#alexscaves:totem_of_possession_enchantable", "weight": 2, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/double_stab.json b/src/main/resources/data/alexscaves/enchantment/double_stab.json index e6b7edb85..cf335bd08 100644 --- a/src/main/resources/data/alexscaves/enchantment/double_stab.json +++ b/src/main/resources/data/alexscaves/enchantment/double_stab.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.double_stab" }, + "exclusive_set": "#alexscaves:exclusive_desolate_dagger", "supported_items": "#alexscaves:desolate_dagger_enchantable", "weight": 2, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/gamma_ray.json b/src/main/resources/data/alexscaves/enchantment/gamma_ray.json index c50e8739b..bc22be8a6 100644 --- a/src/main/resources/data/alexscaves/enchantment/gamma_ray.json +++ b/src/main/resources/data/alexscaves/enchantment/gamma_ray.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.gamma_ray" }, + "exclusive_set": "#alexscaves:exclusive_raygun", "supported_items": "#alexscaves:raygun_enchantable", "weight": 2, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/impending_stab.json b/src/main/resources/data/alexscaves/enchantment/impending_stab.json index 2b707b824..4516da8c2 100644 --- a/src/main/resources/data/alexscaves/enchantment/impending_stab.json +++ b/src/main/resources/data/alexscaves/enchantment/impending_stab.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.impending_stab" }, + "exclusive_set": "#alexscaves:exclusive_desolate_dagger", "supported_items": "#alexscaves:desolate_dagger_enchantable", "weight": 10, "max_level": 3, diff --git a/src/main/resources/data/alexscaves/enchantment/precise_volley.json b/src/main/resources/data/alexscaves/enchantment/precise_volley.json index 963d83c5b..db0dd6345 100644 --- a/src/main/resources/data/alexscaves/enchantment/precise_volley.json +++ b/src/main/resources/data/alexscaves/enchantment/precise_volley.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.precise_volley" }, + "exclusive_set": "#alexscaves:exclusive_with_relentless_darkness", "supported_items": "#alexscaves:dreadbow_enchantable", "weight": 2, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/relentless_darkness.json b/src/main/resources/data/alexscaves/enchantment/relentless_darkness.json index 112531adf..47b086298 100644 --- a/src/main/resources/data/alexscaves/enchantment/relentless_darkness.json +++ b/src/main/resources/data/alexscaves/enchantment/relentless_darkness.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.relentless_darkness" }, + "exclusive_set": "#alexscaves:exclusive_with_relentless_darkness", "supported_items": "#alexscaves:dreadbow_enchantable", "weight": 1, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/second_wave.json b/src/main/resources/data/alexscaves/enchantment/second_wave.json index c4d21faab..de5756434 100644 --- a/src/main/resources/data/alexscaves/enchantment/second_wave.json +++ b/src/main/resources/data/alexscaves/enchantment/second_wave.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.second_wave" }, + "exclusive_set": "#alexscaves:exclusive_ortholance", "supported_items": "#alexscaves:ortholance_enchantable", "weight": 2, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/targeted_ricochet.json b/src/main/resources/data/alexscaves/enchantment/targeted_ricochet.json index 5592144c3..51db33c62 100644 --- a/src/main/resources/data/alexscaves/enchantment/targeted_ricochet.json +++ b/src/main/resources/data/alexscaves/enchantment/targeted_ricochet.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.targeted_ricochet" }, + "exclusive_set": "#alexscaves:exclusive_shot_gum", "supported_items": "#alexscaves:shot_gum_enchantable", "weight": 2, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/triple_splash.json b/src/main/resources/data/alexscaves/enchantment/triple_splash.json index 7bc0ca349..bd93bd844 100644 --- a/src/main/resources/data/alexscaves/enchantment/triple_splash.json +++ b/src/main/resources/data/alexscaves/enchantment/triple_splash.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.triple_splash" }, + "exclusive_set": "#alexscaves:exclusive_sea_staff", "supported_items": "#alexscaves:sea_staff_enchantable", "weight": 2, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/triple_split.json b/src/main/resources/data/alexscaves/enchantment/triple_split.json index 5151ee54d..d55fcccc9 100644 --- a/src/main/resources/data/alexscaves/enchantment/triple_split.json +++ b/src/main/resources/data/alexscaves/enchantment/triple_split.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.triple_split" }, + "exclusive_set": "#alexscaves:exclusive_shot_gum", "supported_items": "#alexscaves:shot_gum_enchantable", "weight": 2, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/tsunami.json b/src/main/resources/data/alexscaves/enchantment/tsunami.json index 9c07db88c..6eb954f58 100644 --- a/src/main/resources/data/alexscaves/enchantment/tsunami.json +++ b/src/main/resources/data/alexscaves/enchantment/tsunami.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.tsunami" }, + "exclusive_set": "#alexscaves:exclusive_ortholance", "supported_items": "#alexscaves:ortholance_enchantable", "weight": 1, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/enchantment/twilight_perfection.json b/src/main/resources/data/alexscaves/enchantment/twilight_perfection.json index 5f9360b4a..0cefaee42 100644 --- a/src/main/resources/data/alexscaves/enchantment/twilight_perfection.json +++ b/src/main/resources/data/alexscaves/enchantment/twilight_perfection.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.twilight_perfection" }, + "exclusive_set": "#alexscaves:exclusive_with_relentless_darkness", "supported_items": "#alexscaves:dreadbow_enchantable", "weight": 2, "max_level": 3, diff --git a/src/main/resources/data/alexscaves/enchantment/x_ray.json b/src/main/resources/data/alexscaves/enchantment/x_ray.json index fc0e12db6..bf5fc5f77 100644 --- a/src/main/resources/data/alexscaves/enchantment/x_ray.json +++ b/src/main/resources/data/alexscaves/enchantment/x_ray.json @@ -2,6 +2,7 @@ "description": { "translate": "enchantment.alexscaves.x_ray" }, + "exclusive_set": "#alexscaves:exclusive_raygun", "supported_items": "#alexscaves:raygun_enchantable", "weight": 10, "max_level": 1, diff --git a/src/main/resources/data/alexscaves/tags/enchantment/exclusive_desolate_dagger.json b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_desolate_dagger.json new file mode 100644 index 000000000..bb6af9bf3 --- /dev/null +++ b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_desolate_dagger.json @@ -0,0 +1,3 @@ +{ + "values": ["alexscaves:double_stab", "alexscaves:impending_stab"] +} diff --git a/src/main/resources/data/alexscaves/tags/enchantment/exclusive_ortholance.json b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_ortholance.json new file mode 100644 index 000000000..87f124f8c --- /dev/null +++ b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_ortholance.json @@ -0,0 +1,3 @@ +{ + "values": ["alexscaves:second_wave", "alexscaves:tsunami"] +} diff --git a/src/main/resources/data/alexscaves/tags/enchantment/exclusive_raygun.json b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_raygun.json new file mode 100644 index 000000000..b3d2f21e5 --- /dev/null +++ b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_raygun.json @@ -0,0 +1,3 @@ +{ + "values": ["alexscaves:x_ray", "alexscaves:gamma_ray"] +} diff --git a/src/main/resources/data/alexscaves/tags/enchantment/exclusive_sea_staff.json b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_sea_staff.json new file mode 100644 index 000000000..150db158c --- /dev/null +++ b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_sea_staff.json @@ -0,0 +1,3 @@ +{ + "values": ["alexscaves:bouncing_bolt", "alexscaves:triple_splash"] +} diff --git a/src/main/resources/data/alexscaves/tags/enchantment/exclusive_shot_gum.json b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_shot_gum.json new file mode 100644 index 000000000..b003ffbde --- /dev/null +++ b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_shot_gum.json @@ -0,0 +1,3 @@ +{ + "values": ["alexscaves:targeted_ricochet", "alexscaves:triple_split"] +} diff --git a/src/main/resources/data/alexscaves/tags/enchantment/exclusive_totem_of_possession.json b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_totem_of_possession.json new file mode 100644 index 000000000..6fbe679d0 --- /dev/null +++ b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_totem_of_possession.json @@ -0,0 +1,3 @@ +{ + "values": ["alexscaves:detonating_death", "alexscaves:astral_transferring"] +} diff --git a/src/main/resources/data/alexscaves/tags/enchantment/exclusive_with_relentless_darkness.json b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_with_relentless_darkness.json new file mode 100644 index 000000000..801059949 --- /dev/null +++ b/src/main/resources/data/alexscaves/tags/enchantment/exclusive_with_relentless_darkness.json @@ -0,0 +1,8 @@ +{ + "values": [ + "alexscaves:relentless_darkness", + "alexscaves:precise_volley", + "alexscaves:dark_nock", + "alexscaves:twilight_perfection" + ] +} diff --git a/src/main/resources/data/alexscaves/tags/item/vallumraptor_steals.json b/src/main/resources/data/alexscaves/tags/item/vallumraptor_steals.json index 64c09a368..3a50d1214 100644 --- a/src/main/resources/data/alexscaves/tags/item/vallumraptor_steals.json +++ b/src/main/resources/data/alexscaves/tags/item/vallumraptor_steals.json @@ -3,6 +3,7 @@ "values": [ "#minecraft:eggs", "alexscaves:dinosaur_chop", - "alexscaves:cooked_dinosaur_chop" + "alexscaves:cooked_dinosaur_chop", + "alexscaves:dinosaur_nugget" ] -} \ No newline at end of file +} diff --git a/src/main/resources/data/alexscaves/tags/worldgen/structure/ore_protected.json b/src/main/resources/data/alexscaves/tags/worldgen/structure/ore_protected.json new file mode 100644 index 000000000..b70480464 --- /dev/null +++ b/src/main/resources/data/alexscaves/tags/worldgen/structure/ore_protected.json @@ -0,0 +1,11 @@ +{ + "values": [ + "alexscaves:underground_cabin", + "alexscaves:gingerbread_town", + "alexscaves:licowitch_tower", + "alexscaves:soda_bottle", + "alexscaves:abyssal_ruins", + "alexscaves:forlorn_bridge", + "alexscaves:donut_arch" + ] +} diff --git a/src/main/resources/data/minecraft/tags/entity_type/can_breathe_under_water.json b/src/main/resources/data/minecraft/tags/entity_type/can_breathe_under_water.json new file mode 100644 index 000000000..e01a1ffdc --- /dev/null +++ b/src/main/resources/data/minecraft/tags/entity_type/can_breathe_under_water.json @@ -0,0 +1,18 @@ +{ + "__comment": "All entities that can breathe underwater.", + "values": [ + "alexscaves:deep_one", + "alexscaves:deep_one_knight", + "alexscaves:deep_one_mage", + "alexscaves:mine_guardian", + "alexscaves:tremorzilla", + "alexscaves:trilocaris", + "alexscaves:radgill", + "alexscaves:lanternfish", + "alexscaves:sweetish_fish", + "alexscaves:sea_pig", + "alexscaves:gossamer_worm", + "alexscaves:tripodfish", + "alexscaves:hullbreaker" + ] +} diff --git a/src/main/resources/data/minecraft/tags/worldgen/biome/has_structure/mineshaft.json b/src/main/resources/data/minecraft/tags/worldgen/biome/has_structure/mineshaft.json new file mode 100644 index 000000000..d2b5b1b7e --- /dev/null +++ b/src/main/resources/data/minecraft/tags/worldgen/biome/has_structure/mineshaft.json @@ -0,0 +1,5 @@ +{ + "replace": false, + "values": [], + "remove": ["#alexscaves:alexs_caves_biomes"] +} diff --git a/src/main/resources/data/minecraft/tags/worldgen/biome/has_structure/stronghold.json b/src/main/resources/data/minecraft/tags/worldgen/biome/has_structure/stronghold.json new file mode 100644 index 000000000..d2b5b1b7e --- /dev/null +++ b/src/main/resources/data/minecraft/tags/worldgen/biome/has_structure/stronghold.json @@ -0,0 +1,5 @@ +{ + "replace": false, + "values": [], + "remove": ["#alexscaves:alexs_caves_biomes"] +} diff --git a/src/main/resources/data/minecraft/tags/worldgen/biome/has_structure/trial_chambers.json b/src/main/resources/data/minecraft/tags/worldgen/biome/has_structure/trial_chambers.json new file mode 100644 index 000000000..d2b5b1b7e --- /dev/null +++ b/src/main/resources/data/minecraft/tags/worldgen/biome/has_structure/trial_chambers.json @@ -0,0 +1,5 @@ +{ + "replace": false, + "values": [], + "remove": ["#alexscaves:alexs_caves_biomes"] +} diff --git a/src/main/resources/data/minecraft/tags/worldgen/biome/mineshaft_blocking.json b/src/main/resources/data/minecraft/tags/worldgen/biome/mineshaft_blocking.json new file mode 100644 index 000000000..a2277405a --- /dev/null +++ b/src/main/resources/data/minecraft/tags/worldgen/biome/mineshaft_blocking.json @@ -0,0 +1,4 @@ +{ + "replace": false, + "values": ["#alexscaves:alexs_caves_biomes"] +} diff --git a/src/main/resources/data/neoforge/data_maps/item/compostables.json b/src/main/resources/data/neoforge/data_maps/item/compostables.json new file mode 100644 index 000000000..4ecc2b5f1 --- /dev/null +++ b/src/main/resources/data/neoforge/data_maps/item/compostables.json @@ -0,0 +1,55 @@ +{ + "values": { + "alexscaves:pine_nuts": { + "chance": 0.5 + }, + "alexscaves:pewen_sap": { + "chance": 0.2 + }, + "alexscaves:pewen_sapling": { + "chance": 0.3 + }, + "alexscaves:pewen_pines": { + "chance": 0.3 + }, + "alexscaves:pewen_branch": { + "chance": 0.3 + }, + "alexscaves:ancient_sapling": { + "chance": 0.3 + }, + "alexscaves:ancient_leaves": { + "chance": 0.3 + }, + "alexscaves:fiddlehead": { + "chance": 0.4 + }, + "alexscaves:curly_fern": { + "chance": 0.3 + }, + "alexscaves:flytrap": { + "chance": 0.65 + }, + "alexscaves:cycad": { + "chance": 0.65 + }, + "alexscaves:tree_star": { + "chance": 0.65 + }, + "alexscaves:archaic_vine": { + "chance": 0.5 + }, + "alexscaves:fern_thatch": { + "chance": 0.85 + }, + "alexscaves:underweed": { + "chance": 0.3 + }, + "alexscaves:thornwood_branch": { + "chance": 0.3 + }, + "alexscaves:thornwood_sapling": { + "chance": 0.3 + } + } +}