From 4a0a1a3a0427bcee70fe1005f3110807845c1649 Mon Sep 17 00:00:00 2001 From: James Date: Sun, 29 Sep 2024 13:29:48 -0700 Subject: [PATCH] not quite working yet but nothing broke --- .../wakes_compat/DynamicWakeSize.java | 14 ++ .../java/g_mungus/wakes_compat/ShipWake.java | 220 ++++++++++++++++++ src/main/java/g_mungus/wakes_compat/Util.java | 32 --- .../g_mungus/wakes_compat/VSWakesCompat.java | 47 +--- ...eMixin.java => ShipObjectClientMixin.java} | 39 +++- .../resources/vs-wakes-compat.mixins.json | 2 +- 6 files changed, 268 insertions(+), 86 deletions(-) create mode 100644 src/main/java/g_mungus/wakes_compat/DynamicWakeSize.java create mode 100644 src/main/java/g_mungus/wakes_compat/ShipWake.java rename src/main/java/g_mungus/wakes_compat/mixin/{ExampleMixin.java => ShipObjectClientMixin.java} (68%) diff --git a/src/main/java/g_mungus/wakes_compat/DynamicWakeSize.java b/src/main/java/g_mungus/wakes_compat/DynamicWakeSize.java new file mode 100644 index 0000000..12f6813 --- /dev/null +++ b/src/main/java/g_mungus/wakes_compat/DynamicWakeSize.java @@ -0,0 +1,14 @@ +package g_mungus.wakes_compat; + +import net.minecraft.util.math.Vec3d; + +public interface DynamicWakeSize { + + public float vs_wakes_compat_template_1_20_1$getWidth(); + + public void vs_wakes_compat_template_1_20_1$setWidth(float width); + + public Vec3d vs_wakes_compat_template_1_20_1$getPos(); + + public void vs_wakes_compat_template_1_20_1$setOffset(Vec3d pos); +} diff --git a/src/main/java/g_mungus/wakes_compat/ShipWake.java b/src/main/java/g_mungus/wakes_compat/ShipWake.java new file mode 100644 index 0000000..2f507eb --- /dev/null +++ b/src/main/java/g_mungus/wakes_compat/ShipWake.java @@ -0,0 +1,220 @@ +package g_mungus.wakes_compat; + +import com.goby56.wakes.WakesClient; +import com.goby56.wakes.duck.ProducesWake; +import com.goby56.wakes.simulation.WakeHandler; +import com.goby56.wakes.simulation.WakeNode; +import net.minecraft.client.MinecraftClient; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; +import net.minecraft.world.World; +import org.joml.Vector3d; +import org.joml.Vector3dc; +import org.joml.Vector3i; +import org.joml.primitives.AABBdc; +import org.joml.primitives.AABBic; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.core.api.world.LevelYRange; +import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import static g_mungus.wakes_compat.Util.approximateDirection; +import static g_mungus.wakes_compat.Util.getYaw; + +public class ShipWake { + + public static void placeWakeTrail(Ship ship) { + WakeHandler wakeHandler = WakeHandler.getInstance(); + if (wakeHandler != null) { + ProducesWake producer = (ProducesWake)ship; + double velocity = producer.getHorizontalVelocity(); + float height = producer.producingHeight(); + Iterator var7; + WakeNode node; + + Vec3d prevPos = producer.getPrevPos(); + + AABBdc aabb = ship.getWorldAABB(); + AABBic saabb = ship.getShipAABB(); + if (prevPos != null) { + assert saabb != null; + float xwidth = saabb.maxX() - saabb.minX(); + float zwidth = saabb.maxZ() - saabb.minZ(); + float width = Math.min(xwidth, zwidth); + + var7 = WakeNode.Factory.thickNodeTrail(prevPos.x, prevPos.z, (aabb.maxX() + aabb.minX())/2, (aabb.maxZ() + aabb.minZ())/2, height, (float) WakesClient.CONFIG_INSTANCE.initialStrength, velocity, width).iterator(); + + while(var7.hasNext()) { + node = (WakeNode)var7.next(); + wakeHandler.insert(node); + } + + } + } + } + + public static void checkShipSize(Ship s) { + + World world = MinecraftClient.getInstance().world; + + Vector3dc horizontalVelocity = new Vector3d(s.getVelocity().x(), 0, s.getVelocity().z()); + + if (horizontalVelocity.length() < 0.05) return; + + + double velAngle = horizontalVelocity.angleSigned(new Vector3d(0, 0, -1), new Vector3d(0, 1, 0)); + + + double shipAngle = getYaw(s.getTransform().getShipToWorldRotation()); + + + + Direction direction = approximateDirection(Math.toDegrees(velAngle - shipAngle)); + + Vec3d shipPos = Util.getCentre(s.getWorldAABB()); + + Double yLevelShip = VectorConversionsMCKt.toJOML(new Vec3d(shipPos.x, 62.9, shipPos.z)).mulPosition(s.getWorldToShip()).y; + + int blockYLevelShip = yLevelShip.intValue(); + + + Vector3i minWorldPos = new Vector3i(); + Vector3i maxWorldPos = new Vector3i(); + + // Rounding minY down to the nearest multiple of 16 + int minY = (blockYLevelShip / 16) * 16; + + // Rounding maxY up to the nearest multiple of 16, then subtracting 1 to get congruent to 15 + int maxY = ((blockYLevelShip / 16) * 16) + 15; + + + s.getActiveChunksSet().getMinMaxWorldPos(minWorldPos, maxWorldPos, new LevelYRange(minY, maxY)); + + float width = 0; + Vec3d offset; + + //floodfill stuff + + + offset = Vec3d.ZERO; + + ((DynamicWakeSize) s).vs_wakes_compat_template_1_20_1$setWidth(width); + ((DynamicWakeSize) s).vs_wakes_compat_template_1_20_1$setOffset(offset); + + + assert MinecraftClient.getInstance().player != null; + MinecraftClient.getInstance().player.sendMessage(Text.of(String.valueOf(minWorldPos) + String.valueOf(maxWorldPos))); + + } + + + // Helper method to calculate ship's width and offset + private static void calculateShipWidthAndOffset(World world, Vector3i minWorldPos, Vector3i maxWorldPos, + int blockYLevelShip, Direction direction, Ship s) { + // Axis variables to abstract x-axis or z-axis iterations + boolean isZAxis = (direction == Direction.NORTH || direction == Direction.SOUTH); + + int primaryMin = isZAxis ? minWorldPos.z() : minWorldPos.x(); // Min for the primary iteration axis + int primaryMax = isZAxis ? maxWorldPos.z() : maxWorldPos.x(); // Max for the primary iteration axis + int secondaryMin = isZAxis ? minWorldPos.x() : minWorldPos.z(); // Min for the secondary axis + int secondaryMax = isZAxis ? maxWorldPos.x() : maxWorldPos.z(); // Max for the secondary axis + boolean isNegativeDirection = (direction == Direction.NORTH || direction == Direction.WEST); // Reverse iteration? + + // Variables to track the row index and bounds + boolean foundFirstNonAirBlock = false; + int rowsChecked = 0; + + RowWithBlocks widestRow = null; + Vec3d boundsCenter = new Vec3d((minWorldPos.x() + maxWorldPos.x()) / 2.0, blockYLevelShip, + (minWorldPos.z() + maxWorldPos.z()) / 2.0); + + // Iterate based on primary axis (either x or z depending on direction) + for (int primary = isNegativeDirection ? primaryMax : primaryMin; + isNegativeDirection ? primary >= primaryMin : primary <= primaryMax; + primary += isNegativeDirection ? -1 : 1) { + + List blockPositions = new ArrayList<>(); + int minInRow = secondaryMax; + int maxInRow = secondaryMin; + boolean foundNonAirBlockInRow = false; + + // Iterate over the secondary axis (either z or x depending on direction) + for (int secondary = secondaryMin; secondary <= secondaryMax; secondary++) { + int x = isZAxis ? secondary : primary; // Set x for BlockPos + int z = isZAxis ? primary : secondary; // Set z for BlockPos + + if (!world.getBlockState(new BlockPos(x, blockYLevelShip, z)).isAir()) { + foundNonAirBlockInRow = true; + blockPositions.add(new BlockPos(x, blockYLevelShip, z)); + minInRow = Math.min(minInRow, secondary); + maxInRow = Math.max(maxInRow, secondary); + } + } + + if (foundNonAirBlockInRow) { + if (!foundFirstNonAirBlock) { + foundFirstNonAirBlock = true; + } + rowsChecked++; + + // Create a new RowWithBlocks instance for this row + RowWithBlocks currentRow = new RowWithBlocks(rowsChecked, blockPositions, minInRow, maxInRow, Util.getCentre((AABBdc) s.getShipAABB())); + + // Update widestRow if this row is wider + if (widestRow == null || currentRow.getWidth() > widestRow.getWidth()) { + widestRow = currentRow; + } + + // Stop after 5 rows checked + if (rowsChecked >= 5) break; + } + } + + // Use the widest row to calculate the final width and offset + if (widestRow != null) { + float width = widestRow.getWidth(); + Vec3d offset = widestRow.getOffset(); + + ((DynamicWakeSize) s).vs_wakes_compat_template_1_20_1$setWidth(width); + ((DynamicWakeSize) s).vs_wakes_compat_template_1_20_1$setOffset(offset); + + assert MinecraftClient.getInstance().player != null; + MinecraftClient.getInstance().player.sendMessage(Text.of("Width: " + width + ", Offset: " + offset)); + } else { + ((DynamicWakeSize) s).vs_wakes_compat_template_1_20_1$setWidth(0); + ((DynamicWakeSize) s).vs_wakes_compat_template_1_20_1$setOffset(Vec3d.ZERO); + } + } + + + + + private static class RowWithBlocks { + int index; + List blockPositions; + int width; + Vec3d offset; + + public RowWithBlocks(int index, List blockPositions, int minPos, int maxPos, Vec3d boundsCenter) { + this.index = index; + this.blockPositions = blockPositions; + this.width = maxPos - minPos; + // Offset is calculated as the center between min and max non-air blocks + this.offset = new Vec3d((minPos + maxPos) / 2.0, boundsCenter.y, boundsCenter.z); + } + + public int getWidth() { + return this.width; + } + + public Vec3d getOffset() { + return this.offset; + } + } +} diff --git a/src/main/java/g_mungus/wakes_compat/Util.java b/src/main/java/g_mungus/wakes_compat/Util.java index e9771f0..1e9a49f 100644 --- a/src/main/java/g_mungus/wakes_compat/Util.java +++ b/src/main/java/g_mungus/wakes_compat/Util.java @@ -18,36 +18,6 @@ public class Util { - public static void placeWakeTrail(Ship ship) { - WakeHandler wakeHandler = WakeHandler.getInstance(); - if (wakeHandler != null) { - ProducesWake producer = (ProducesWake)ship; - double velocity = producer.getHorizontalVelocity(); - float height = producer.producingHeight(); - Iterator var7; - WakeNode node; - - Vec3d prevPos = producer.getPrevPos(); - - AABBdc aabb = ship.getWorldAABB(); - AABBic saabb = ship.getShipAABB(); - if (prevPos != null) { - assert saabb != null; - float xwidth = saabb.maxX() - saabb.minX(); - float zwidth = saabb.maxZ() - saabb.minZ(); - float width = Math.min(xwidth, zwidth); - - var7 = WakeNode.Factory.thickNodeTrail(prevPos.x, prevPos.z, (aabb.maxX() + aabb.minX())/2, (aabb.maxZ() + aabb.minZ())/2, height, (float)WakesClient.CONFIG_INSTANCE.initialStrength, velocity, width).iterator(); - - while(var7.hasNext()) { - node = (WakeNode)var7.next(); - wakeHandler.insert(node); - } - - } - } - } - public static Vec3d getCentre (AABBdc aabb) { double centreX = (aabb.maxX() + aabb.minX())/2; double centreZ = (aabb.maxZ() + aabb.minZ())/2; @@ -56,13 +26,11 @@ public static Vec3d getCentre (AABBdc aabb) { public static double getYaw(Quaterniondc quaternion) { - // Extract the components of the quaternion double w = quaternion.w(); double x = quaternion.x(); double y = quaternion.y(); double z = quaternion.z(); - // Calculate yaw using atan2 return -Math.atan2(2.0 * (w * y + x * z), 1.0 - 2.0 * (y * y + z * z)); } diff --git a/src/main/java/g_mungus/wakes_compat/VSWakesCompat.java b/src/main/java/g_mungus/wakes_compat/VSWakesCompat.java index 8593962..9fc3b36 100644 --- a/src/main/java/g_mungus/wakes_compat/VSWakesCompat.java +++ b/src/main/java/g_mungus/wakes_compat/VSWakesCompat.java @@ -16,7 +16,6 @@ import org.slf4j.LoggerFactory; import org.valkyrienskies.core.api.ships.Ship; import org.valkyrienskies.core.api.world.LevelYRange; -import org.valkyrienskies.mod.common.VSClientGameUtils; import org.valkyrienskies.mod.common.VSGameUtilsKt; import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; @@ -54,12 +53,12 @@ private void onClientTick() { if (s != null) { if (shipSizeUpdaterCooldown == 0) { - checkShipSize(s); + ShipWake.checkShipSize(s); } - Util.placeWakeTrail(s); - ((ProducesWake)s).setPrevPos(Util.getCentre(s.getWorldAABB())); + ShipWake.placeWakeTrail(s); + ((ProducesWake)s).setPrevPos(((DynamicWakeSize)s).vs_wakes_compat_template_1_20_1$getPos()); } @@ -72,51 +71,11 @@ private void onClientTick() { } } - private int checkShipSize(Ship s) { - World world = MinecraftClient.getInstance().world; - Vector3dc horizontalVelocity = new Vector3d(s.getVelocity().x(), 0, s.getVelocity().z()); - if (horizontalVelocity.length() < 0.2) return -1; - double velAngle = horizontalVelocity.angleSigned(new Vector3d(0, 0, -1), new Vector3d(0, 1, 0)); - - - double shipAngle = getYaw(s.getTransform().getShipToWorldRotation()); - - - - Direction direction = approximateDirection(Math.toDegrees(velAngle - shipAngle)); - - Vec3d shipPos = Util.getCentre(s.getWorldAABB()); - - Double yLevelShip = VectorConversionsMCKt.toJOML(new Vec3d(shipPos.x, 62.9, shipPos.z)).mulPosition(s.getWorldToShip()).y; - - int blockYLevelShip = yLevelShip.intValue(); - - - Vector3i minWorldPos = new Vector3i(); - Vector3i maxWorldPos = new Vector3i(); - - // Rounding minY down to the nearest multiple of 16 - int minY = (blockYLevelShip / 16) * 16; - - // Rounding maxY up to the nearest multiple of 16, then subtracting 1 to get congruent to 15 - int maxY = ((blockYLevelShip / 16) * 16) + 15; - - - s.getActiveChunksSet().getMinMaxWorldPos(minWorldPos, maxWorldPos, new LevelYRange(minY, maxY)); - - - - assert MinecraftClient.getInstance().player != null; - MinecraftClient.getInstance().player.sendMessage(Text.of(String.valueOf(minWorldPos) + String.valueOf(maxWorldPos))); - - return 0; - } - } \ No newline at end of file diff --git a/src/main/java/g_mungus/wakes_compat/mixin/ExampleMixin.java b/src/main/java/g_mungus/wakes_compat/mixin/ShipObjectClientMixin.java similarity index 68% rename from src/main/java/g_mungus/wakes_compat/mixin/ExampleMixin.java rename to src/main/java/g_mungus/wakes_compat/mixin/ShipObjectClientMixin.java index 98a6cb2..077d3ef 100644 --- a/src/main/java/g_mungus/wakes_compat/mixin/ExampleMixin.java +++ b/src/main/java/g_mungus/wakes_compat/mixin/ShipObjectClientMixin.java @@ -2,27 +2,30 @@ import com.goby56.wakes.duck.ProducesWake; import com.goby56.wakes.particle.custom.SplashPlaneParticle; +import g_mungus.wakes_compat.DynamicWakeSize; import g_mungus.wakes_compat.Util; -import net.fabricmc.loader.impl.lib.sat4j.core.Vec; -import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.Vec3d; import org.joml.Vector3d; import org.joml.Vector3dc; 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.core.api.ships.Ship; import org.valkyrienskies.core.impl.game.ships.ShipObjectClient; import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; @Mixin(ShipObjectClient.class) -public abstract class ExampleMixin implements ProducesWake { +public abstract class ShipObjectClientMixin implements ProducesWake, DynamicWakeSize { + @Unique private Vec3d prevPosOnSurface; + @Unique + private float wakeWidth = 0; + + @Unique + private Vec3d offset = Vec3d.ZERO; + @Shadow public abstract Vector3dc getVelocity(); @Override @@ -40,12 +43,30 @@ public Vec3d getPrevPos() { return this.prevPosOnSurface == null ? null : new Vec3d(this.prevPosOnSurface.x, this.prevPosOnSurface.y, this.prevPosOnSurface.z); } - @Unique - public Vec3d getPos() { - return Util.getCentre(((Ship)(Object)this).getWorldAABB()); + @Override + public float vs_wakes_compat_template_1_20_1$getWidth() { + return this.wakeWidth; + } + + @Override + public void vs_wakes_compat_template_1_20_1$setWidth(float width) { + this.wakeWidth = width; + } + + @Override + public Vec3d vs_wakes_compat_template_1_20_1$getPos() { + Ship ship = (Ship)(Object)this; + return Util.getCentre(ship.getWorldAABB()).add(offset.rotateY((float) Util.getYaw(ship.getTransform().getShipToWorldRotation()))); } @Override + public void vs_wakes_compat_template_1_20_1$setOffset(Vec3d vec3d) { + this.offset = vec3d; + } + + + + @Override public void setPrevPos(Vec3d pos) { this.prevPosOnSurface = pos; } diff --git a/src/main/resources/vs-wakes-compat.mixins.json b/src/main/resources/vs-wakes-compat.mixins.json index 590a2b7..f1687d4 100644 --- a/src/main/resources/vs-wakes-compat.mixins.json +++ b/src/main/resources/vs-wakes-compat.mixins.json @@ -3,7 +3,7 @@ "package": "g_mungus.wakes_compat.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ - "ExampleMixin" + "ShipObjectClientMixin" ], "injectors": { "defaultRequire": 1