diff --git a/.circleci/config.yml b/.circleci/config.yml index 7ede9e82c..c3cb2f2b2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -118,7 +118,7 @@ jobs: - discord/status: success_message: ${DISCORD_MSG} success_only: true - webhook: ${VS2_118_WEBHOOK} + webhook: ${VS2_1192_WEBHOOK} # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows diff --git a/.github/workflows/build-1.18.x.yml b/.github/workflows/build.yml similarity index 98% rename from .github/workflows/build-1.18.x.yml rename to .github/workflows/build.yml index 92cbe7656..fbb07ea83 100644 --- a/.github/workflows/build-1.18.x.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,7 @@ on: push: branches: - '1.18.x/*' + - '1.19.2/*' pull_request: types: [ opened, synchronize, reopened ] jobs: diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/ValkyrienMixinErrorHandler.java b/common/src/main/java/org/valkyrienskies/mod/mixin/ValkyrienMixinErrorHandler.java index 52d011744..a5fa9a31d 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/ValkyrienMixinErrorHandler.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/ValkyrienMixinErrorHandler.java @@ -10,7 +10,9 @@ public class ValkyrienMixinErrorHandler implements IMixinErrorHandler { private final Set warnList = new HashSet<>(Arrays.asList( - "org.valkyrienskies.mod.mixin.feature.water_in_ships_entity.MixinEntity" + "org.valkyrienskies.mod.mixin.feature.water_in_ships_entity.MixinEntity", + "org.valkyrienskies.mod.mixin.mod_compat.create_big_cannons.MixinAbstractCannonProjectile", + "org.valkyrienskies.mod.mixin.mod_compat.create_big_cannons.MixinPitchOrientedContraptionEntity" )); @Override diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java b/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java index f82f1e084..d22a6a363 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java @@ -7,6 +7,7 @@ import net.minecraft.ReportedException; import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ClipContext; diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/fix_render_chunk_sorting/MixinRenderChunk.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/fix_render_chunk_sorting/MixinRenderChunk.java index 209c90e91..ba901c22d 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/fix_render_chunk_sorting/MixinRenderChunk.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/fix_render_chunk_sorting/MixinRenderChunk.java @@ -51,4 +51,17 @@ private void preGetSquaredCameraDistance(final CallbackInfoReturnable ci cir.setReturnValue(relDistanceSq); } } + + // This fixes ship blocks not rendering for some reason... + @Inject(method = "hasAllNeighbors", at = @At("HEAD"), cancellable = true) + private void preHasAllNeighbors(final CallbackInfoReturnable cir) { + final ClientLevel world = Minecraft.getInstance().level; + if (world == null) { + return; + } + + if (VSGameUtilsKt.isBlockInShipyard(world, origin)) { + cir.setReturnValue(true); + } + } } diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/sodium/MixinRegionChunkRenderer.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/sodium/MixinRegionChunkRenderer.java index a4dcc8298..18f2d1376 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/sodium/MixinRegionChunkRenderer.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/sodium/MixinRegionChunkRenderer.java @@ -18,7 +18,7 @@ import org.valkyrienskies.mod.common.VSGameUtilsKt; import org.valkyrienskies.mod.mixinducks.mod_compat.sodium.RegionChunkRendererDuck; -@Mixin(value = RegionChunkRenderer.class, remap = false) +@Mixin(value = RegionChunkRenderer.class, remap = false, priority = 1101) public class MixinRegionChunkRenderer implements RegionChunkRendererDuck { @Unique @@ -27,28 +27,29 @@ public class MixinRegionChunkRenderer implements RegionChunkRendererDuck { @Unique private final Vector3d camInShip = new Vector3d(); - @Redirect( + @WrapOperation( at = @At( value = "INVOKE", target = "Lme/jellysquid/mods/sodium/client/render/chunk/RenderSection;getBounds()Lme/jellysquid/mods/sodium/client/render/chunk/data/ChunkRenderBounds;" ), method = "buildDrawBatches" ) - private ChunkRenderBounds injectBuildDrawBatches(final RenderSection section, final List sections, - final BlockRenderPass pass, final ChunkCameraContext c) { - + private ChunkRenderBounds injectBuildDrawBatches( + final RenderSection section, final Operation getBounds, final List sections, + final BlockRenderPass pass, final ChunkCameraContext c + ) { final ClientShip ship = VSGameUtilsKt.getShipObjectManagingPos(Minecraft.getInstance().level, section.getChunkX(), section.getChunkZ()); if (ship != null) { ship.getRenderTransform().getWorldToShip().transformPosition(camInWorld, camInShip); - final ChunkRenderBounds originalBounds = section.getBounds(); + final ChunkRenderBounds originalBounds = getBounds.call(section); return new ChunkRenderBounds(originalBounds.x1 - 1.9f, originalBounds.y1 - 1.9f, originalBounds.z1 - 1.9f, originalBounds.x2 + 1.9f, originalBounds.y2 + 1.9f, originalBounds.z2 + 1.9f); } else { camInShip.set(camInWorld); - return section.getBounds(); + return getBounds.call(section); } } diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/sound_physics_remastered/MixinSoundPhysics.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/sound_physics_remastered/MixinSoundPhysics.java index de87e5605..cd1ef96fa 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/sound_physics_remastered/MixinSoundPhysics.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/sound_physics_remastered/MixinSoundPhysics.java @@ -13,7 +13,7 @@ import org.valkyrienskies.mod.common.VSGameUtilsKt; @Pseudo -@Mixin(targets = "com.sonicether.soundphysics.SoundPhysics") +@Mixin(targets = "com.sonicether.soundphysics.SoundPhysics", remap = false) public abstract class MixinSoundPhysics { @Shadow diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/server/world/MixinChunkMap.java b/common/src/main/java/org/valkyrienskies/mod/mixin/server/world/MixinChunkMap.java index 590b3c56d..982aac48e 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/server/world/MixinChunkMap.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/server/world/MixinChunkMap.java @@ -5,6 +5,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; @@ -32,6 +33,9 @@ public abstract class MixinChunkMap { @Final private Supplier overworldDataStorage; + @Shadow + protected abstract CompoundTag upgradeChunkTag(CompoundTag compoundTag); + /** * Force the game to generate empty chunks in the shipyard. * @@ -42,28 +46,28 @@ public abstract class MixinChunkMap { */ /* @Inject(method = "readChunk", at = @At("HEAD"), cancellable = true) - private void preReadChunk(final ChunkPos chunkPos, final CallbackInfoReturnable cir) - throws IOException { + private void preReadChunk(final ChunkPos chunkPos, + final CallbackInfoReturnable>> cir) { final ChunkMap self = ChunkMap.class.cast(this); - final CompoundTag compoundTag = self.read(chunkPos); - final CompoundTag originalToReturn = compoundTag == null ? null : - self.upgradeChunkTag(this.level.dimension(), this.overworldDataStorage, compoundTag, Optional.empty()); - cir.setReturnValue(originalToReturn); - if (originalToReturn == null) { - final ServerShip ship = VSGameUtilsKt.getShipManagingPos(level, chunkPos.x, chunkPos.z); - // If its in a ship and it shouldn't generate chunks OR if there is no ship but its happening in the shipyard - if ((ship == null && VSGameUtilsKt.isChunkInShipyard(level, chunkPos.x, chunkPos.z)) || - (ship != null && !ShipSettingsKt.getSettings(ship).getShouldGenerateChunks())) { - // The chunk doesn't yet exist and is in the shipyard. Make a new empty chunk - // Generate the chunk to be nothing - final LevelChunk generatedChunk = new LevelChunk(level, - new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, - level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null), null); - // Its wasteful to serialize just for this to be deserialized, but it will work for now. - cir.setReturnValue(ChunkSerializer.write(level, generatedChunk)); + cir.setReturnValue(self.read(chunkPos).thenApplyAsync(compoundTag -> { + if (compoundTag.isEmpty()) { + final ServerShip ship = VSGameUtilsKt.getShipManagingPos(level, chunkPos.x, chunkPos.z); + // If its in a ship and it shouldn't generate chunks OR if there is no ship but its happening in the shipyard + if ((ship == null && VSGameUtilsKt.isChunkInShipyard(level, chunkPos.x, chunkPos.z)) || + (ship != null && !ShipSettingsKt.getSettings(ship).getShouldGenerateChunks())) { + // The chunk doesn't yet exist and is in the shipyard. Make a new empty chunk + // Generate the chunk to be nothing + final LevelChunk generatedChunk = new LevelChunk(level, + new ProtoChunk(chunkPos, UpgradeData.EMPTY, level, + level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), null), null); + // Its wasteful to serialize just for this to be deserialized, but it will work for now. + return Optional.of(ChunkSerializer.write(level, generatedChunk)); + } } - } + return compoundTag.map(this::upgradeChunkTag); + })); + } */ diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/config/VSKeyBindings.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/config/VSKeyBindings.kt index d68efb214..609fcbbfa 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/config/VSKeyBindings.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/config/VSKeyBindings.kt @@ -33,4 +33,8 @@ object VSKeyBindings { fun clientSetup(registerar: Consumer) { toBeRegistered.forEach { it.accept(registerar) } } + + fun isKeyMappingFromVS2(keyMapping: KeyMapping): Boolean { + return keyMapping.name.startsWith("key.valkyrienskies") + } } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/item/ShipCreatorItem.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/item/ShipCreatorItem.kt index 95e0e8afe..c70884fef 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/item/ShipCreatorItem.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/item/ShipCreatorItem.kt @@ -2,6 +2,7 @@ package org.valkyrienskies.mod.common.item import net.minecraft.Util import net.minecraft.network.chat.Component +import net.minecraft.network.chat.Component import net.minecraft.server.level.ServerLevel import net.minecraft.world.InteractionResult import net.minecraft.world.item.Item diff --git a/common/src/main/resources/valkyrienskies-common.mixins.json b/common/src/main/resources/valkyrienskies-common.mixins.json index ed62d8488..d91a6d85b 100644 --- a/common/src/main/resources/valkyrienskies-common.mixins.json +++ b/common/src/main/resources/valkyrienskies-common.mixins.json @@ -48,7 +48,6 @@ "feature.shipyard_entities.MixinTransientEntitySectionManager", "feature.spawn_player_on_ship.MixinServerGamePacketListenerImpl", "feature.tick_ship_chunks.MixinChunkMap", - "feature.water_in_ships_entity.MixinEntity", "feature.world_border.MixinLevel", "feature.world_border.MixinWorldBorder", "mod_compat.create.IMixinDeployerHandler", diff --git a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/client/render/MixinLevelRenderer.java b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/client/render/MixinLevelRenderer.java new file mode 100644 index 000000000..8bb3bdc91 --- /dev/null +++ b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/client/render/MixinLevelRenderer.java @@ -0,0 +1,77 @@ +package org.valkyrienskies.mod.fabric.mixin.client.render; + +import static org.valkyrienskies.mod.common.VSClientGameUtils.transformRenderWithShip; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.valkyrienskies.core.api.ships.ClientShip; +import org.valkyrienskies.core.api.ships.properties.ShipTransform; +import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.mixin.accessors.client.render.OverlayVertexConsumerAccessor; + +@Mixin(LevelRenderer.class) +public abstract class MixinLevelRenderer { + @Shadow + private ClientLevel level; + + /** + * This mixin makes block damage render on ships. + */ + @WrapOperation(method = "renderLevel", at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/renderer/block/BlockRenderDispatcher;renderBreakingTexture(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/BlockAndTintGetter;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;)V")) + private void renderBlockDamage(final BlockRenderDispatcher blockRenderManager, final BlockState state, + final BlockPos blockPos, final BlockAndTintGetter blockRenderWorld, final PoseStack matrix, + final VertexConsumer vertexConsumer, final Operation renderBreakingTexture, final PoseStack matrixStack, + final float methodTickDelta, final long methodLimitTime, final boolean methodRenderBlockOutline, + final Camera methodCamera, final GameRenderer methodGameRenderer, + final LightTexture methodLightmapTextureManager, final Matrix4f methodMatrix4f) { + + final ClientShip ship = VSGameUtilsKt.getShipObjectManagingPos(level, blockPos); + if (ship != null) { + // Remove the vanilla render transform + matrixStack.popPose(); + + // Add the VS render transform + matrixStack.pushPose(); + + final ShipTransform renderTransform = ship.getRenderTransform(); + final Vec3 cameraPos = methodCamera.getPosition(); + + transformRenderWithShip(renderTransform, matrixStack, blockPos, cameraPos.x, cameraPos.y, cameraPos.z); + + final Matrix3f newNormalMatrix = matrixStack.last().normal().copy(); + final Matrix4f newModelMatrix = matrixStack.last().pose().copy(); + + // Then update the matrices in vertexConsumer (I'm guessing vertexConsumer is responsible for mapping + // textures, so we need to update its matrices otherwise the block damage texture looks wrong) + final SheetedDecalTextureGenerator newVertexConsumer = + new SheetedDecalTextureGenerator(((OverlayVertexConsumerAccessor) vertexConsumer).getDelegate(), + newModelMatrix, newNormalMatrix); + + // Finally, invoke the render damage function. + renderBreakingTexture.call(blockRenderManager, state, blockPos, blockRenderWorld, matrix, + newVertexConsumer); + } else { + // Vanilla behavior + renderBreakingTexture.call(blockRenderManager, state, blockPos, blockRenderWorld, matrix, vertexConsumer); + } + } +} diff --git a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/feature/duplicate_keybindings/KeyMappingAccessor.java b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/feature/duplicate_keybindings/KeyMappingAccessor.java new file mode 100644 index 000000000..41b94b6a6 --- /dev/null +++ b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/feature/duplicate_keybindings/KeyMappingAccessor.java @@ -0,0 +1,18 @@ +package org.valkyrienskies.mod.fabric.mixin.feature.duplicate_keybindings; + +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.client.KeyMapping; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(KeyMapping.class) +public interface KeyMappingAccessor { + @Accessor + InputConstants.Key getKey(); + + @Accessor + int getClickCount(); + + @Accessor + void setClickCount(int clickCount); +} diff --git a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/feature/duplicate_keybindings/MixinKeyMapping.java b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/feature/duplicate_keybindings/MixinKeyMapping.java new file mode 100644 index 000000000..3e20fe9f9 --- /dev/null +++ b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/feature/duplicate_keybindings/MixinKeyMapping.java @@ -0,0 +1,74 @@ +package org.valkyrienskies.mod.fabric.mixin.feature.duplicate_keybindings; + +import com.google.common.collect.Maps; +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.platform.InputConstants.Key; +import java.util.Map; +import net.minecraft.client.KeyMapping; +import org.spongepowered.asm.mixin.Final; +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.valkyrienskies.mod.common.config.VSKeyBindings; + +/** + * This Mixin makes it so VS2 keybindings are pressed even when there exists another keybinding bound to the set same + * key. + */ +@Mixin(KeyMapping.class) +public class MixinKeyMapping { + @Unique + private static final Map VS2_KEYMAP = Maps.newHashMap(); + + @Shadow + @Final + private static Map MAP; + + @Shadow + @Final + private static Map ALL; + + @Shadow + private InputConstants.Key key; + + @Inject(method = "click", at = @At("HEAD")) + private static void preClick(final InputConstants.Key key, final CallbackInfo callbackInfo) { + final KeyMapping originalKeyMapping = MAP.get(key); + final KeyMapping vs2KeyMapping = VS2_KEYMAP.get(key); + if (vs2KeyMapping != null && originalKeyMapping != vs2KeyMapping) { + final KeyMappingAccessor keyMappingAccessor = (KeyMappingAccessor) vs2KeyMapping; + keyMappingAccessor.setClickCount(keyMappingAccessor.getClickCount() + 1); + } + } + + @Inject(method = "set", at = @At("HEAD")) + private static void preSet(final InputConstants.Key key, final boolean bl, final CallbackInfo callbackInfo) { + final KeyMapping originalKeyMapping = MAP.get(key); + final KeyMapping vs2KeyMapping = VS2_KEYMAP.get(key); + if (vs2KeyMapping != null && originalKeyMapping != vs2KeyMapping) { + vs2KeyMapping.setDown(bl); + } + } + + @Inject(method = "resetMapping", at = @At("HEAD")) + private static void preResetMapping(final CallbackInfo callbackInfo) { + VS2_KEYMAP.clear(); + for (final KeyMapping keyMapping : ALL.values()) { + if (VSKeyBindings.INSTANCE.isKeyMappingFromVS2(keyMapping)) { + final KeyMappingAccessor keyMappingAccessor = (KeyMappingAccessor) keyMapping; + VS2_KEYMAP.put(keyMappingAccessor.getKey(), keyMapping); + } + } + } + + @Inject(method = "", at = @At("RETURN"), remap = false) + private void postInit(final CallbackInfo callbackInfo) { + final KeyMapping thisAsKeyMapping = KeyMapping.class.cast(this); + if (VSKeyBindings.INSTANCE.isKeyMappingFromVS2(thisAsKeyMapping)) { + VS2_KEYMAP.put(this.key, thisAsKeyMapping); + } + } +} diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/water_in_ships_entity/MixinEntity.java b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/feature/water_in_ships_entity/MixinEntity.java similarity index 98% rename from common/src/main/java/org/valkyrienskies/mod/mixin/feature/water_in_ships_entity/MixinEntity.java rename to fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/feature/water_in_ships_entity/MixinEntity.java index ecc3f5b40..a54f535e1 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/water_in_ships_entity/MixinEntity.java +++ b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/feature/water_in_ships_entity/MixinEntity.java @@ -1,4 +1,4 @@ -package org.valkyrienskies.mod.mixin.feature.water_in_ships_entity; +package org.valkyrienskies.mod.fabric.mixin.feature.water_in_ships_entity; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; diff --git a/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/common/ValkyrienSkiesModFabric.kt b/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/common/ValkyrienSkiesModFabric.kt index 13e5b2914..b18d6318e 100644 --- a/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/common/ValkyrienSkiesModFabric.kt +++ b/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/common/ValkyrienSkiesModFabric.kt @@ -143,7 +143,7 @@ class ValkyrienSkiesModFabric : ModInitializer { ValkyrienSkiesMod.TEST_HINGE_BLOCK_ENTITY_TYPE ) - CommandRegistrationCallback.EVENT.register { dispatcher ,d, _ -> + CommandRegistrationCallback.EVENT.register { dispatcher, _, _ -> VSCommands.registerServerCommands(dispatcher) } diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 186e340e3..48ad3da8f 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -29,8 +29,8 @@ ], "accessWidener": "valkyrienskies-common.accesswidener", "depends": { - "fabricloader": ">=0.14.6", - "minecraft": ">=1.18.2", + "fabricloader": ">=0.14.9", + "minecraft": "1.19.2", "fabric": "*" }, "breaks": { diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/client/render/MixinLevelRenderer.java b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/client/render/MixinLevelRenderer.java index 304e0c108..d7f3579d3 100644 --- a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/client/render/MixinLevelRenderer.java +++ b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/client/render/MixinLevelRenderer.java @@ -1,14 +1,40 @@ package org.valkyrienskies.mod.forge.mixin.client.render; +import static org.valkyrienskies.mod.common.VSClientGameUtils.transformRenderWithShip; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Matrix3f; +import com.mojang.math.Matrix4f; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.block.BlockRenderDispatcher; import net.minecraft.client.renderer.culling.Frustum; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.client.model.data.ModelData; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; +import org.valkyrienskies.core.api.ships.ClientShip; +import org.valkyrienskies.core.api.ships.properties.ShipTransform; +import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.mixin.accessors.client.render.OverlayVertexConsumerAccessor; @Mixin(LevelRenderer.class) public class MixinLevelRenderer { + @Shadow + private ClientLevel level; @Redirect(method = "renderLevel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/culling/Frustum;isVisible(Lnet/minecraft/world/phys/AABB;)Z")) @@ -16,4 +42,46 @@ public boolean dontClipTileEntities(final Frustum receiver, final AABB aabb) { return true; } + /** + * This mixin makes block damage render on ships. + */ + @WrapOperation(method = "renderLevel", at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/renderer/block/BlockRenderDispatcher;renderBreakingTexture(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/BlockAndTintGetter;Lcom/mojang/blaze3d/vertex/PoseStack;Lcom/mojang/blaze3d/vertex/VertexConsumer;Lnet/minecraftforge/client/model/data/ModelData;)V")) + private void renderBlockDamage(final BlockRenderDispatcher blockRenderManager, final BlockState state, + final BlockPos blockPos, final BlockAndTintGetter blockRenderWorld, final PoseStack matrix, + final VertexConsumer vertexConsumer, final ModelData modelData, final Operation renderBreakingTexture, final PoseStack matrixStack, + final float methodTickDelta, final long methodLimitTime, final boolean methodRenderBlockOutline, + final Camera methodCamera, final GameRenderer methodGameRenderer, + final LightTexture methodLightmapTextureManager, final Matrix4f methodMatrix4f) { + + final ClientShip ship = VSGameUtilsKt.getShipObjectManagingPos(level, blockPos); + if (ship != null) { + // Remove the vanilla render transform + matrixStack.popPose(); + + // Add the VS render transform + matrixStack.pushPose(); + + final ShipTransform renderTransform = ship.getRenderTransform(); + final Vec3 cameraPos = methodCamera.getPosition(); + + transformRenderWithShip(renderTransform, matrixStack, blockPos, cameraPos.x, cameraPos.y, cameraPos.z); + + final Matrix3f newNormalMatrix = matrixStack.last().normal().copy(); + final Matrix4f newModelMatrix = matrixStack.last().pose().copy(); + + // Then update the matrices in vertexConsumer (I'm guessing vertexConsumer is responsible for mapping + // textures, so we need to update its matrices otherwise the block damage texture looks wrong) + final SheetedDecalTextureGenerator newVertexConsumer = + new SheetedDecalTextureGenerator(((OverlayVertexConsumerAccessor) vertexConsumer).getDelegate(), + newModelMatrix, newNormalMatrix); + + // Finally, invoke the render damage function. + renderBreakingTexture.call(blockRenderManager, state, blockPos, blockRenderWorld, matrix, + newVertexConsumer, modelData); + } else { + // Vanilla behavior + renderBreakingTexture.call(blockRenderManager, state, blockPos, blockRenderWorld, matrix, vertexConsumer, modelData); + } + } } diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/feature/water_in_ships_entity/MixinEntity.java b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/feature/water_in_ships_entity/MixinEntity.java new file mode 100644 index 000000000..70d1f439b --- /dev/null +++ b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/feature/water_in_ships_entity/MixinEntity.java @@ -0,0 +1,181 @@ +package org.valkyrienskies.mod.forge.mixin.feature.water_in_ships_entity; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.extensions.IForgeEntity; +import net.minecraftforge.fluids.FluidType; +import org.apache.commons.lang3.tuple.MutableTriple; +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.valkyrienskies.mod.common.VSGameUtilsKt; + +@Mixin(Entity.class) +public abstract class MixinEntity { + @Shadow + public Level level; + @Shadow + private AABB bb; + + @Shadow + public abstract double getEyeY(); + + @Shadow + public abstract double getX(); + + @Shadow + public abstract double getZ(); + + @Shadow + public abstract boolean touchingUnloadedChunk(); + + @Shadow + public abstract AABB getBoundingBox(); + + @Shadow + public abstract boolean isPushedByFluid(); + + @Shadow + public abstract Vec3 getDeltaMovement(); + + @Shadow + public abstract void setDeltaMovement(Vec3 vec3); + + @Unique + private boolean isShipWater = false; + + @Shadow + protected abstract void setFluidTypeHeight(FluidType type, double height); + + @Inject( + at = @At("HEAD"), + method = "updateFluidHeightAndDoFluidPushing()V", + remap = false + ) + // Overwrite the forge method, since it's written in a way that's really hard to precisely mixin into. + private void afterFluidStateUpdate(final CallbackInfo callbackInfo) { + if (this.touchingUnloadedChunk()) { + return; + } + VSGameUtilsKt.transformFromWorldToNearbyShipsAndWorld(level, this.getBoundingBox().deflate(0.001), aabb -> { + int i = Mth.floor(aabb.minX); + int j = Mth.ceil(aabb.maxX); + int k = Mth.floor(aabb.minY); + int l = Mth.ceil(aabb.maxY); + int i1 = Mth.floor(aabb.minZ); + int j1 = Mth.ceil(aabb.maxZ); + double d0 = 0.0; + boolean flag = this.isPushedByFluid(); + boolean flag1 = false; + Vec3 vec3 = Vec3.ZERO; + boolean k1 = false; + BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(); + Object2ObjectArrayMap + interimCalcs = new Object2ObjectArrayMap((Integer) FluidType.SIZE.get() - 1); + for (int l1 = i; l1 < j; ++l1) { + for (int i2 = k; i2 < l; ++i2) { + for (int j2 = i1; j2 < j1; ++j2) { + double d1; + blockpos$mutableblockpos.set(l1, i2, j2); + FluidState fluidstate = this.level.getFluidState(blockpos$mutableblockpos); + FluidType fluidType2 = fluidstate.getFluidType(); + if (fluidType2.isAir() || !((d1 = + (double) ((float) i2 + fluidstate.getHeight(this.level, blockpos$mutableblockpos))) >= + aabb.minY)) continue; + flag1 = true; + MutableTriple interim2 = + interimCalcs.computeIfAbsent(fluidType2, t -> MutableTriple.of(0.0, Vec3.ZERO, 0)); + interim2.setLeft(Math.max(d1 - aabb.minY, (Double) interim2.getLeft())); + if (!((IForgeEntity) this).isPushedByFluid(fluidType2)) continue; + Vec3 vec31 = fluidstate.getFlow(this.level, blockpos$mutableblockpos); + if ((Double) interim2.getLeft() < 0.4) { + vec31 = vec31.scale((Double) interim2.getLeft()); + } + interim2.setMiddle(((Vec3) interim2.getMiddle()).add(vec31)); + interim2.setRight((Integer) interim2.getRight() + 1); + } + } + } + interimCalcs.forEach((fluidType, interim) -> { + if (((Vec3) interim.getMiddle()).length() > 0.0) { + if ((Integer) interim.getRight() > 0) { + interim.setMiddle(((Vec3) interim.getMiddle()).scale( + 1.0 / (double) ((Integer) interim.getRight()).intValue())); + } + if (!Player.class.isInstance(this)) { + interim.setMiddle(((Vec3) interim.getMiddle()).normalize()); + } + Vec3 vec32 = this.getDeltaMovement(); + interim.setMiddle(((Vec3) interim.getMiddle()).scale( + ((IForgeEntity) this).getFluidMotionScale((FluidType) fluidType))); + double d2 = 0.003; + if (Math.abs(vec32.x) < 0.003 && Math.abs(vec32.z) < 0.003 && + ((Vec3) interim.getMiddle()).length() < 0.0045000000000000005) { + interim.setMiddle(((Vec3) interim.getMiddle()).normalize().scale(0.0045000000000000005)); + } + this.setDeltaMovement(this.getDeltaMovement().add((Vec3) interim.getMiddle())); + } + this.setFluidTypeHeight((FluidType) fluidType, (Double) interim.getLeft()); + }); + }); + } + + @WrapOperation( + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/level/Level;getFluidState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/material/FluidState;"), + method = "updateFluidOnEyes" + ) + private FluidState getFluidStateRedirect(final Level level, final BlockPos blockPos, + final Operation getFluidState) { + final FluidState[] fluidState = {getFluidState.call(level, blockPos)}; + isShipWater = false; + if (fluidState[0].isEmpty()) { + + final double d = this.getEyeY() - 0.1111111119389534; + + final double origX = this.getX(); + final double origY = d; + final double origZ = this.getZ(); + + VSGameUtilsKt.transformToNearbyShipsAndWorld(this.level, origX, origY, origZ, this.bb.getSize(), + (x, y, z) -> { + fluidState[0] = getFluidState.call(level, new BlockPos(x, y, z)); + }); + isShipWater = true; + } + return fluidState[0]; + } + + @WrapOperation( + at = @At(value = "INVOKE", + target = "Lnet/minecraft/world/level/material/FluidState;getHeight(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)F"), + method = "updateFluidOnEyes" + ) + private float fluidHeightOverride(final FluidState instance, final BlockGetter arg, final BlockPos arg2, + final Operation getHeight) { + if (!instance.isEmpty() && this.level instanceof Level) { + + if (isShipWater) { + if (instance.isSource()) { + return 1; + } + } + + } + return getHeight.call(instance, arg, arg2); + } + +} diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/world/level/block/FireMixin.java b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/world/level/block/FireMixin.java index 97b70494c..aed12e5ae 100644 --- a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/world/level/block/FireMixin.java +++ b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/world/level/block/FireMixin.java @@ -1,6 +1,5 @@ package org.valkyrienskies.mod.forge.mixin.world.level.block; -import java.util.Random; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml index d66740e54..ecd097609 100644 --- a/forge/src/main/resources/META-INF/mods.toml +++ b/forge/src/main/resources/META-INF/mods.toml @@ -23,6 +23,6 @@ side = "BOTH" [[dependencies.valkyrienskies]] modId = "minecraft" mandatory = true -versionRange = "[1.18.2,)" +versionRange = "[1.19.2]" ordering = "NONE" side = "BOTH" diff --git a/forge/src/main/resources/valkyrienskies-forge.mixins.json b/forge/src/main/resources/valkyrienskies-forge.mixins.json index 647a06f8d..34deb5e14 100644 --- a/forge/src/main/resources/valkyrienskies-forge.mixins.json +++ b/forge/src/main/resources/valkyrienskies-forge.mixins.json @@ -14,6 +14,7 @@ "compat.thermalexpansion.MixinTileCoFH", "compat.tis3d.MixinInfraredPacketEntity", "feature.forge_interact.MixinIForgePlayer", + "feature.water_in_ships_entity.MixinEntity", "world.level.block.FireMixin" ], "client": [