diff --git a/build.gradle b/build.gradle index b3da12d7f..c270bce7a 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ plugins { id "dev.architectury.loom" version "1.3.355" apply false id 'io.github.juuxel.loom-vineflower' version '1.11.0' apply false // Kotlin - id "org.jetbrains.kotlin.jvm" version "1.9.10" apply false + id "org.jetbrains.kotlin.jvm" version "2.1.0" apply false id 'com.matthewprenger.cursegradle' version '1.4.0' apply false id "com.modrinth.minotaur" version "2.4.3" apply false } @@ -70,20 +70,25 @@ subprojects { apply plugin: "org.jetbrains.kotlin.jvm" apply plugin: "io.github.juuxel.loom-vineflower" - configurations.each { it.resolutionStrategy.useGlobalDependencySubstitutionRules.set(false) } - repositories { try { def vsCoreBuild = gradle.includedBuild("vs-core") - mavenLocal { - content { - includeGroup("org.valkyrienskies.core") + + tasks.register('removeIncludedClasses') { + // IntelliJ bug: IntelliJ always adds the build/classes folder in composite builds to the classpath, + // even though we want the shadowJar stuff on the classpath rather than build/classes + // + // To fix this, we just delete it. Very reliable and supported and not cursed at all. + doLast { + new File(vsCoreBuild.projectDir, "build/classes").deleteDir() } } - [':impl', ':api', ':api-game'].each { - compileJava.dependsOn(vsCoreBuild.task("${it}:publishToMavenLocal")) + tasks.named('classes') { + finalizedBy tasks.named('removeIncludedClasses') + dependsOn vsCoreBuild.task(":shadowJar") } + } catch (UnknownDomainObjectException ignore) {} mavenCentral() @@ -114,6 +119,20 @@ subprojects { maven { url = "https://maven.cafeteria.dev/releases" } // Fake Player API maven { url = "https://maven.jamieswhiteshirt.com/libs-release" } // Reach Entity Attributes maven { url = "https://jitpack.io"} + maven { // FTB Stuffs + url "https://maven.saps.dev/releases" + content { + includeGroup "dev.latvian.mods" + includeGroup "dev.ftb.mods" + } + } + maven { // FTB Stuffs + url "https://maven.saps.dev/snapshots" + content { + includeGroup "dev.latvian.mods" + includeGroup "dev.ftb.mods" + } + } } maven { name = "Valkyrien Skies Internal" diff --git a/common/build.gradle b/common/build.gradle index e8e216ed8..0167058c0 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,4 +1,3 @@ - dependencies { implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:0.2.0")) @@ -11,19 +10,26 @@ dependencies { modCompileOnly("maven.modrinth:sodium:${sodium_version}") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.0") + // vs-core implementation("org.valkyrienskies.core:impl:${rootProject.vs_core_version}") { exclude module: "netty-buffer" exclude module: "fastutil" + exclude module: "kotlin-stdlib" + } + implementation("org.valkyrienskies.core:api:${rootProject.vs_core_version}") { + exclude module: "kotlin-stdlib" + } + implementation("org.valkyrienskies.core:api-game:${rootProject.vs_core_version}") { + exclude module: "kotlin-stdlib" + } + implementation("org.valkyrienskies.core:util:${rootProject.vs_core_version}") { + exclude module: "kotlin-stdlib" } - implementation("org.valkyrienskies.core:api:${rootProject.vs_core_version}") - implementation("org.valkyrienskies.core:api-game:${rootProject.vs_core_version}") - implementation("org.valkyrienskies.core:util:${rootProject.vs_core_version}") // FTB Stuffs - modCompileOnly("curse.maven:ftb-util-404465:4210935") - modCompileOnly("curse.maven:ftb-teams-404468:4229138") - modCompileOnly("curse.maven:ftb-chunks-314906:4229120") + modCompileOnly("dev.ftb.mods:ftb-chunks:2001.3.4") { transitive = false } // EMF compat modCompileOnly("curse.maven:entity-model-features-844662:5696901") @@ -32,6 +38,9 @@ dependencies { // Weather2 1.20.1 modCompileOnly("curse.maven:weather-storms-tornadoes-237746:5244118") + // CC: Tweaked + modCompileOnly("maven.modrinth:cc-tweaked:${cc_tweaked_version}") + //Common create compat, //We just use a version from a platform and hope the classes exist on both versions and mixins apply correctly modCompileOnly("com.simibubi.create:create-fabric-${minecraft_version}:${create_fabric_version}") diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/conduit_fix/ConduitMixin.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/conduit_fix/ConduitMixin.java index a3306db6f..752cfd7d6 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/conduit_fix/ConduitMixin.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/conduit_fix/ConduitMixin.java @@ -11,7 +11,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.api.ValkyrienSkies; @Mixin(ConduitBlockEntity.class) public class ConduitMixin extends BlockEntity { @@ -31,12 +31,7 @@ public ConduitMixin(final BlockEntityType blockEntityType, final BlockPos blo ) private static boolean closerThan(final BlockPos instance, final Vec3i vec3i, final double distance, final Level level, final BlockPos blockPos, final List list) { - final double retValue = - VSGameUtilsKt.squaredDistanceBetweenInclShips(level, instance.getX(), instance.getY(), instance.getZ(), - vec3i.getX(), - vec3i.getY(), - vec3i.getZ()); - return retValue < distance * distance; + return ValkyrienSkies.closerThan(level, instance, vec3i, distance); } @Redirect( diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/explosions/MixinExplosion.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/explosions/MixinExplosion.java index ad96562bc..6c3f1a359 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/explosions/MixinExplosion.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/explosions/MixinExplosion.java @@ -23,7 +23,7 @@ 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.ServerShip; +import org.valkyrienskies.core.api.ships.LoadedServerShip; import org.valkyrienskies.mod.common.VSGameUtilsKt; import org.valkyrienskies.mod.common.config.VSGameConfig; import org.valkyrienskies.mod.common.util.GameTickForceApplier; @@ -74,8 +74,8 @@ private void doExplodeForce() { ClipContext.Fluid.NONE, null)); if (result.getType() == Type.BLOCK) { final BlockPos blockPos = result.getBlockPos(); - final ServerShip ship = - (ServerShip) VSGameUtilsKt.getShipObjectManagingPos(this.level, blockPos); + final LoadedServerShip ship = + (LoadedServerShip) VSGameUtilsKt.getShipObjectManagingPos(this.level, blockPos); if (ship != null) { final Vector3d forceVector = VectorConversionsMCKt.toJOML( diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/huge_bounding_box_fix/MixinPlayer.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/huge_bounding_box_fix/MixinPlayer.java index 70ff794f8..e1ab355e3 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/huge_bounding_box_fix/MixinPlayer.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/huge_bounding_box_fix/MixinPlayer.java @@ -8,7 +8,7 @@ import net.minecraft.world.phys.AABB; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.api.ValkyrienSkies; /** * Transform the player's vehicle's bounding box to the shipyard, preventing the 'collision box too big' error. @@ -29,6 +29,6 @@ protected MixinPlayer(final EntityType entityType, ) ) private AABB transformBoundingBoxToWorld(final AABB aabb) { - return VSGameUtilsKt.transformAabbToWorld(this.level(), aabb); + return ValkyrienSkies.toWorld(this.level(), aabb); } } diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/mob_spawning/NaturalSpawnerMixin.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/mob_spawning/NaturalSpawnerMixin.java index 93b07c491..0b3acc903 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/mob_spawning/NaturalSpawnerMixin.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/mob_spawning/NaturalSpawnerMixin.java @@ -8,7 +8,7 @@ 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; +import org.valkyrienskies.mod.api.ValkyrienSkies; import org.valkyrienskies.mod.common.config.VSGameConfig; @Mixin(NaturalSpawner.class) @@ -18,7 +18,7 @@ public class NaturalSpawnerMixin { private static void determineSpawningOnShips(final ServerLevel level, final LevelChunk chunk, final SpawnState spawnState, final boolean spawnFriendlies, final boolean spawnMonsters, final boolean bl, final CallbackInfo ci) { - if (VSGameUtilsKt.isChunkInShipyard(level, chunk.getPos().x, chunk.getPos().z)) { + if (ValkyrienSkies.isChunkInShipyard(level, chunk.getPos().x, chunk.getPos().z)) { if (!VSGameConfig.SERVER.getAllowMobSpawns()) { ci.cancel(); } diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/render_blockentity_distance_check/MixinBlockEntityRenderDispatcher.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/render_blockentity_distance_check/MixinBlockEntityRenderDispatcher.java index b57119725..634856a50 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/render_blockentity_distance_check/MixinBlockEntityRenderDispatcher.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/render_blockentity_distance_check/MixinBlockEntityRenderDispatcher.java @@ -15,7 +15,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.valkyrienskies.core.api.ships.ClientShip; import org.valkyrienskies.core.api.ships.Ship; -import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.api.ValkyrienSkies; /** * This mixin fixes {@link BlockEntity}s belonging to ships not rendering. @@ -48,7 +48,7 @@ private boolean isTileEntityInRenderRange(final BlockEnt // If by default was false, then check if this BlockEntity belongs to a ship final BlockPos bePos = blockEntity.getBlockPos(); - final Ship nullableShip = VSGameUtilsKt.getShipObjectManagingPos(level, bePos); + final Ship nullableShip = ValkyrienSkies.getShipManagingBlock(level, bePos); if (nullableShip instanceof ClientShip ship) { final Matrix4dc m = ship.getRenderTransform().getShipToWorld(); diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/save_mob_location_on_ship/MixinChunkMap.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/save_mob_location_on_ship/MixinChunkMap.java index e73bf5fe1..1ce6eee0e 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/save_mob_location_on_ship/MixinChunkMap.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/save_mob_location_on_ship/MixinChunkMap.java @@ -13,12 +13,11 @@ 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.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.api.ValkyrienSkies; import org.valkyrienskies.mod.common.config.VSGameConfig; import org.valkyrienskies.mod.common.entity.ShipyardPosSavable; import org.valkyrienskies.mod.common.util.EntityDraggingInformation; import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider; -import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; @Mixin(ChunkMap.class) public class MixinChunkMap { @@ -35,12 +34,13 @@ public class MixinChunkMap { @Inject(method = "removeEntity", at = @At("HEAD")) protected void unloadEntityMixin(Entity entity, CallbackInfo info) { - if (entity instanceof Mob mob) { + if (entity instanceof Mob mob && entity instanceof ShipyardPosSavable savable) { Vector3d shipyardPos = valkyrienskies$getShipyardPos(mob); if (shipyardPos != null && - VSGameUtilsKt.getShipManagingPos(this.level, shipyardPos) != null && - ((ShipyardPosSavable)mob).valkyrienskies$getUnloadedShipyardPos() == null) { - ((ShipyardPosSavable)mob).valkyrienskies$setUnloadedShipyardPos(shipyardPos); + ValkyrienSkies.getShipManagingBlock(this.level, shipyardPos) != null && + savable.valkyrienskies$getUnloadedShipyardPos() == null + ) { + savable.valkyrienskies$setUnloadedShipyardPos(shipyardPos); } } } @@ -53,13 +53,13 @@ protected void unloadEntityMixin(Entity entity, CallbackInfo info) { @Inject(method = "addEntity", at = @At("RETURN")) protected void loadEntityMixin(Entity entity, CallbackInfo info) { - if (entity instanceof Mob mob) { - Vector3d shipyardPos = ((ShipyardPosSavable)mob).valkyrienskies$getUnloadedShipyardPos(); - if(shipyardPos != null) { + if (entity instanceof Mob mob && entity instanceof ShipyardPosSavable savable) { + Vector3d shipyardPos = savable.valkyrienskies$getUnloadedShipyardPos(); + if (shipyardPos != null) { if (VSGameConfig.SERVER.getSaveMobsPositionOnShip()){ mob.teleportTo(shipyardPos.x, shipyardPos.y, shipyardPos.z); } - ((ShipyardPosSavable) mob).valkyrienskies$setUnloadedShipyardPos(null); + savable.valkyrienskies$setUnloadedShipyardPos(null); } } } @@ -75,9 +75,9 @@ protected void loadEntityMixin(Entity entity, CallbackInfo info) { EntityDraggingInformation dragInfo = ((IEntityDraggingInformationProvider) entity).getDraggingInformation(); if (dragInfo.getLastShipStoodOn() != null) { - Ship ship = VSGameUtilsKt.getAllShips(this.level).getById(dragInfo.getLastShipStoodOn()); - if (ship != null && ship.getWorldAABB().containsPoint(VectorConversionsMCKt.toJOML(entity.position()))) { - return ship.getWorldToShip().transformPosition(VectorConversionsMCKt.toJOML(entity.position())); + Ship ship = ValkyrienSkies.getShipById(this.level, dragInfo.getLastShipStoodOn()); + if (ship != null && ship.getWorldAABB().containsPoint(ValkyrienSkies.toJOML(entity.position()))) { + return ship.getWorldToShip().transformPosition(ValkyrienSkies.toJOML(entity.position())); } } diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/sound/client/MixinSimpleSoundInstance.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/sound/client/MixinSimpleSoundInstance.java index 1797b4e21..22bcc38d1 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/sound/client/MixinSimpleSoundInstance.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/sound/client/MixinSimpleSoundInstance.java @@ -11,8 +11,8 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.mod.api.ValkyrienSkies; import org.valkyrienskies.mod.client.audio.SimpleSoundInstanceOnShip; -import org.valkyrienskies.mod.common.VSGameUtilsKt; @Mixin(SimpleSoundInstance.class) public class MixinSimpleSoundInstance { @@ -25,7 +25,7 @@ public class MixinSimpleSoundInstance { private static void forRecord(final SoundEvent sound, final Vec3 pos, final CallbackInfoReturnable cir) { - final Ship ship = VSGameUtilsKt.getShipManagingPos(Minecraft.getInstance().level, pos.x(), pos.y(), pos.z()); + final Ship ship = ValkyrienSkies.getShipManagingBlock(Minecraft.getInstance().level, pos.x(), pos.y(), pos.z()); if (ship != null) { cir.setReturnValue(new SimpleSoundInstanceOnShip( sound, SoundSource.RECORDS, 4.0F, 1.0F, SoundInstance.createUnseededRandom(), false, 0, diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/teleport_reconnected_player_to_ship/MixinServerPlayer.java b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/teleport_reconnected_player_to_ship/MixinServerPlayer.java index 903bd866c..18985dbd5 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/feature/teleport_reconnected_player_to_ship/MixinServerPlayer.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/feature/teleport_reconnected_player_to_ship/MixinServerPlayer.java @@ -15,7 +15,7 @@ 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.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.api.ValkyrienSkies; import org.valkyrienskies.mod.common.config.VSGameConfig; import org.valkyrienskies.mod.common.util.EntityDraggingInformation; import org.valkyrienskies.mod.common.util.IEntityDraggingInformationProvider; @@ -42,7 +42,7 @@ void teleportToShip(final CompoundTag compoundTag, final CallbackInfo ci) { final long lastShipId = compoundTag.getLong("LastShipId"); - final Ship ship = VSGameUtilsKt.getShipObjectWorld(serverLevel()).getAllShips().getById(lastShipId); + final Ship ship = ValkyrienSkies.getShipById(serverLevel(), lastShipId); // Don't teleport if the ship doesn't exist anymore if (ship == null) return; @@ -69,7 +69,7 @@ void rememberLastShip(final CompoundTag compoundTag, final CallbackInfo ci) { if (lastShipId == null) return; - final Ship ship = VSGameUtilsKt.getShipObjectWorld(serverLevel()).getAllShips().getById(lastShipId); + final Ship ship = ValkyrienSkies.getShipById(serverLevel(), lastShipId); if (ship == null) return; diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinSpeakerSound.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinSpeakerSound.java similarity index 81% rename from forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinSpeakerSound.java rename to common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinSpeakerSound.java index 907ec7493..d86e67782 100644 --- a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinSpeakerSound.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinSpeakerSound.java @@ -1,4 +1,4 @@ -package org.valkyrienskies.mod.forge.mixin.compat.cc_tweaked; +package org.valkyrienskies.mod.mixin.mod_compat.cc_tweaked; import dan200.computercraft.client.sound.SpeakerSound; import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; @@ -16,8 +16,8 @@ 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.mod.api.ValkyrienSkies; import org.valkyrienskies.mod.client.audio.VelocityTickableSoundInstance; -import org.valkyrienskies.mod.common.VSGameUtilsKt; @Mixin(SpeakerSound.class) public abstract class MixinSpeakerSound extends AbstractSoundInstance implements VelocityTickableSoundInstance { @@ -35,9 +35,9 @@ protected MixinSpeakerSound(ResourceLocation arg, SoundSource arg2, RandomSource ) private void isOnShip(SpeakerPosition position, CallbackInfo ci) { this.speakerPosition = position; - this.ship = VSGameUtilsKt.getShipManagingPos(position.level(), position.position()); + this.ship = ValkyrienSkies.getShipManagingBlock(position.level(), position.position()); if (this.ship != null) { - Vec3 worldPos = VSGameUtilsKt.toWorldCoordinates(speakerPosition.level(), speakerPosition.position()); + Vec3 worldPos = ValkyrienSkies.positionToWorld(speakerPosition.level(), speakerPosition.position()); x = worldPos.x; y = worldPos.y; z = worldPos.z; @@ -50,7 +50,7 @@ private void isOnShip(SpeakerPosition position, CallbackInfo ci) { ) private void updateWorldPos(CallbackInfo ci) { if (this.ship != null) { - Vec3 worldPos = VSGameUtilsKt.toWorldCoordinates(speakerPosition.level(), speakerPosition.position()); + Vec3 worldPos = ValkyrienSkies.positionToWorld(speakerPosition.level(), speakerPosition.position()); x = worldPos.x; y = worldPos.y; z = worldPos.z; diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinTurtleBrain.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinTurtleBrain.java new file mode 100644 index 000000000..80830ffc3 --- /dev/null +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinTurtleBrain.java @@ -0,0 +1,76 @@ +package org.valkyrienskies.mod.mixin.mod_compat.cc_tweaked; + +import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity; +import dan200.computercraft.shared.turtle.core.TurtleBrain; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.joml.Vector3d; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.mod.api.ValkyrienSkies; +import org.valkyrienskies.mod.common.config.VSGameConfig; + +@Pseudo +@Mixin(TurtleBrain.class) +public abstract class MixinTurtleBrain { + @Shadow(remap = false) + public abstract TurtleBlockEntity getOwner(); + + @Shadow(remap = false) + public abstract void setOwner(TurtleBlockEntity owner); + + @Shadow + public abstract Level getLevel(); + + @ModifyVariable( + method = "teleportTo(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Z", + at = @At(value = "HEAD"), + index = 2, + argsOnly = true, + remap = false + ) + private BlockPos ValkyrienSkies2$teleportToBlockPos(final BlockPos pos) { + final TurtleBlockEntity currentOwner = getOwner(); + final BlockPos oldPos = currentOwner.getBlockPos(); + final Level world = getLevel(); + + final Ship ship = ValkyrienSkies.getShipManagingBlock(world, oldPos); + if (ship != null) { + // THERE IS A SHIP + + final Vector3d transformedDirection = ship.getShipToWorld().transformDirection( + ValkyrienSkies.toJOMLd(currentOwner.getDirection().getNormal()) + ); + if (!ship.getShipAABB().containsPoint(ValkyrienSkies.toJOML(pos))) { + // POSITION IS OUTSIDE THE SHIP'S AABB + + currentOwner.setDirection( + Direction.getNearest(transformedDirection.x, transformedDirection.y, transformedDirection.z)); + setOwner(currentOwner); + + final boolean isShipScaled = !ship.getTransform().getShipToWorldScaling().equals(1.000E+0, 1.000E+0, 1.000E+0); + + if (isShipScaled) { + // SHIP IS SCALED + + if (VSGameConfig.SERVER.getComputerCraft().getCanTurtlesLeaveScaledShips()) { + // TURTLES CAN LEAVE SCALED SHIPS + + return BlockPos.containing(ValkyrienSkies.positionToWorld(ship, Vec3.atCenterOf(pos))); + } + } else { + // SHIP ISNT SCALED + + return BlockPos.containing(ValkyrienSkies.positionToWorld(ship, Vec3.atCenterOf(pos))); + } + } + } + return pos; + } +} diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinTurtleMoveCommand.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinTurtleMoveCommand.java new file mode 100644 index 000000000..2b4218fa2 --- /dev/null +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinTurtleMoveCommand.java @@ -0,0 +1,57 @@ +package org.valkyrienskies.mod.mixin.mod_compat.cc_tweaked; + +import com.google.common.collect.Streams; +import dan200.computercraft.api.turtle.TurtleCommandResult; +import dan200.computercraft.shared.turtle.core.TurtleMoveCommand; +import dan200.computercraft.shared.turtle.core.TurtlePlayer; +import java.util.ArrayList; +import java.util.List; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import org.joml.Vector3d; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Pseudo; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.mod.api.ValkyrienSkies; + +@Pseudo +@Mixin(TurtleMoveCommand.class) +public abstract class MixinTurtleMoveCommand { + @Inject(method = "canEnter", at = @At("RETURN"), remap = false, cancellable = true) + private static void ValkyrienSkies2$canEnter( + TurtlePlayer turtlePlayer, ServerLevel world, BlockPos position, + CallbackInfoReturnable cir) { + if (cir.getReturnValue().isSuccess()) { + final Ship ship = ValkyrienSkies.getShipManagingBlock(world, position); + Vector3d testPosition = ValkyrienSkies.toJOML(position.getCenter()); + + if (ship != null) { + final ChunkPos chunk = world.getChunkAt(position).getPos(); + if (!ship.getChunkClaim().contains(chunk.x, chunk.z)) { + cir.setReturnValue(TurtleCommandResult.failure("Out of ship chunk")); + } + + testPosition = ValkyrienSkies.positionToWorld(ship, testPosition); + } + + final List nearbyShips = + new ArrayList<>(Streams.stream(ValkyrienSkies.positionToNearbyShips(world, + testPosition.x, testPosition.y, testPosition.z, 0.1)).toList()); + + final boolean notInAir = !nearbyShips.isEmpty() && nearbyShips + .stream() + .map(ValkyrienSkies::toMinecraft) + .map(BlockPos::containing) + .map(world::getBlockState) + .anyMatch(state -> !state.isAir()); + + if (notInAir) { + cir.setReturnValue(TurtleCommandResult.failure("Movement obstructed by ship")); + } + } + } +} diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinWirelessModemPeripheral.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinWirelessModemPeripheral.java similarity index 81% rename from forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinWirelessModemPeripheral.java rename to common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinWirelessModemPeripheral.java index 01226e2e1..e45a6accd 100644 --- a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinWirelessModemPeripheral.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinWirelessModemPeripheral.java @@ -1,4 +1,4 @@ -package org.valkyrienskies.mod.forge.mixin.compat.cc_tweaked; +package org.valkyrienskies.mod.mixin.mod_compat.cc_tweaked; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; @@ -7,7 +7,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.injection.At; -import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.api.ValkyrienSkies; @Pseudo @Mixin(WirelessModemPeripheral.class) @@ -20,6 +20,6 @@ public abstract class MixinWirelessModemPeripheral { ) ) public Vec3 ValkyrienSkies$getPosition(WirelessModemPeripheral instance, Operation original){ - return VSGameUtilsKt.toWorldCoordinates(instance.getLevel(), original.call(instance)); + return ValkyrienSkies.positionToWorld(instance.getLevel(), original.call(instance)); } } diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinWirelessNetwork.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinWirelessNetwork.java similarity index 87% rename from forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinWirelessNetwork.java rename to common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinWirelessNetwork.java index 01c3d5537..b4ca44916 100644 --- a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinWirelessNetwork.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/MixinWirelessNetwork.java @@ -1,8 +1,8 @@ -package org.valkyrienskies.mod.forge.mixin.compat.cc_tweaked; +package org.valkyrienskies.mod.mixin.mod_compat.cc_tweaked; +import dan200.computercraft.api.network.Packet; import dan200.computercraft.api.network.PacketReceiver; import dan200.computercraft.api.network.PacketSender; -import dan200.computercraft.api.network.Packet; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; @@ -12,7 +12,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.api.ValkyrienSkies; @Pseudo @Mixin(WirelessNetwork.class) @@ -30,7 +30,7 @@ public class MixinWirelessNetwork { ) ) private static double ValkyrienSkies$distanceToSqr(final Vec3 instance, final Vec3 d) { - return VSGameUtilsKt.squaredDistanceBetweenInclShips(shipReceiver.getLevel(), instance.x, instance.y, + return ValkyrienSkies.distanceSquared(shipReceiver.getLevel(), instance.x, instance.y, instance.z, d.x, d.y, d.z); } diff --git a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/README.MD b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/README.MD similarity index 100% rename from fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/README.MD rename to common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/cc_tweaked/README.MD diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/entity/MixinAbstractContraptionEntity.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/entity/MixinAbstractContraptionEntity.java index 5639ab068..19d018290 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/entity/MixinAbstractContraptionEntity.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/create/entity/MixinAbstractContraptionEntity.java @@ -306,7 +306,7 @@ private void postTick(final CallbackInfo ci) { if (ship != null) { try { // This can happen if a player moves a train contraption from ship to world using a wrench - ship.getAttachment(WingManager.class) + ship.getWingManager() .setWingGroupTransform(wingGroupId, computeContraptionWingTransform()); } catch (final Exception e) { // I'm not sure why, but this fails sometimes. For now just catch the error and print it diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/etf/MixinBlockEntity.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/etf/MixinBlockEntity.java index c7e64422e..953e5b261 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/etf/MixinBlockEntity.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/etf/MixinBlockEntity.java @@ -5,17 +5,17 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.phys.Vec3; import org.spongepowered.asm.mixin.Mixin; -import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.api.ValkyrienSkies; import traben.entity_texture_features.utils.ETFEntity; @Mixin(value = BlockEntity.class, priority = 1200) public abstract class MixinBlockEntity implements ETFEntity { @Override public float etf$distanceTo(final Entity entity) { - final var level = Minecraft.getInstance().level; - final var aW = VSGameUtilsKt.toWorldCoordinates(level, Vec3.atCenterOf(etf$getBlockPos())); - final var bW = VSGameUtilsKt.toWorldCoordinates(level, entity.position()); - final var dist = aW.distanceTo(bW); - return (float) dist; + return (float) ValkyrienSkies.distance( + Minecraft.getInstance().level, + Vec3.atCenterOf(etf$getBlockPos()), + entity.position() + ); } } diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/ftb_chunks/MixinClaimedChunkManager.java b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/ftb_chunks/MixinClaimedChunkManagerImpl.java similarity index 70% rename from common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/ftb_chunks/MixinClaimedChunkManager.java rename to common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/ftb_chunks/MixinClaimedChunkManagerImpl.java index 4767bfcd9..a1740cef3 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/ftb_chunks/MixinClaimedChunkManager.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/mod_compat/ftb_chunks/MixinClaimedChunkManagerImpl.java @@ -1,10 +1,10 @@ package org.valkyrienskies.mod.mixin.mod_compat.ftb_chunks; -/* -import dev.ftb.mods.ftbchunks.data.ClaimedChunkManager; +import dev.ftb.mods.ftbchunks.data.ClaimedChunkManagerImpl; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import org.joml.Vector3d; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; @@ -13,24 +13,24 @@ import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.valkyrienskies.core.api.ships.Ship; -import org.valkyrienskies.mod.common.VSGameUtilsKt; +import org.valkyrienskies.mod.api.ValkyrienSkies; import org.valkyrienskies.mod.common.config.VSGameConfig; import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; @Pseudo -@Mixin(ClaimedChunkManager.class) -public abstract class MixinClaimedChunkManager { +@Mixin(ClaimedChunkManagerImpl.class) +public abstract class MixinClaimedChunkManagerImpl { @Unique private Entity entity = null; - @ModifyVariable(method = "protect", at = @At("HEAD"), name = "entity", remap = false) + @ModifyVariable(method = "shouldPreventInteraction", at = @At("HEAD"), name = "entity", remap = false) private Entity ValkyrienSkies$entity(final Entity entity) { this.entity = entity; return entity; } @ModifyArg( - method = "protect", + method = "shouldPreventInteraction", at = @At( value = "INVOKE", target = "Ldev/ftb/mods/ftblibrary/math/ChunkDimPos;(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)V" @@ -43,22 +43,19 @@ public abstract class MixinClaimedChunkManager { final Level level = entity.level(); - final Ship ship = VSGameUtilsKt.getShipManagingPos(level, pos); + final Ship ship = ValkyrienSkies.getShipManagingBlock(level, pos); if (ship == null) { return pos; } - final Vector3d vec = ship.getShipToWorld().transformPosition(new Vector3d(pos.getX(), pos.getY(), pos.getZ())); + final Vector3d vec = ship.getShipToWorld().transformPosition(VectorConversionsMCKt.toJOML(Vec3.atCenterOf(pos))); final BlockPos newPos = BlockPos.containing(VectorConversionsMCKt.toMinecraft(vec)); - if ( - (newPos.getY() > level.getMaxBuildHeight() || newPos.getY() < level.getMinBuildHeight()) && - !VSGameConfig.SERVER.getFTBChunks().getShipsProtectionOutOfBuildHeight() - ) { + if ((newPos.getY() > level.getMaxBuildHeight() || newPos.getY() < level.getMinBuildHeight()) && + !VSGameConfig.SERVER.getFTBChunks().getShipsProtectionOutOfBuildHeight()) { return pos; } return newPos; } } -*/ diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/server/MixinMinecraftServer.java b/common/src/main/java/org/valkyrienskies/mod/mixin/server/MixinMinecraftServer.java index 7170da286..6538f1cd1 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/server/MixinMinecraftServer.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/server/MixinMinecraftServer.java @@ -83,12 +83,12 @@ public abstract class MixinMinecraftServer implements IShipObjectWorldServerProv method = "runServer" ) private void beforeInitServer(final CallbackInfo info) { - ValkyrienSkiesMod.setCurrentServer(MinecraftServer.class.cast(this)); + ValkyrienSkiesMod.addServer(MinecraftServer.class.cast(this)); } @Inject(at = @At("TAIL"), method = "stopServer") private void afterStopServer(final CallbackInfo ci) { - ValkyrienSkiesMod.setCurrentServer(null); + ValkyrienSkiesMod.removeServer(MinecraftServer.class.cast(this)); } @Nullable diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/server/world/MixinServerLevel.java b/common/src/main/java/org/valkyrienskies/mod/mixin/server/world/MixinServerLevel.java index a6897d90e..db8e62f0e 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/server/world/MixinServerLevel.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/server/world/MixinServerLevel.java @@ -53,25 +53,22 @@ @Mixin(ServerLevel.class) public abstract class MixinServerLevel implements IShipObjectWorldServerProvider, VSServerLevel { - @Shadow - @Final - private ServerChunkCache chunkSource; - - @Shadow - @NotNull - public abstract MinecraftServer getServer(); - + // How many ticks we wait before unloading a chunk + @Unique + private static final long VS$CHUNK_UNLOAD_THRESHOLD = 100; // Map from ChunkPos to the list of voxel chunks that chunk owns @Unique private final Map> vs$knownChunks = new HashMap<>(); - // Maps chunk pos to number of ticks we have considered unloading the chunk @Unique private final Long2LongOpenHashMap vs$chunksToUnload = new Long2LongOpenHashMap(); + @Shadow + @Final + private ServerChunkCache chunkSource; - // How many ticks we wait before unloading a chunk - @Unique - private static final long VS$CHUNK_UNLOAD_THRESHOLD = 100; + @Shadow + @NotNull + public abstract MinecraftServer getServer(); @Nullable @Override @@ -150,24 +147,25 @@ private boolean includeShipsInParticleDistanceCheck( final LoadedServerShip ship = VSGameUtilsKt.getShipObjectManagingPos(thisAsLevel, chunkX, chunkZ); if (ship != null) { - // Sussy cast, but I don't want to expose this directly through the vs-core api - final WingManager shipAsWingManager = ship.getAttachment(WingManager.class); - final MutableBlockPos mutableBlockPos = new MutableBlockPos(); - for (int x = 0; x < 16; x++) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - final BlockState blockState = chunkSection.getBlockState(x, y, z); - final int posX = (chunkX << 4) + x; - final int posY = worldChunk.getMinBuildHeight() + (sectionY << 4) + y; - final int posZ = (chunkZ << 4) + z; - if (blockState.getBlock() instanceof WingBlock) { - mutableBlockPos.set(posX, posY, posZ); - final Wing wing = - ((WingBlock) blockState.getBlock()).getWing(thisAsLevel, - mutableBlockPos, blockState); - if (wing != null) { - shipAsWingManager.setWing(shipAsWingManager.getFirstWingGroupId(), - posX, posY, posZ, wing); + final WingManager shipAsWingManager = ship.getWingManager(); + if (shipAsWingManager != null) { + final MutableBlockPos mutableBlockPos = new MutableBlockPos(); + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + final BlockState blockState = chunkSection.getBlockState(x, y, z); + final int posX = (chunkX << 4) + x; + final int posY = worldChunk.getMinBuildHeight() + (sectionY << 4) + y; + final int posZ = (chunkZ << 4) + z; + if (blockState.getBlock() instanceof WingBlock) { + mutableBlockPos.set(posX, posY, posZ); + final Wing wing = + ((WingBlock) blockState.getBlock()).getWing(thisAsLevel, + mutableBlockPos, blockState); + if (wing != null) { + shipAsWingManager.setWing(shipAsWingManager.getFirstWingGroupId(), + posX, posY, posZ, wing); + } } } } @@ -195,13 +193,15 @@ private void postTick(final BooleanSupplier shouldKeepTicking, final CallbackInf // Create DenseVoxelShapeUpdate for new loaded chunks // Also mark the chunks as loaded in the ship objects final List voxelShapeUpdates = new ArrayList<>(); - final DistanceManagerAccessor distanceManagerAccessor = (DistanceManagerAccessor) chunkSource.chunkMap.getDistanceManager(); + final DistanceManagerAccessor distanceManagerAccessor = + (DistanceManagerAccessor) chunkSource.chunkMap.getDistanceManager(); for (final ChunkHolder chunkHolder : chunkMapAccessor.callGetChunks()) { final Optional worldChunkOptional = chunkHolder.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).left(); // Only load chunks that are present and that have tickets - if (worldChunkOptional.isPresent() && distanceManagerAccessor.getTickets().containsKey(chunkHolder.getPos().toLong())) { + if (worldChunkOptional.isPresent() && + distanceManagerAccessor.getTickets().containsKey(chunkHolder.getPos().toLong())) { // Only load chunks that have a ticket final LevelChunk worldChunk = worldChunkOptional.get(); vs$loadChunk(worldChunk, voxelShapeUpdates); @@ -213,7 +213,8 @@ private void postTick(final BooleanSupplier shouldKeepTicking, final CallbackInf final Entry> knownChunkPosEntry = knownChunkPosIterator.next(); final long chunkPos = knownChunkPosEntry.getKey().toLong(); // Unload chunks if they don't have tickets or if they're not in the visible chunks - if ((!distanceManagerAccessor.getTickets().containsKey(chunkPos) || chunkMapAccessor.callGetVisibleChunkIfPresent(chunkPos) == null)) { + if ((!distanceManagerAccessor.getTickets().containsKey(chunkPos) || + chunkMapAccessor.callGetVisibleChunkIfPresent(chunkPos) == null)) { final long ticksWaitingToUnload = vs$chunksToUnload.getOrDefault(chunkPos, 0L); if (ticksWaitingToUnload > VS$CHUNK_UNLOAD_THRESHOLD) { // Unload this chunk diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/api/ShipBlockHitResult.kt b/common/src/main/kotlin/org/valkyrienskies/mod/api/ShipBlockHitResult.kt new file mode 100644 index 000000000..729fa3656 --- /dev/null +++ b/common/src/main/kotlin/org/valkyrienskies/mod/api/ShipBlockHitResult.kt @@ -0,0 +1,69 @@ +package org.valkyrienskies.mod.api + +import net.minecraft.world.phys.BlockHitResult +import net.minecraft.world.phys.Vec3 + +/** + * Valkyrien Skies modifies vanilla methods to return an instance of [ShipBlockHitResult] when a raycast hits a block + * on a ship. + * + * By default, we set the [location] to be in world-space, while the [blockPos] is in ship-space. However, + * in some cases, mods want the [location] to be in ship-space as well. In that case, that mod (or a mixin into it) + * can check if a hit result is `instanceof ShipBlockHitResult` and use either [useLocationInShip] or + * [withLocationInShip] to change the [location]. + * + * See also: [#613](https://github.com/ValkyrienSkies/Valkyrien-Skies-2/issues/613) + * + * @constructor The default constructor uses the [locationInWorld] to set [location]. The [location] of the original + * [BlockHitResult] is ignored. + */ +class ShipBlockHitResult private constructor( + hitResult: BlockHitResult, + /** + * The location this raycast hit, in ship coordinates + */ + val locationInShip: Vec3, + /** + * The location this raycast hit, in world coordinates + */ + val locationInWorld: Vec3, +) : BlockHitResult(locationInWorld, hitResult.direction, hitResult.blockPos, hitResult.isInside) { + + companion object { + @JvmStatic + fun create(hitResult: BlockHitResult, locationInShip: Vec3, locationInWorld: Vec3) = + ShipBlockHitResult(hitResult, locationInShip, locationInWorld) + } + + init { + require(hitResult.type != Type.MISS) { "Cannot construct a ShipBlockHitResult out of a miss." } + } + + /** + * Sets [location] to [locationInShip]. This *mutates* the current hit result - use carefully. + */ + fun useLocationInShip(): BlockHitResult = also { + this.location = locationInShip + } + + /** + * Sets [location] to [locationInWorld]. This *mutates* the current hit result - use carefully. + */ + fun useLocationInWorld(): BlockHitResult = also { + this.location = locationInWorld + } + + /** + * Returns a new copy of this [ShipBlockHitResult] with [location] set to [locationInWorld]. + */ + fun withLocationInWorld(): ShipBlockHitResult = + ShipBlockHitResult(this, locationInShip, locationInWorld) + .also { it.useLocationInWorld() } + + /** + * Returns a new copy of this [ShipBlockHitResult] with [location] set to [locationInShip]. + */ + fun withLocationInShip(): ShipBlockHitResult = + ShipBlockHitResult(this, locationInShip, locationInWorld) + .also { it.useLocationInShip() } +} diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/api/ValkyrienSkies.kt b/common/src/main/kotlin/org/valkyrienskies/mod/api/ValkyrienSkies.kt index 5ef8f8264..50467f55b 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/api/ValkyrienSkies.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/api/ValkyrienSkies.kt @@ -1,20 +1,606 @@ +/* + * This is basically the god class for all functions needed by addon developers. + * + * This class may be moved into a separate mod at some point, so that it can + * be shaded. Therefore, only use standard libraries, Minecraft classes, and + * classes in + * + * - org.valkyrienskies.core.api.* + * - org.valkyrienskies.mod.api.* + * - org.joml.* + * + * Notably do NOT use classes from + * - org.valkyrienskies.mod.* (except api) + * - org.valkyrienskies.core.util.* + * - org.valkyrienskies.core.apigame.* + * + * Style notes: + * + * Since this class will also be used from Java, try to make parameters nullable + * wherever possible. Null-checking is pretty cumbersome in Java, so for each + * function that takes non-nullable parameters and returns a non-nullable type, + * make a variant that takes nullable parameters and returns a nullable type as + * well. + * + * Prefer to use extension functions and fields rather than global functions. + */ @file:JvmName("ValkyrienSkies") package org.valkyrienskies.mod.api +import com.mojang.blaze3d.vertex.PoseStack +import net.minecraft.client.Minecraft import net.minecraft.core.BlockPos +import net.minecraft.core.Direction +import net.minecraft.core.Position +import net.minecraft.core.Vec3i +import net.minecraft.server.MinecraftServer +import net.minecraft.world.entity.Entity import net.minecraft.world.level.ChunkPos import net.minecraft.world.level.Level -import org.valkyrienskies.core.api.ships.LoadedShip +import net.minecraft.world.phys.AABB +import net.minecraft.world.phys.Vec3 +import org.jetbrains.annotations.Contract +import org.joml.Matrix3f +import org.joml.Matrix4d +import org.joml.Matrix4dc +import org.joml.Quaterniondc +import org.joml.Quaternionf +import org.joml.Vector2i +import org.joml.Vector2ic +import org.joml.Vector3d +import org.joml.Vector3dc +import org.joml.Vector3f +import org.joml.Vector3i +import org.joml.Vector3ic +import org.joml.Vector4f +import org.joml.primitives.AABBd +import org.joml.primitives.AABBdc import org.valkyrienskies.core.api.ships.Ship +import org.valkyrienskies.core.api.ships.properties.ShipId +import org.valkyrienskies.core.api.ships.properties.ShipTransform +import org.valkyrienskies.core.api.util.functions.DoubleTernaryConsumer +import org.valkyrienskies.core.api.world.ClientShipWorld +import org.valkyrienskies.core.api.world.ServerShipWorld +import org.valkyrienskies.core.api.world.ShipWorld +import org.valkyrienskies.core.api.world.properties.DimensionId +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind.EXACTLY_ONCE +import kotlin.contracts.contract +import kotlin.math.sqrt -val vsApi: VsApi @JvmName("getApi") get() = TODO() +/** + * The singleton instance of [VsApi]. + */ +@get:JvmName("api") +val vsApi: VsApi by lazy { + try { + val modClass = Class.forName("org.valkyrienskies.mod.common.ValkyrienSkiesMod") + val getApi = modClass.getDeclaredMethod("getApi") + val instance = getApi.invoke(null) as VsApi -fun Level?.getShipManagingBlock(pos: BlockPos?) = vsApi.getShipManagingBlock(this, pos) -fun Level?.getShipManagingBlock(x: Int, y: Int, z: Int) = getShipManagingChunk(x shr 4, z shr 4) + instance + } catch (ex: Exception) { + throw IllegalStateException("Failed initialize the Valkyrien Skies API. " + + "Suggestion: Ensure that you have Valkyrien Skies installed.", ex) + } +} -fun Level?.getLoadedShipManagingBlock(pos: BlockPos?): LoadedShip? = TODO() +/** + * The String/[DimensionId] used within vs-core for representing this [Level]. + * + * This is a Kotlin-only function. + */ +val Level.dimensionId: DimensionId + @JvmSynthetic + @JvmName("getDimensionIdNonnull") + get() = vsApi.getDimensionId(this) -fun Level?.getDeadShipManagingBlock(pos: BlockPos?): Ship? = TODO() +/** + * The String/[DimensionId] used within vs-core for representing this [Level]. + */ +val Level?.dimensionId: DimensionId? + @Contract("null -> null; !null -> !null") + get() = this?.dimensionId -fun Level?.getShipManagingChunk(pos: ChunkPos?) = vsApi.getShipManagingChunk(this, pos) -fun Level?.getShipManagingChunk(chunkX: Int, chunkZ: Int) = vsApi.getShipManagingChunk(this, chunkX, chunkZ) + +/** + * The [ServerShipWorld] associated with this [MinecraftServer] if it exists. + */ +val MinecraftServer?.shipWorld: ServerShipWorld? get() = + vsApi.getServerShipWorld(this) + +/** + * The [ClientShipWorld] associated with this [Minecraft] if it exists. + */ +val Minecraft?.shipWorld: ClientShipWorld? get() = + vsApi.getClientShipWorld(this) + +val Level?.shipWorld: ShipWorld? get() = + vsApi.getShipWorld(this) + +fun Level?.getShipById(id: ShipId): Ship? = + shipWorld?.allShips?.getById(id) + +fun Level?.isBlockInShipyard(blockX: Int, blockY: Int, blockZ: Int): Boolean = + isChunkInShipyard(blockX shr 4, blockZ shr 4) + +fun Level?.isChunkInShipyard(chunkX: Int, chunkZ: Int): Boolean = + vsApi.isChunkInShipyard(this, chunkX, chunkZ) + +fun Level?.getShipManagingChunk(chunkX: Int, chunkZ: Int): Ship? = + vsApi.getShipManagingChunk(this, chunkX, chunkZ) + +fun Level?.getShipManagingChunk(pos: ChunkPos?): Ship? = + pos?.let { getShipManagingChunk(pos.x, pos.z) } + +fun Level?.getShipManagingBlock(x: Int, y: Int, z: Int): Ship? = + getShipManagingChunk(x shr 4, z shr 4) + +fun Level?.getShipManagingBlock(pos: BlockPos?): Ship? = + pos?.let { getShipManagingBlock(pos.x, pos.y, pos.z) } + +fun Level?.getShipManagingBlock(x: Double, y: Double, z: Double): Ship? = + getShipManagingBlock(x.toInt(), y.toInt(), z.toInt()) + +fun Level?.getShipManagingBlock(v: Vector3dc?): Ship? = + v?.let { getShipManagingBlock(v.x(), v.y(), v.z()) } + +fun Level?.getShipManagingBlock(v: Position?): Ship? = + v?.let { getShipManagingBlock(v.x(), v.y(), v.z()) } + +/** + * Convenience function for + * `entity.level().getShipManagingBlock(entity.position())`. + * + * @see getShipManagingBlock + */ +fun Entity?.getShipManagingEntity(): Ship? = + this?.level()?.getShipManagingBlock(position()) + +/** + * If both endpoints of the given [aabb] are in the same ship, transform them + * to the world and return the new AABB. Otherwise, leaves it untouched. + */ +fun Level?.toWorld(aabb: AABBdc, dest: AABBd): AABBd { + val ship1 = getShipManagingBlock(aabb.minX(), aabb.minY(), aabb.minZ()) + ?: return dest.set(aabb) + val ship2 = getShipManagingBlock(aabb.maxX(), aabb.maxY(), aabb.maxZ()) + ?: return dest.set(aabb) + + // if both endpoints of the aabb are in the same ship, do the transform + if (ship1.id == ship2.id) { + return aabb.transform(ship1.shipToWorld, dest) + } + + return dest.set(aabb) +} + +fun Level?.toWorld(aabb: AABBd) = + toWorld(aabb, aabb) + +fun Level?.toWorld(aabb: AABB): AABB = + toWorld(aabb.toJOML()).toMinecraft() + + +fun Level?.positionToWorld(pos: Vec3): Vec3 = + getShipManagingBlock(pos).positionToWorld(pos) + +fun Level?.positionToWorld(pos: Vector3d): Vector3d = + positionToWorld(pos, pos) + +fun Level?.positionToWorld(pos: Vector3dc, dest: Vector3d): Vector3d = + getShipManagingBlock(pos).positionToWorld(pos, dest) + +fun Ship?.positionToWorld(pos: Vec3): Vec3 = + this?.transform.positionToWorld(pos) + +fun Ship?.positionToWorld(pos: Vector3d): Vector3d = + positionToWorld(pos, pos) + +fun Ship?.positionToWorld(pos: Vector3dc, dest: Vector3d): Vector3d = + this?.transform.positionToWorld(pos, dest) + +fun Ship?.positionToShip(pos: Vec3): Vec3 = + this?.transform.positionToShip(pos) + +fun Ship?.positionToShip(pos: Vector3d): Vector3d = + positionToShip(pos, pos) + +fun Ship?.positionToShip(pos: Vector3dc, dest: Vector3d): Vector3d = + this?.transform.positionToShip(pos, dest) + +fun ShipTransform?.positionToWorld(pos: Vec3): Vec3 = + this?.shipToWorld?.transformPosition(pos) ?: pos + +fun ShipTransform?.positionToWorld(pos: Vector3d): Vector3d = + positionToWorld(pos, pos) + +fun ShipTransform?.positionToWorld(pos: Vector3dc, dest: Vector3d): Vector3d = + this?.shipToWorld?.transformPosition(pos, dest) ?: dest.set(pos) + +fun ShipTransform?.positionToShip(pos: Vec3): Vec3 = + this?.worldToShip?.transformPosition(pos) ?: pos + +fun ShipTransform?.positionToShip(pos: Vector3d): Vector3d = + positionToShip(pos, pos) + +fun ShipTransform?.positionToShip(pos: Vector3dc, dest: Vector3d): Vector3d = + this?.worldToShip?.transformPosition(pos, dest) ?: dest.set(pos) + +/** + * Returns all the ships whose AABBs contain x/y/z + */ +fun Level?.getShipsIntersecting(x: Double, y: Double, z: Double): Iterable = + vsApi.getShipsIntersecting(this, x, y, z) + +/** + * Returns all the ships whose AABBs intersect [aabb] + */ +fun Level?.getShipsIntersecting(aabb: AABBdc?): Iterable = + vsApi.getShipsIntersecting(this, aabb) + +/** + * Transforms the given world position x/y/z into the ship space of all ships whose AABBs contain x/y/z + */ +fun Level?.positionToNearbyShips(x: Double, y: Double, z: Double): Iterable = + getShipsIntersecting(x, y, z).map { it.positionToShip(Vector3d(x, y, z)) } + +/** + * Transforms the given world position into the ship space of all ships whose AABB intersects [aabb] + */ +fun Level?.positionToNearbyShips(x: Double, y: Double, z: Double, aabb: AABBdc?): Iterable { + if (this == null || aabb == null) return emptyList() + return getShipsIntersecting(aabb).map { it.positionToShip(Vector3d(x, y, z)) } +} + +fun Level?.positionToNearbyShips(x: Double, y: Double, z: Double, aabbRadius: Double): Iterable = + positionToNearbyShips(x, y, z, newAABBWithRadius(x, y, z, aabbRadius)) + +fun Level?.positionToNearbyShips(x: Double, y: Double, z: Double, cb: DoubleTernaryConsumer): Unit = + positionToNearbyShips(x, y, z, null, cb::accept) + +fun Level?.positionToNearbyShips(x: Double, y: Double, z: Double, aabb: AABBdc?, cb: DoubleTernaryConsumer): Unit = + positionToNearbyShips(x, y, z, aabb, cb::accept) + +fun Level?.positionToNearbyShips(x: Double, y: Double, z: Double, aabbRadius: Double, cb: DoubleTernaryConsumer): Unit = + positionToNearbyShips(x, y, z, newAABBWithRadius(x, y, z, aabbRadius), cb) + +fun Level?.positionToNearbyShipsAndWorld(x: Double, y: Double, z: Double): Iterable = + listOf(Vector3d(x, y, z)) + positionToNearbyShips(x, y, z) + +fun Level?.positionToNearbyShipsAndWorld(x: Double, y: Double, z: Double, aabb: AABBdc?): Iterable = + listOf(Vector3d(x, y, z)) + positionToNearbyShips(x, y, z, aabb) + +fun Level?.positionToNearbyShipsAndWorld(x: Double, y: Double, z: Double, aabbRadius: Double): Iterable = + positionToNearbyShipsAndWorld(x, y, z, newAABBWithRadius(x, y, z, aabbRadius)) + +fun Level?.positionToNearbyShipsAndWorld(x: Double, y: Double, z: Double, cb: DoubleTernaryConsumer): Unit = + positionToNearbyShipsAndWorld(x, y, z, null, cb::accept) + +fun Level?.positionToNearbyShipsAndWorld(x: Double, y: Double, z: Double, aabb: AABBdc?, cb: DoubleTernaryConsumer): Unit = + positionToNearbyShipsAndWorld(x, y, z, aabb, cb::accept) + +fun Level?.positionToNearbyShipsAndWorld(x: Double, y: Double, z: Double, aabbRadius: Double, cb: DoubleTernaryConsumer): Unit = + positionToNearbyShipsAndWorld(x, y, z, newAABBWithRadius(x, y, z, aabbRadius), cb) + +private fun newAABBWithRadius(x: Double, y: Double, z: Double, r: Double) = + AABBd(x - r, y - r, z - r, x + r, y + r, z + r) + +private inline fun Level?.positionToNearbyShipsAndWorld( + x: Double, + y: Double, + z: Double, + aabb: AABBdc?, + cb: (Double, Double, Double) -> Unit +) { + cb(x, y, z) + positionToNearbyShips(x, y, z, aabb, cb) +} + +/** + * Gets all ships intersecting [aabb] (or x, y, z if [aabb] is null), then + * transforms the position x, y, z to their respective ship spaces + * and calls [cb] with the transformed positions. + */ +private inline fun Level?.positionToNearbyShips( + x: Double, + y: Double, + z: Double, + aabb: AABBdc?, + cb: (Double, Double, Double) -> Unit +) { + val ships = aabb?.let(this::getShipsIntersecting) + ?: this.getShipsIntersecting(x, y, z) + + for (ship in ships) { + ship.worldToShip.transformPositionInline(x, y, z, cb) + } +} + +fun Level?.distance(x1: Double, y1: Double, z1: Double, x2: Double, y2: Double, z2: Double): Double = + sqrt(distanceSquared(x1, y1, z1, x2, y2, z2)) + +fun Level?.distance(v1: Position, v2: Position): Double = + sqrt(distanceSquared(v1, v2)) + +/** + * Calculates squared distance including ships. + * + * Transforms the points into world space, then calculates the squared distance + * between them. + */ +fun Level?.distanceSquared(x1: Double, y1: Double, z1: Double, x2: Double, y2: Double, z2: Double): Double { + var inWorldX1 = x1 + var inWorldY1 = y1 + var inWorldZ1 = z1 + var inWorldX2 = x2 + var inWorldY2 = y2 + var inWorldZ2 = z2 + + val ship1 = this.getShipManagingBlock(x1, y1, z1) + val ship2 = this.getShipManagingBlock(x2, y2, z2) + + // Do this transform manually to avoid allocation + if (ship1 != null && ship2 != null && ship1 != ship2) { + ship1.shipToWorld.transformPositionInline(x1, y1, z1) { x, y, z -> + inWorldX1 = x + inWorldY1 = y + inWorldZ1 = z + } + ship2.shipToWorld.transformPositionInline(x2, y2, z2) { x, y, z -> + inWorldX2 = x + inWorldY2 = y + inWorldZ2 = z + } + } + + val dx = inWorldX2 - inWorldX1 + val dy = inWorldY2 - inWorldY1 + val dz = inWorldZ2 - inWorldZ1 + + return dx * dx + dy * dy + dz * dz +} + +/** + * Variant of [Vec3.distanceToSqr] including ships. + */ +fun Level?.distanceSquared(v1: Position, v2: Position): Double = + distanceSquared(v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z()) + +/** + * Variant of [Vec3i.distSqr] including ships. + */ +fun Level?.distanceSquared(v1: Vec3i, v2: Vec3i): Double = + distanceSquared(v1.x.toDouble(), v1.y.toDouble(), v1.z.toDouble(), + v2.x.toDouble(), v2.y.toDouble(), v2.z.toDouble()) + +/** + * Variant of [Vec3i.distToCenterSqr] including ships. + */ +fun Level?.distanceToCenterSquared(v1: Vec3i, x2: Double, y2: Double, z2: Double): Double = + distanceSquared(v1.x.toDouble() + 0.5, v1.y.toDouble() + 0.5, v1.z.toDouble() + 0.5, x2, y2, z2) + +/** + * Variant of [Vec3i.distToCenterSqr] including ships. + */ +fun Level?.distanceToCenterSquared(v1: Vec3i, v2: Position): Double = + distanceToCenterSquared(v1, v2.x(), v2.y(), v2.z()) + +/** + * Variant of [Vec3.closerThan] including ships. + */ +fun Level?.closerThan(v1: Position, v2: Position, distance: Double): Boolean = + distanceSquared(v1, v2) < distance.squared() + +/** + * Variant of [Vec3i.closerThan] including ships + */ +fun Level?.closerThan(v1: Vec3i, v2: Vec3i, distance: Double): Boolean = + distanceSquared(v1, v2) < distance.squared() + +/** + * Variant of [Vec3i.closerToCenterThan] including ships + */ +fun Level?.closerToCenterThan(v1: Vec3i, x2: Double, y2: Double, z2: Double, distance: Double): Boolean = + distanceToCenterSquared(v1, x2, y2, z2) < distance.squared() + +/** + * Variant of [Vec3i.closerToCenterThan] including ships + */ +fun Level?.closerToCenterThan(v1: Vec3i, v2: Position, distance: Double): Boolean = + distanceToCenterSquared(v1, v2) < distance.squared() + +// region Private utilities + +private fun Double.squared() = this * this + +/** + * Transform a position without allocating any intermediate objects + */ +@OptIn(ExperimentalContracts::class) +private inline fun Matrix4dc.transformPositionInline( + x: Double, + y: Double, + z: Double, + transformed: (Double, Double, Double) -> T +): T { + contract { + callsInPlace(transformed, EXACTLY_ONCE) + } + return transformed( + m00() * x + m10() * y + m20() * z + m30(), + m01() * x + m11() * y + m21() * z + m31(), + m02() * x + m12() * y + m22() * z + m32() + ) +} + +// endregion + +// region Vector Conversions + +// region JOML + +/** + * Sets the x, y, and z components to match the supplied vector [v]. + * + * @return this + */ +fun Vector3i.set(v: Vec3i) = also { + x = v.x + y = v.y + z = v.z +} + +/** + * Sets the x, y, and z components to match the supplied vector [v]. + * + * @return this + */ +fun Vector3d.set(v: Vec3i) = also { + x = v.x.toDouble() + y = v.y.toDouble() + z = v.z.toDouble() +} + +/** + * Sets the x, y, and z components to match the supplied vector [v]. + * + * @return this + */ +fun Vector3f.set(v: Vec3i) = also { + x = v.x.toFloat() + y = v.y.toFloat() + z = v.z.toFloat() +} + +/** + * Sets the x, y, and z components to match the supplied vector [v]. + * + * @return this + */ +fun Vector3d.set(v: Position) = also { + x = v.x() + y = v.y() + z = v.z() +} + +/** + * Sets the minX, minY, minZ, maxX, maxY, and maxZ components to match the + * supplied aabb [v]. + * + * @return this + */ +fun AABBd.set(v: AABB) = also { + minX = v.minX + minY = v.minY + minZ = v.minZ + maxX = v.maxX + maxY = v.maxY + maxZ = v.maxZ +} + +/** + * Converts a [Vector3ic] to a [BlockPos]. + * + * @return a new [BlockPos] with x, y, and z components matching this. + */ +fun Vector3ic.toBlockPos() = BlockPos(x(), y(), z()) + +/** + * Converts a [Vector3dc] to a [Vec3]. + * + * @return a new [Vec3] with x, y, and z components matching this. + */ +fun Vector3dc.toMinecraft() = Vec3(x(), y(), z()) + +/** + * Converts an [AABBdc] to an [AABB]. + * + * @return a new [AABB] with minX, minY, minZ, maxX, maxY, and maxZ components + * matching this. + */ +fun AABBdc.toMinecraft() = AABB(minX(), minY(), minZ(), maxX(), maxY(), maxZ()) + +/** + * Converts an [AABB] to an [AABBd]. + * + * @return a new [AABBd] with minX, minY, minZ, maxX, maxY, and maxZ components + * matching this. + */ +fun AABB.toJOML() = AABBd().set(this) + +fun Vector2ic.toChunkPos() = ChunkPos(x(), y()) +fun ChunkPos.toJOML() = Vector2i().set(this) + +fun Vec3.toJOML() = Vector3d().set(this) + +fun Vector3d.set(v: Vec3) = also { + x = v.x + y = v.y + z = v.z +} + +fun Vector2i.set(pos: ChunkPos) = also { + x = pos.x + y = pos.z +} + +@JvmOverloads +fun Matrix4dc.transformDirection(v: Vec3i, dest: Vector3d = Vector3d()): Vector3d = + transformDirection(dest.set(v.x.toDouble(), v.y.toDouble(), v.z.toDouble())) + +@JvmOverloads +fun Matrix4dc.transformDirection(dir: Direction, dest: Vector3d = Vector3d()) = transformDirection(dir.normal, dest) + +fun Matrix4dc.transform(v: Vector4f) = v.also { + it.set( + (m00() * v.x() + m01() * v.y() + m02() * v.z() + m03() * v.w()).toFloat(), + (m10() * v.x() + m11() * v.y() + m12() * v.z() + m13() * v.w()).toFloat(), + (m20() * v.x() + m21() * v.y() + m22() * v.z() + m23() * v.w()).toFloat(), + (m30() * v.x() + m31() * v.y() + m32() * v.z() + m33() * v.w()).toFloat() + ) +} + +/** + * Transforms the position [v] by this. + * + * @return a new [Vec3] representing the transformed position + * + * @see Matrix4dc.transformPosition + */ +fun Matrix4dc.transformPosition(v: Position): Vec3 { + transformPositionInline(v.x(), v.y(), v.z()) { x, y, z -> + return Vec3(x, y, z) + } +} + +// endregion + +// region Minecraft + +fun PoseStack.multiply(modelTransform: Matrix4dc, normalTransform: Quaterniondc) = also { + val last = last() + + val newPose = Matrix4d().set(last.pose()).mul(modelTransform) + val newNormal = last.normal().mul(Matrix3f().set(normalTransform)) + + last.pose().set(newPose) + last.normal().set(newNormal) +} + +fun PoseStack.multiply(modelTransform: Matrix4dc) = also { + val last = last() + val newPose = Matrix4d().set(last.pose()).mul(modelTransform) + last.pose().set(newPose) +} + +fun Vec3i.toJOML() = Vector3i().set(this) +fun Vec3i.toJOMLd() = Vector3d().set(this) +fun Vec3i.toJOMLf() = Vector3f().set(this) + +fun Position.toJOML() = Vector3d().set(this) + +fun Quaterniondc.toFloat() = Quaternionf(x(), y(), z(), w()) +// endregion + +// endregion diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/api/VsApi.kt b/common/src/main/kotlin/org/valkyrienskies/mod/api/VsApi.kt index 270bf4ebc..e1cd78332 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/api/VsApi.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/api/VsApi.kt @@ -1,21 +1,48 @@ package org.valkyrienskies.mod.api +import net.minecraft.client.Minecraft import net.minecraft.client.gui.screens.Screen import net.minecraft.client.multiplayer.ClientLevel import net.minecraft.core.BlockPos -import net.minecraft.world.level.ChunkPos -import net.minecraft.world.level.Level +import net.minecraft.server.MinecraftServer import net.minecraft.server.level.ServerLevel import net.minecraft.world.entity.Entity - +import net.minecraft.world.level.Level import org.jetbrains.annotations.ApiStatus.* +import org.joml.Vector3dc +import org.joml.primitives.AABBdc import org.valkyrienskies.core.api.VsCoreApi import org.valkyrienskies.core.api.event.ListenableEvent import org.valkyrienskies.core.api.ships.* +import org.valkyrienskies.core.api.world.ClientShipWorld +import org.valkyrienskies.core.api.world.ServerShipWorld +import org.valkyrienskies.core.api.world.ShipWorld +import org.valkyrienskies.core.api.world.properties.DimensionId import org.valkyrienskies.mod.api.events.PostRenderShipEvent import org.valkyrienskies.mod.api.events.PreRenderShipEvent import org.valkyrienskies.mod.api.events.RegisterBlockStateEvent +/** + * Public API for Valkyrien Skies with both Minecraft and core APIs. This class + * is stable to use, but using the extension methods (exposed as static methods + * in `ValkyrienSkies` class to Java users) is more ergonomic in most cases. + * + * This is meant to be used by: + * - Valkyrien Skies addon developers + * - 3rd-party mod developers implementing Valkyrien Skies compatibility or + * integrations + * + * You can access the singleton instance of this via [vsApi] + * (exposed as `ValkyrienSkies.getApi()` from Java). + */ +/* + * This class may be moved into a separate mod at some point, so that it can + * be shaded. Therefore, only use Minecraft classes and classes in + * + * - org.valkyrienskies.core.api.* + * - org.valkyrienskies.mod.api.* + * - org.joml.* + */ @NonExtendable interface VsApi : VsCoreApi { @@ -31,26 +58,105 @@ interface VsApi : VsCoreApi { @get:Experimental val postRenderShipEvent: ListenableEvent - fun isShipMountingEntity(entity: Entity): Boolean @Deprecated(message = "The legacy VS config system will be replaced soon. " + "Migrate to another config library, or the new system when it's released. ") fun createConfigScreenLegacy(parent: Screen, vararg configs: Class<*>): Screen /** - * Get the ship with the chunk claim that contains [pos], if it exists. + * Returns the [DimensionId] + */ + fun getDimensionId(level: Level): DimensionId + + /** + * Returns the ship that [entity] is mounted to, if it exists. + */ + fun getShipMountedTo(entity: Entity?): Ship? + + /** + * Returns the position in the ship that the [entity] is mounted to, if + * it exists. + */ + fun getMountPosInShip(entity: Entity?): Vector3dc? + + /** + * Returns the position in the ship that the [entity] is mounted to, if + * it exists, interpolating their position using [partialTicks] + */ + fun getMountPosInShip(entity: Entity?, partialTicks: Float): Vector3dc? + + /** + * Returns the [ServerShipWorld] associated with the given [MinecraftServer] + * if it exists. + * + * This will return null if there is no [ServerShipWorld] associated with + * [server] + */ + fun getServerShipWorld(server: MinecraftServer?): ServerShipWorld? + + /** + * Returns the [ClientShipWorld] associated with the given [Minecraft] + * if it exists. + * + * This will return null if there is no [ClientShipWorld] associated with + * [client] + */ + fun getClientShipWorld(client: Minecraft?): ClientShipWorld? + + /** + * Returns the [ShipWorld] associated with the given [Level] if it exists. * - * If either parameter is null, this will return null. + * This will return null if there is no [ShipWorld] associated with [level]. + */ + fun getShipWorld(level: Level?): ShipWorld? + + /** + * Potentially returns the globally unique [ServerShipWorld] if it exists. * - * @param level The [Level] to look for the ship in. If [level] is a - * [ServerLevel], this will return a [ServerShip]. If [level] is a - * [ClientLevel], this will return a [ClientShip]. + * This is not guaranteed to always work. Prefer to use + * `getServerShipWorld(MinecraftServer)` in almost all cases. * - * @param pos A block position in the Shipyard + * This will return null if no [ServerShipWorld] is currently loaded, or if + * multiple are loaded because multiple [MinecraftServer] are loaded. */ - fun getShipManagingBlock(level: Level?, pos: BlockPos?): Ship? + @Experimental + fun getServerShipWorld(): ServerShipWorld? - fun getShipManagingChunk(level: Level?, pos: ChunkPos?): Ship? + /** + * Potentially returns the globally unique [ClientShipWorld] if it exists. + * + * This is not guaranteed to always work. Prefer to use + * `getClientShipWorld(Minecraft)` in almost all cases. + * + * This will return null if no [ClientShipWorld] is currently loaded, or if + * multiple are loaded because multiple [Minecraft] are loaded. + */ + @Experimental + fun getClientShipWorld(): ClientShipWorld? + /** + * Returns true if the chunk is in the shipyard. + * + * If [level] is null, always returns false. + */ + fun isChunkInShipyard(level: Level?, chunkX: Int, chunkZ: Int): Boolean + + /** + * Returns the ship whose shipyard contains this chunk, if it exists and is + * in [level]. + * + * If [level] is a [ServerLevel], this will return a [ServerShip]. + * If [level] is a [ClientLevel], this will return a [ClientShip]. + * + * @param level The [Level] to look for the ship in. + */ fun getShipManagingChunk(level: Level?, chunkX: Int, chunkZ: Int): Ship? + + fun getShipManagingChunk(level: ClientLevel?, chunkX: Int, chunkZ: Int): ClientShip? + + fun getShipManagingChunk(level: ServerLevel?, chunkX: Int, chunkZ: Int): ServerShip? + + fun getShipsIntersecting(level: Level?, aabb: AABBdc?): Iterable + + fun getShipsIntersecting(level: Level?, x: Double, y: Double, z: Double): Iterable } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/api_impl/events/VsApiImpl.kt b/common/src/main/kotlin/org/valkyrienskies/mod/api_impl/events/VsApiImpl.kt index 3749d133e..ac81343a4 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/api_impl/events/VsApiImpl.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/api_impl/events/VsApiImpl.kt @@ -1,44 +1,99 @@ package org.valkyrienskies.mod.api_impl.events +import net.minecraft.client.Minecraft import net.minecraft.client.gui.screens.Screen -import net.minecraft.core.BlockPos +import net.minecraft.client.multiplayer.ClientLevel +import net.minecraft.server.MinecraftServer +import net.minecraft.server.level.ServerLevel import net.minecraft.world.entity.Entity -import net.minecraft.world.level.ChunkPos import net.minecraft.world.level.Level +import org.joml.Vector3dc +import org.joml.primitives.AABBd +import org.joml.primitives.AABBdc +import org.valkyrienskies.core.api.VsCoreApi +import org.valkyrienskies.core.api.ships.ClientShip +import org.valkyrienskies.core.api.ships.ServerShip import org.valkyrienskies.core.api.ships.Ship +import org.valkyrienskies.core.api.world.ClientShipWorld +import org.valkyrienskies.core.api.world.ServerShipWorld +import org.valkyrienskies.core.api.world.ShipWorld import org.valkyrienskies.core.util.events.EventEmitterImpl import org.valkyrienskies.mod.api.VsApi import org.valkyrienskies.mod.api.events.PostRenderShipEvent import org.valkyrienskies.mod.api.events.PreRenderShipEvent import org.valkyrienskies.mod.api.events.RegisterBlockStateEvent -import org.valkyrienskies.mod.common.entity.ShipMountingEntity +import org.valkyrienskies.mod.common.IShipObjectWorldClientProvider +import org.valkyrienskies.mod.common.IShipObjectWorldServerProvider +import org.valkyrienskies.mod.common.ValkyrienSkiesMod +import org.valkyrienskies.mod.common.dimensionId import org.valkyrienskies.mod.common.getShipManagingPos +import org.valkyrienskies.mod.common.getShipMountedToData +import org.valkyrienskies.mod.common.getShipObjectManagingPos +import org.valkyrienskies.mod.common.getShipsIntersecting import org.valkyrienskies.mod.compat.clothconfig.VSClothConfig -class VsApiImpl : VsApi { +@Suppress("OVERRIDE_DEPRECATION") +class VsApiImpl( + private val core: VsCoreApi +) : VsApi, VsCoreApi by core { override val registerBlockStateEvent = EventEmitterImpl() override val preRenderShipEvent = EventEmitterImpl() override val postRenderShipEvent = EventEmitterImpl() - override fun isShipMountingEntity(entity: Entity): Boolean { - return entity is ShipMountingEntity - } + override fun createConfigScreenLegacy(parent: Screen, vararg configs: Class<*>): Screen + = VSClothConfig.createConfigScreenFor(parent, *configs) - override fun createConfigScreenLegacy(parent: Screen, vararg configs: Class<*>): Screen { - return VSClothConfig.createConfigScreenFor(parent, *configs) - } + override fun getDimensionId(level: Level): String = + level.dimensionId + override fun getShipMountedTo(entity: Entity?): Ship? = + entity?.let { org.valkyrienskies.mod.common.getShipMountedTo(it) } - override fun getShipManagingBlock(level: Level?, pos: BlockPos?): Ship? { - return pos?.let { level?.getShipManagingPos(it) } - } + override fun getMountPosInShip(entity: Entity?): Vector3dc? = + entity?.let { getShipMountedToData(it) }?.mountPosInShip + + override fun getMountPosInShip(entity: Entity?, partialTicks: Float): Vector3dc? = + entity?.let { getShipMountedToData(it, partialTicks) }?.mountPosInShip + + override fun getServerShipWorld(): ServerShipWorld? = + getServerShipWorld(ValkyrienSkiesMod.currentServer) + + override fun getServerShipWorld(server: MinecraftServer?): ServerShipWorld? = + (server as IShipObjectWorldServerProvider?)?.shipObjectWorld + + override fun getClientShipWorld(): ClientShipWorld? = + getClientShipWorld(Minecraft.getInstance()) - override fun getShipManagingChunk(level: Level?, pos: ChunkPos?): Ship? { - return pos?.let { level?.getShipManagingPos(it) } + override fun getShipWorld(level: Level?): ShipWorld? = + when (level) { + is ServerLevel -> getServerShipWorld(level.server) + is ClientLevel -> getClientShipWorld() + else -> null + } + + override fun isChunkInShipyard(level: Level?, chunkX: Int, chunkZ: Int): Boolean { + if (level == null) return false + return getShipWorld(level)?.isChunkInShipyard(chunkX, chunkZ, getDimensionId(level)) ?: false } - override fun getShipManagingChunk(level: Level?, chunkX: Int, chunkZ: Int): Ship? { - return level?.getShipManagingPos(chunkX, chunkZ) + override fun getClientShipWorld(client: Minecraft?): ClientShipWorld? = + (client as IShipObjectWorldClientProvider?)?.shipObjectWorld + + override fun getShipManagingChunk(level: Level?, chunkX: Int, chunkZ: Int): Ship? = + level?.getShipManagingPos(chunkX, chunkZ) + + override fun getShipManagingChunk(level: ClientLevel?, chunkX: Int, chunkZ: Int): ClientShip? = + level?.getShipObjectManagingPos(chunkX, chunkZ) + + override fun getShipManagingChunk(level: ServerLevel?, chunkX: Int, chunkZ: Int): ServerShip? = + level?.getShipObjectManagingPos(chunkX, chunkZ) + + override fun getShipsIntersecting(level: Level?, aabb: AABBdc?): Iterable { + if (level == null || aabb == null) return emptyList() + return level.getShipsIntersecting(aabb) } + + override fun getShipsIntersecting(level: Level?, x: Double, y: Double, z: Double): Iterable = + getShipsIntersecting(level, AABBd(x, y, z, x, y, z)) } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/BlockStateInfoProvider.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/BlockStateInfoProvider.kt index 48c4255ff..f513162e5 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/BlockStateInfoProvider.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/BlockStateInfoProvider.kt @@ -11,8 +11,8 @@ import net.minecraft.server.level.ServerLevel import net.minecraft.world.level.Level import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.state.BlockState +import org.valkyrienskies.core.api.VsBeta import org.valkyrienskies.core.api.ships.Wing -import org.valkyrienskies.core.api.ships.WingManager import org.valkyrienskies.core.apigame.world.chunks.BlockType import org.valkyrienskies.mod.common.block.WingBlock import org.valkyrienskies.mod.common.config.MassDatapackResolver @@ -98,6 +98,7 @@ object BlockStateInfo { fun onSetBlock(level: Level, blockPos: BlockPos, prevBlockState: BlockState, newBlockState: BlockState) = onSetBlock(level, blockPos.x, blockPos.y, blockPos.z, prevBlockState, newBlockState) + @OptIn(VsBeta::class) fun onSetBlock(level: Level, x: Int, y: Int, z: Int, prevBlockState: BlockState, newBlockState: BlockState) { if (!::SORTED_REGISTRY.isInitialized) return @@ -110,8 +111,8 @@ object BlockStateInfo { // region Inject wings if (level is ServerLevel) { val loadedShip = level.getShipObjectManagingPos(x shr 4, z shr 4) - if (loadedShip != null) { - val wingManager = loadedShip.getAttachment(WingManager::class.java)!! + val wingManager = loadedShip?.wingManager + if (loadedShip != null && wingManager != null) { val wasOldBlockWing = prevBlockState.block is WingBlock val newBlockStateBlock = newBlockState.block val newWing: Wing? = diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt index e6969a25f..2cc95d81a 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt @@ -38,6 +38,8 @@ import org.valkyrienskies.core.apigame.world.properties.DimensionId import org.valkyrienskies.core.game.ships.ShipObjectServer import org.valkyrienskies.core.impl.hooks.VSEvents.TickEndEvent import org.valkyrienskies.core.util.expand +import org.valkyrienskies.mod.api.getShipsIntersecting +import org.valkyrienskies.mod.api.toWorld import org.valkyrienskies.mod.common.entity.ShipMountedToData import org.valkyrienskies.mod.common.entity.ShipMountedToDataProvider import org.valkyrienskies.mod.common.util.DimensionIdProvider @@ -322,24 +324,73 @@ fun ClientLevel?.transformRenderAABBToWorld(pos: Position, aabb: AABB): AABB { fun Entity?.getShipManaging(): Ship? = this?.let { this.level().getShipManagingPos(this.position()) } // Level +@Deprecated( + message = "Java: use ValkyrienSkies.getShipManagingChunk", + replaceWith = ReplaceWith( + "this.getShipManagingChunk(chunkX, chunkZ)", + "org.valkyrienskies.mod.api.getShipManagingChunk" + ) +) fun Level?.getShipManagingPos(chunkX: Int, chunkZ: Int) = getShipManagingPosImpl(this, chunkX, chunkZ) +@Deprecated( + message = "Java: use ValkyrienSkies.getShipManagingBlock", + replaceWith = ReplaceWith( + "this.getShipManagingBlock(blockPos)", + "org.valkyrienskies.mod.api.getShipManagingBlock" + ) +) fun Level?.getShipManagingPos(blockPos: BlockPos) = getShipManagingPos(blockPos.x shr 4, blockPos.z shr 4) +@Deprecated( + message = "Java: use ValkyrienSkies.getShipManagingBlock", + replaceWith = ReplaceWith( + "this.getShipManagingBlock(pos)", + "org.valkyrienskies.mod.api.getShipManagingBlock" + ) +) fun Level?.getShipManagingPos(pos: Position) = getShipManagingPos(pos.x().toInt() shr 4, pos.z().toInt() shr 4) +@Deprecated( + message = "Java: use ValkyrienSkies.getShipManagingBlock", + replaceWith = ReplaceWith( + "this.getShipManagingBlock(pos)", + "org.valkyrienskies.mod.api.getShipManagingBlock" + ) +) fun Level?.getShipManagingPos(pos: Vector3dc) = getShipManagingPos(pos.x().toInt() shr 4, pos.z().toInt() shr 4) +@Deprecated( + message = "Java: use ValkyrienSkies.getShipManagingBlock", + replaceWith = ReplaceWith( + "this.getShipManagingBlock(posX, posY, posZ)", + "org.valkyrienskies.mod.api.getShipManagingBlock" + ) +) fun Level?.getShipManagingPos(posX: Double, posY: Double, posZ: Double) = getShipManagingPos(posX.toInt() shr 4, posZ.toInt() shr 4) +@Deprecated( + message = "Java: use ValkyrienSkies.getShipManagingBlock", + replaceWith = ReplaceWith( + "this.getShipManagingBlock(chunkPos)", + "org.valkyrienskies.mod.api.getShipManagingBlock" + ) +) fun Level?.getShipManagingPos(posX: Float, posY: Float, posZ: Float) = getShipManagingPos(posX.toInt() shr 4, posZ.toInt() shr 4) +@Deprecated( + message = "Java: use ValkyrienSkies.getShipManagingChunk", + replaceWith = ReplaceWith( + "this.getShipManagingChunk(chunkPos)", + "org.valkyrienskies.mod.api.getShipManagingChunk" + ) +) fun Level?.getShipManagingPos(chunkPos: ChunkPos) = getShipManagingPos(chunkPos.x, chunkPos.z) @@ -415,19 +466,7 @@ fun Level.getShipsIntersecting(aabb: AABB): Iterable = getShipsIntersectin fun Level.getShipsIntersecting(aabb: AABBdc): Iterable = allShips.getIntersecting(aabb, dimensionId) fun Level?.transformAabbToWorld(aabb: AABB): AABB = transformAabbToWorld(aabb.toJOML()).toMinecraft() fun Level?.transformAabbToWorld(aabb: AABBd) = this?.transformAabbToWorld(aabb, aabb) ?: aabb -fun Level?.transformAabbToWorld(aabb: AABBdc, dest: AABBd): AABBd { - val ship1 = getShipManagingPos(aabb.minX(), aabb.minY(), aabb.minZ()) - ?: return dest.set(aabb) - val ship2 = getShipManagingPos(aabb.maxX(), aabb.maxY(), aabb.maxZ()) - ?: return dest.set(aabb) - - // if both endpoints of the aabb are in the same ship, do the transform - if (ship1.id == ship2.id) { - return aabb.transform(ship1.shipToWorld, dest) - } - - return dest.set(aabb) -} +fun Level?.transformAabbToWorld(aabb: AABBdc, dest: AABBd): AABBd = this.toWorld(aabb, dest) /** * Execute [runnable] immediately iff the thread invoking this is the same as the game thread. diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/ValkyrienSkiesMod.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/ValkyrienSkiesMod.kt index 9d92e71f2..383aa5d0f 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/ValkyrienSkiesMod.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/ValkyrienSkiesMod.kt @@ -45,8 +45,14 @@ object ValkyrienSkiesMod { val VS_CREATIVE_TAB = ResourceKey.create(Registries.CREATIVE_MODE_TAB, ResourceLocation("valkyrienskies")) + /** + * Keeps track of the MinecraftServers which have been created and run. Hopefully this contains at most one + * server... + */ + private val currentServers = mutableListOf() + @JvmStatic - var currentServer: MinecraftServer? = null + val currentServer: MinecraftServer? get() = currentServers.lastOrNull() @JvmStatic lateinit var vsCore: VSCore @@ -55,11 +61,27 @@ object ValkyrienSkiesMod { val vsCoreClient get() = vsCore as VSCoreClient @JvmStatic - val api = VsApiImpl() + val api by lazy { + VsApiImpl(vsCore) + } @JvmStatic lateinit var splitHandler: SplitHandler + @JvmStatic + fun addServer(server: MinecraftServer?) { + if (server != null) { + currentServers.add(server) + } + } + + @JvmStatic + fun removeServer(server: MinecraftServer?) { + if (server != null) { + currentServers.remove(server) + } + } + fun init(core: VSCore) { this.vsCore = core @@ -68,6 +90,12 @@ object ValkyrienSkiesMod { VSGamePackets.registerHandlers() core.registerConfigLegacy("vs", VSGameConfig::class.java) + core.registerAttachment(GameTickForceApplier::class.java) { + useLegacySerializer() + } + core.registerAttachment(SplittingDisablerAttachment::class.java) { + useLegacySerializer() + } splitHandler = SplitHandler(this.vsCore.hooks.enableBlockEdgeConnectivity, this.vsCore.hooks.enableBlockCornerConnectivity) diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/SeamlessChunksManager.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/SeamlessChunksManager.kt index f79def783..2a61a4229 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/SeamlessChunksManager.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/SeamlessChunksManager.kt @@ -13,11 +13,11 @@ import org.valkyrienskies.core.api.ships.ClientShip import org.valkyrienskies.core.api.ships.properties.ChunkClaim import org.valkyrienskies.core.impl.hooks.VSEvents.ShipLoadEventClient import org.valkyrienskies.core.util.pollUntilEmpty +import org.valkyrienskies.mod.api.toChunkPos import org.valkyrienskies.mod.common.getShipManagingPos import org.valkyrienskies.mod.common.isChunkInShipyard import org.valkyrienskies.mod.common.networking.PacketRestartChunkUpdates import org.valkyrienskies.mod.common.networking.PacketStopChunkUpdates -import org.valkyrienskies.mod.common.util.toMinecraft import org.valkyrienskies.mod.common.vsCore import org.valkyrienskies.mod.mixinducks.feature.seamless_copy.SeamlessCopyClientPacketListenerDuck import org.valkyrienskies.mod.util.logger @@ -45,7 +45,7 @@ class SeamlessChunksManager(private val listener: ClientPacketListener) { init { with(vsCore.simplePacketNetworking) { PacketStopChunkUpdates::class.registerClientHandler { (chunks) -> - chunks.forEach { stalledChunks.add(it.toMinecraft().toLong()) } + chunks.forEach { stalledChunks.add(it.toChunkPos().toLong()) } } PacketRestartChunkUpdates::class.registerClientHandler { packet -> Minecraft.getInstance().execute { @@ -71,7 +71,7 @@ class SeamlessChunksManager(private val listener: ClientPacketListener) { val (chunks) = packet chunks.forEach { p -> - val pos = p.toMinecraft() + val pos = p.toChunkPos() stalledChunks.remove(pos.toLong()) val packets = queuedUpdates.remove(pos) if (!packets.isNullOrEmpty()) { diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/ShipAssembler.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/ShipAssembler.kt index 6ee1d6579..986c6ca21 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/ShipAssembler.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/ShipAssembler.kt @@ -7,9 +7,9 @@ import net.minecraft.world.level.block.state.BlockState import org.joml.Vector3d import org.joml.Vector3i import org.joml.Vector3ic +import org.valkyrienskies.core.api.attachment.getAttachment import org.valkyrienskies.core.api.ships.ServerShip import org.valkyrienskies.core.api.ships.Ship -import org.valkyrienskies.core.api.ships.getAttachment import org.valkyrienskies.core.impl.game.ShipTeleportDataImpl import org.valkyrienskies.mod.common.BlockStateInfo.onSetBlock import org.valkyrienskies.mod.common.dimensionId @@ -74,7 +74,6 @@ object ShipAssembler { if (shouldDisableSplitting) { level.shipObjectWorld.loadedShips.getById(newShip.id)?.getAttachment()?.disableSplitting() - } val contraptionShipPos = newShip.worldToShip.transformPosition(Vector3d(contraptionWorldPos.x.toDouble(),contraptionWorldPos.y.toDouble(),contraptionWorldPos.z.toDouble())) diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/block/TestHingeBlock.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/block/TestHingeBlock.kt index b2cf03379..0ecc7b122 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/block/TestHingeBlock.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/block/TestHingeBlock.kt @@ -7,7 +7,6 @@ import net.minecraft.core.Direction.NORTH import net.minecraft.core.Direction.SOUTH import net.minecraft.core.Direction.UP import net.minecraft.core.Direction.WEST -import net.minecraft.server.level.ServerLevel import net.minecraft.world.InteractionHand import net.minecraft.world.InteractionResult import net.minecraft.world.entity.player.Player @@ -15,7 +14,6 @@ import net.minecraft.world.item.context.BlockPlaceContext import net.minecraft.world.level.BlockGetter import net.minecraft.world.level.Level import net.minecraft.world.level.block.Block -import net.minecraft.world.level.block.Blocks import net.minecraft.world.level.block.DirectionalBlock import net.minecraft.world.level.block.EntityBlock import net.minecraft.world.level.block.SoundType @@ -27,22 +25,7 @@ import net.minecraft.world.level.block.state.StateDefinition import net.minecraft.world.phys.BlockHitResult import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape -import org.joml.AxisAngle4d -import org.joml.Quaterniond -import org.joml.Quaterniondc -import org.joml.Vector3d -import org.joml.Vector3dc -import org.valkyrienskies.core.apigame.constraints.VSAttachmentConstraint -import org.valkyrienskies.core.apigame.constraints.VSHingeOrientationConstraint -import org.valkyrienskies.core.impl.game.ships.ShipDataCommon -import org.valkyrienskies.core.impl.game.ships.ShipTransformImpl -import org.valkyrienskies.mod.common.ValkyrienSkiesMod import org.valkyrienskies.mod.common.blockentity.TestHingeBlockEntity -import org.valkyrienskies.mod.common.dimensionId -import org.valkyrienskies.mod.common.getShipManagingPos -import org.valkyrienskies.mod.common.shipObjectWorld -import org.valkyrienskies.mod.common.util.toJOML -import kotlin.math.roundToInt object TestHingeBlock : DirectionalBlock( @@ -107,139 +90,139 @@ object TestHingeBlock : hand: InteractionHand, blockHitResult: BlockHitResult ): InteractionResult { - if (level.isClientSide) return InteractionResult.SUCCESS - - val blockEntity = level.getBlockEntity(pos, ValkyrienSkiesMod.TEST_HINGE_BLOCK_ENTITY_TYPE) - - if (blockEntity.isPresent) { - if (blockEntity.get().otherHingePos == null) { - // The ship that owns [pos] - val shipThisIsIn = level.getShipManagingPos(pos) - - // Create an empty ship - val ship = (level as ServerLevel).shipObjectWorld.createNewShipAtBlock( - pos.offset(0, 1, 0).toJOML(), false, 1.0, level.dimensionId - ) - val shipCenterPos = BlockPos( - (ship.transform.positionInShip.x() - 0.5).roundToInt(), - (ship.transform.positionInShip.y() - 0.5).roundToInt(), - (ship.transform.positionInShip.z() - 0.5).roundToInt() - ) - - // Extra height added to the hinge to keep the top ship slightly above the bottom ship - val extraHeight = 0.0 - - // The rotation we apply to different face values. The code below is set up to create Y-hinges by - // default, and [rotationQuaternion] converts them to other types of hinges - val rotationQuaternion: Quaterniondc - when (state.getValue(FACING)) { - DOWN -> { - rotationQuaternion = Quaterniond(AxisAngle4d(Math.PI, Vector3d(1.0, 0.0, 0.0))) - } - NORTH -> { - rotationQuaternion = Quaterniond(AxisAngle4d(Math.PI, Vector3d(0.0, 1.0, 0.0))).mul(Quaterniond(AxisAngle4d(Math.PI / 2.0, Vector3d(1.0, 0.0, 0.0)))).normalize() - } - EAST -> { - rotationQuaternion = Quaterniond(AxisAngle4d(0.5 * Math.PI, Vector3d(0.0, 1.0, 0.0))).mul(Quaterniond(AxisAngle4d(Math.PI / 2.0, Vector3d(1.0, 0.0, 0.0)))).normalize() - } - SOUTH -> { - rotationQuaternion = Quaterniond(AxisAngle4d(Math.PI / 2.0, Vector3d(1.0, 0.0, 0.0))).normalize() - } - WEST -> { - rotationQuaternion = Quaterniond(AxisAngle4d(1.5 * Math.PI, Vector3d(0.0, 1.0, 0.0))).mul(Quaterniond(AxisAngle4d(Math.PI / 2.0, Vector3d(1.0, 0.0, 0.0)))).normalize() - } - UP -> { - // Do nothing - rotationQuaternion = Quaterniond() - } - else -> { - // This should be impossible, but have this here just in case - rotationQuaternion = Quaterniond() - } - } - - // The positions the hinge attaches relative to the center of mass - val attachmentOffset0: Vector3dc = rotationQuaternion.transform(Vector3d(0.0, 0.5 + extraHeight, 0.0)) - val attachmentOffset1: Vector3dc = rotationQuaternion.transform(Vector3d(0.0, -0.5, 0.0)) - - val attachmentLocalPos0: Vector3dc = Vector3d(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5).add(attachmentOffset0) - val attachmentLocalPos1: Vector3dc = - Vector3d(shipCenterPos.x + 0.5, shipCenterPos.y + 0.5, shipCenterPos.z + 0.5).add(attachmentOffset1) - - // Move [ship] if we are on a ship - if (shipThisIsIn != null) { - // Put the new ship where the old ship is - val newPos = shipThisIsIn.transform.shipToWorld.transformPosition(attachmentLocalPos0, Vector3d()) - newPos.sub(shipThisIsIn.transform.shipToWorldRotation.transform(attachmentOffset1, Vector3d())) - val newTransform = ShipTransformImpl( - newPos, - ship.transform.positionInShip, - shipThisIsIn.transform.shipToWorldRotation, // Copy source ship rotation - ship.transform.shipToWorldScaling - ) - // Update the ship transform - (ship as ShipDataCommon).transform = newTransform - } else { - val newPos = Vector3d(attachmentLocalPos0) - newPos.sub(attachmentOffset1) - val newTransform = ShipTransformImpl( - newPos, - ship.transform.positionInShip, - ship.transform.shipToWorldRotation, - ship.transform.shipToWorldScaling - ) - // Update the ship transform - (ship as ShipDataCommon).transform = newTransform - } - - level.setBlockAndUpdate(shipCenterPos, Blocks.IRON_BLOCK.defaultBlockState()) - blockEntity.get().otherHingePos = shipCenterPos - - val shipId0 = shipThisIsIn?.id ?: level.shipObjectWorld.dimensionToGroundBodyIdImmutable[level.dimensionId]!! - val shipId1 = ship.id - - // Attachment constraint - run { - // I don't recommend setting compliance lower than 1e-10 because it tends to cause instability - // TODO: Investigate why small compliance cause instability - val attachmentCompliance = 1e-10 - val attachmentMaxForce = 1e10 - val attachmentFixedDistance = 0.0 - val attachmentConstraint = VSAttachmentConstraint( - shipId0, shipId1, attachmentCompliance, attachmentLocalPos0, attachmentLocalPos1, - attachmentMaxForce, attachmentFixedDistance - ) - blockEntity.get().constraintId = level.shipObjectWorld.createNewConstraint(attachmentConstraint) - } - - // Hinge constraints will attempt to align the X-axes of both bodies, so to align the Y axis we - // apply this rotation to the X-axis - val hingeOrientation = rotationQuaternion.mul(Quaterniond(AxisAngle4d(Math.toRadians(90.0), 0.0, 0.0, 1.0)), Quaterniond()).normalize() - - // Hinge orientation constraint - run { - // I don't recommend setting compliance lower than 1e-10 because it tends to cause instability - val hingeOrientationCompliance = 1e-10 - val hingeMaxTorque = 1e10 - val hingeConstraint = VSHingeOrientationConstraint( - shipId0, shipId1, hingeOrientationCompliance, hingeOrientation, hingeOrientation, hingeMaxTorque - ) - blockEntity.get().constraintId = level.shipObjectWorld.createNewConstraint(hingeConstraint) - } - - // Add position damping to make the hinge more stable - // val posDampingConstraint = VSPosDampingConstraint(shipId0, shipId1, 1e-10, attachmentLocalPos0, attachmentLocalPos1, 1e10, 1e-2) - // blockEntity.get().constraintId = level.shipObjectWorld.createNewConstraint(posDampingConstraint) - - // Add perpendicular rotation damping to make the hinge more stable - // val perpendicularRotDampingConstraint = VSRotDampingConstraint(shipId0, shipId1, 1e-10, hingeOrientation, hingeOrientation, 1e10, 1e-2, ALL_AXES) - // blockEntity.get().constraintId = level.shipObjectWorld.createNewConstraint(perpendicularRotDampingConstraint) - - // Add parallel rotation damping to prevent the hinge from spinning forever - // val parallelRotDampingConstraint = VSRotDampingConstraint(shipId0, shipId1, 0.0, hingeOrientation, hingeOrientation, 1e10, 1e-1, PARALLEL) - // blockEntity.get().constraintId = level.shipObjectWorld.createNewConstraint(parallelRotDampingConstraint) - } - } + // if (level.isClientSide) return InteractionResult.SUCCESS + // + // val blockEntity = level.getBlockEntity(pos, ValkyrienSkiesMod.TEST_HINGE_BLOCK_ENTITY_TYPE) + // + // if (blockEntity.isPresent) { + // if (blockEntity.get().otherHingePos == null) { + // // The ship that owns [pos] + // val shipThisIsIn = level.getShipManagingPos(pos) + // + // // Create an empty ship + // val ship = (level as ServerLevel).shipObjectWorld.createNewShipAtBlock( + // pos.offset(0, 1, 0).toJOML(), false, 1.0, level.dimensionId + // ) + // val shipCenterPos = BlockPos( + // (ship.transform.positionInShip.x() - 0.5).roundToInt(), + // (ship.transform.positionInShip.y() - 0.5).roundToInt(), + // (ship.transform.positionInShip.z() - 0.5).roundToInt() + // ) + // + // // Extra height added to the hinge to keep the top ship slightly above the bottom ship + // val extraHeight = 0.0 + // + // // The rotation we apply to different face values. The code below is set up to create Y-hinges by + // // default, and [rotationQuaternion] converts them to other types of hinges + // val rotationQuaternion: Quaterniondc + // when (state.getValue(FACING)) { + // DOWN -> { + // rotationQuaternion = Quaterniond(AxisAngle4d(Math.PI, Vector3d(1.0, 0.0, 0.0))) + // } + // NORTH -> { + // rotationQuaternion = Quaterniond(AxisAngle4d(Math.PI, Vector3d(0.0, 1.0, 0.0))).mul(Quaterniond(AxisAngle4d(Math.PI / 2.0, Vector3d(1.0, 0.0, 0.0)))).normalize() + // } + // EAST -> { + // rotationQuaternion = Quaterniond(AxisAngle4d(0.5 * Math.PI, Vector3d(0.0, 1.0, 0.0))).mul(Quaterniond(AxisAngle4d(Math.PI / 2.0, Vector3d(1.0, 0.0, 0.0)))).normalize() + // } + // SOUTH -> { + // rotationQuaternion = Quaterniond(AxisAngle4d(Math.PI / 2.0, Vector3d(1.0, 0.0, 0.0))).normalize() + // } + // WEST -> { + // rotationQuaternion = Quaterniond(AxisAngle4d(1.5 * Math.PI, Vector3d(0.0, 1.0, 0.0))).mul(Quaterniond(AxisAngle4d(Math.PI / 2.0, Vector3d(1.0, 0.0, 0.0)))).normalize() + // } + // UP -> { + // // Do nothing + // rotationQuaternion = Quaterniond() + // } + // else -> { + // // This should be impossible, but have this here just in case + // rotationQuaternion = Quaterniond() + // } + // } + // + // // The positions the hinge attaches relative to the center of mass + // val attachmentOffset0: Vector3dc = rotationQuaternion.transform(Vector3d(0.0, 0.5 + extraHeight, 0.0)) + // val attachmentOffset1: Vector3dc = rotationQuaternion.transform(Vector3d(0.0, -0.5, 0.0)) + // + // val attachmentLocalPos0: Vector3dc = Vector3d(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5).add(attachmentOffset0) + // val attachmentLocalPos1: Vector3dc = + // Vector3d(shipCenterPos.x + 0.5, shipCenterPos.y + 0.5, shipCenterPos.z + 0.5).add(attachmentOffset1) + // + // // Move [ship] if we are on a ship + // if (shipThisIsIn != null) { + // // Put the new ship where the old ship is + // val newPos = shipThisIsIn.transform.shipToWorld.transformPosition(attachmentLocalPos0, Vector3d()) + // newPos.sub(shipThisIsIn.transform.shipToWorldRotation.transform(attachmentOffset1, Vector3d())) + // val newTransform = ShipTransformImpl( + // newPos, + // ship.transform.positionInShip, + // shipThisIsIn.transform.shipToWorldRotation, // Copy source ship rotation + // ship.transform.shipToWorldScaling + // ) + // // Update the ship transform + // (ship as ShipDataCommon).setFromTransform(newTransform) + // } else { + // val newPos = Vector3d(attachmentLocalPos0) + // newPos.sub(attachmentOffset1) + // val newTransform = ShipTransformImpl( + // newPos, + // ship.transform.positionInShip, + // ship.transform.shipToWorldRotation, + // ship.transform.shipToWorldScaling + // ) + // // Update the ship transform + // (ship as ShipDataCommon).setFromTransform(newTransform) + // } + // + // level.setBlockAndUpdate(shipCenterPos, Blocks.IRON_BLOCK.defaultBlockState()) + // blockEntity.get().otherHingePos = shipCenterPos + // + // val shipId0 = shipThisIsIn?.id ?: level.shipObjectWorld.dimensionToGroundBodyIdImmutable[level.dimensionId]!! + // val shipId1 = ship.id + // + // // Attachment constraint + // run { + // // I don't recommend setting compliance lower than 1e-10 because it tends to cause instability + // // TODO: Investigate why small compliance cause instability + // val attachmentCompliance = 1e-10 + // val attachmentMaxForce = 1e10 + // val attachmentFixedDistance = 0.0 + // val attachmentConstraint = VSAttachmentConstraint( + // shipId0, shipId1, attachmentCompliance, attachmentLocalPos0, attachmentLocalPos1, + // attachmentMaxForce, attachmentFixedDistance + // ) + // blockEntity.get().constraintId = level.shipObjectWorld.createNewConstraint(attachmentConstraint) + // } + // + // // Hinge constraints will attempt to align the X-axes of both bodies, so to align the Y axis we + // // apply this rotation to the X-axis + // val hingeOrientation = rotationQuaternion.mul(Quaterniond(AxisAngle4d(Math.toRadians(90.0), 0.0, 0.0, 1.0)), Quaterniond()).normalize() + // + // // Hinge orientation constraint + // run { + // // I don't recommend setting compliance lower than 1e-10 because it tends to cause instability + // val hingeOrientationCompliance = 1e-10 + // val hingeMaxTorque = 1e10 + // val hingeConstraint = VSHingeOrientationConstraint( + // shipId0, shipId1, hingeOrientationCompliance, hingeOrientation, hingeOrientation, hingeMaxTorque + // ) + // blockEntity.get().constraintId = level.shipObjectWorld.createNewConstraint(hingeConstraint) + // } + // + // // Add position damping to make the hinge more stable + // // val posDampingConstraint = VSPosDampingConstraint(shipId0, shipId1, 1e-10, attachmentLocalPos0, attachmentLocalPos1, 1e10, 1e-2) + // // blockEntity.get().constraintId = level.shipObjectWorld.createNewConstraint(posDampingConstraint) + // + // // Add perpendicular rotation damping to make the hinge more stable + // // val perpendicularRotDampingConstraint = VSRotDampingConstraint(shipId0, shipId1, 1e-10, hingeOrientation, hingeOrientation, 1e10, 1e-2, ALL_AXES) + // // blockEntity.get().constraintId = level.shipObjectWorld.createNewConstraint(perpendicularRotDampingConstraint) + // + // // Add parallel rotation damping to prevent the hinge from spinning forever + // // val parallelRotDampingConstraint = VSRotDampingConstraint(shipId0, shipId1, 0.0, hingeOrientation, hingeOrientation, 1e10, 1e-1, PARALLEL) + // // blockEntity.get().constraintId = level.shipObjectWorld.createNewConstraint(parallelRotDampingConstraint) + // } + // } return InteractionResult.CONSUME } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/blockentity/TestHingeBlockEntity.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/blockentity/TestHingeBlockEntity.kt index 19ba56f16..509c5b73c 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/blockentity/TestHingeBlockEntity.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/blockentity/TestHingeBlockEntity.kt @@ -3,14 +3,14 @@ package org.valkyrienskies.mod.common.blockentity import net.minecraft.core.BlockPos import net.minecraft.world.level.block.entity.BlockEntity import net.minecraft.world.level.block.state.BlockState -import org.valkyrienskies.core.apigame.constraints.VSConstraintId +// import org.valkyrienskies.core.apigame.constraints.VSConstraintId import org.valkyrienskies.mod.common.ValkyrienSkiesMod class TestHingeBlockEntity(blockPos: BlockPos, blockState: BlockState) : BlockEntity( ValkyrienSkiesMod.TEST_HINGE_BLOCK_ENTITY_TYPE, blockPos, blockState ) { var otherHingePos: BlockPos? = null - var constraintId: VSConstraintId? = null + // var constraintId: VSConstraintId? = null fun tick() { // println("Amogus") diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/config/VSMassDataLoader.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/config/VSMassDataLoader.kt index bca78d148..2e7cca2e7 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/config/VSMassDataLoader.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/config/VSMassDataLoader.kt @@ -375,10 +375,11 @@ object MassDatapackResolver : BlockStateInfoProvider { mcBlockStateToVs[blockState] = vsBlockState } + runRegisterBlockStateEvent() + registeredBlocks = true } - // TODO implement private fun runRegisterBlockStateEvent() { val event = RegisterBlockStateEventImpl() ValkyrienSkiesMod.api.registerBlockStateEvent.emit(event) diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/ShipMountingEntity.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/ShipMountingEntity.kt index 6889d8be9..35852203a 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/ShipMountingEntity.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/ShipMountingEntity.kt @@ -14,6 +14,7 @@ import org.joml.Vector3f import org.valkyrienskies.core.api.ships.LoadedServerShip import org.valkyrienskies.core.api.ships.setAttachment import org.valkyrienskies.mod.api.SeatedControllingPlayer +import org.valkyrienskies.mod.api.getShipManagingBlock import org.valkyrienskies.mod.common.config.VSKeyBindings import org.valkyrienskies.mod.common.getShipManagingPos import org.valkyrienskies.mod.common.getShipObjectManagingPos @@ -62,7 +63,7 @@ open class ShipMountingEntity(type: EntityType, level: Level // This is a partial fix for mounting ships that have been deleted // TODO: Make a full fix eventually override fun getDismountLocationForPassenger(livingEntity: LivingEntity): Vec3 { - if (level().isBlockInShipyard(position()) && level().getShipManagingPos(position()) == null) { + if (level().isBlockInShipyard(position()) && level().getShipManagingBlock(position()) == null) { // Don't teleport to the ship if we can't find the ship return livingEntity.position() } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/item/PhysicsEntityCreatorItem.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/item/PhysicsEntityCreatorItem.kt index d6f02bcc4..f362ab069 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/item/PhysicsEntityCreatorItem.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/item/PhysicsEntityCreatorItem.kt @@ -8,10 +8,10 @@ import net.minecraft.world.item.context.UseOnContext import org.joml.Quaterniond import org.joml.Vector3d import org.joml.Vector3dc -import org.valkyrienskies.core.apigame.constraints.VSAttachmentConstraint -import org.valkyrienskies.core.apigame.constraints.VSPosDampingConstraint -import org.valkyrienskies.core.apigame.constraints.VSRotDampingAxes -import org.valkyrienskies.core.apigame.constraints.VSRotDampingConstraint +// import org.valkyrienskies.core.apigame.constraints.VSAttachmentConstraint +// import org.valkyrienskies.core.apigame.constraints.VSPosDampingConstraint +// import org.valkyrienskies.core.apigame.constraints.VSRotDampingAxes +// import org.valkyrienskies.core.apigame.constraints.VSRotDampingConstraint import org.valkyrienskies.core.impl.game.ships.ShipTransformImpl.Companion import org.valkyrienskies.mod.common.ValkyrienSkiesMod import org.valkyrienskies.mod.common.dimensionId @@ -60,24 +60,24 @@ class PhysicsEntityCreatorItem( if (shipOn != null) { val attachCompliance = 1e-8 val attachMaxForce = 1e10 - // Attach the click position of the ship to the surface of the physics entity - val attachConstraint = VSAttachmentConstraint( - shipOn.id, physicsEntityData.shipId, attachCompliance, ctx.clickLocation.toJOML(), offsetInGlobal.mul(-1.0, Vector3d()), - attachMaxForce, 0.0 - ) - val posDampingConstraint = VSPosDampingConstraint( - shipOn.id, physicsEntityData.shipId, attachCompliance, ctx.clickLocation.toJOML(), offsetInGlobal.mul(-1.0, Vector3d()), - attachMaxForce, 0.1 - ) - val rotDampingConstraint = VSRotDampingConstraint( - shipOn.id, physicsEntityData.shipId, attachCompliance, shipOn.transform.shipToWorldRotation.invert( - Quaterniond() - ), - Quaterniond(), 1e10, 0.1, VSRotDampingAxes.ALL_AXES - ) - level.shipObjectWorld.createNewConstraint(attachConstraint) - level.shipObjectWorld.createNewConstraint(posDampingConstraint) - level.shipObjectWorld.createNewConstraint(rotDampingConstraint) + // // Attach the click position of the ship to the surface of the physics entity + // val attachConstraint = VSAttachmentConstraint( + // shipOn.id, physicsEntityData.shipId, attachCompliance, ctx.clickLocation.toJOML(), offsetInGlobal.mul(-1.0, Vector3d()), + // attachMaxForce, 0.0 + // ) + // val posDampingConstraint = VSPosDampingConstraint( + // shipOn.id, physicsEntityData.shipId, attachCompliance, ctx.clickLocation.toJOML(), offsetInGlobal.mul(-1.0, Vector3d()), + // attachMaxForce, 0.1 + // ) + // val rotDampingConstraint = VSRotDampingConstraint( + // shipOn.id, physicsEntityData.shipId, attachCompliance, shipOn.transform.shipToWorldRotation.invert( + // Quaterniond() + // ), + // Quaterniond(), 1e10, 0.1, VSRotDampingAxes.ALL_AXES + // ) + // level.shipObjectWorld.createNewConstraint(attachConstraint) + // level.shipObjectWorld.createNewConstraint(posDampingConstraint) + // level.shipObjectWorld.createNewConstraint(rotDampingConstraint) } } 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 b4ad34e82..fb6df6cd3 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 @@ -17,6 +17,7 @@ import org.valkyrienskies.mod.common.shipObjectWorld import org.valkyrienskies.mod.common.util.toBlockPos import org.valkyrienskies.mod.common.util.toJOML import org.valkyrienskies.mod.common.util.toJOMLD +import org.valkyrienskies.mod.common.vsCore import org.valkyrienskies.mod.common.yRange import org.valkyrienskies.mod.util.relocateBlock import java.util.function.DoubleSupplier @@ -63,9 +64,8 @@ class ShipCreatorItem( // Do not allow scaling to go below minScaling newShipScaling = Vector3d(minScaling, minScaling, minScaling) } - val shipTransform = - ShipTransformImpl(newShipPosInWorld, newShipPosInShipyard, newShipRotation, newShipScaling) - (serverShip as ShipDataCommon).transform = shipTransform + val shipTransform = vsCore.newShipTransform(newShipPosInWorld, newShipPosInShipyard, newShipRotation, newShipScaling) + (serverShip as ShipDataCommon).setFromTransform(shipTransform) } } } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/VSGamePackets.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/VSGamePackets.kt index db56b3466..8860e80dc 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/VSGamePackets.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/networking/VSGamePackets.kt @@ -3,9 +3,8 @@ package org.valkyrienskies.mod.common.networking import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer +import org.valkyrienskies.core.api.attachment.getAttachment import org.valkyrienskies.core.api.ships.LoadedServerShip -import org.valkyrienskies.core.api.ships.getAttachment -import org.valkyrienskies.core.api.ships.setAttachment import org.valkyrienskies.mod.api.SeatedControllingPlayer import org.valkyrienskies.mod.common.entity.ShipMountingEntity import org.valkyrienskies.mod.common.entity.handling.VSEntityManager diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/util/ShipSettings.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/util/ShipSettings.kt index be9f2f8c7..15b13f85e 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/util/ShipSettings.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/util/ShipSettings.kt @@ -1,8 +1,7 @@ package org.valkyrienskies.mod.common.util -import org.valkyrienskies.core.api.ships.ServerShip -import org.valkyrienskies.core.api.ships.getAttachment -import org.valkyrienskies.core.api.ships.saveAttachment +import org.valkyrienskies.core.api.attachment.getAttachment +import org.valkyrienskies.core.api.ships.LoadedServerShip /** * A attachment that stores ship specific settings. @@ -20,5 +19,5 @@ data class ShipSettings( var changeDimensionOnTouchPortals: Boolean = true ) -val ServerShip.settings: ShipSettings - get() = getAttachment() ?: ShipSettings().also { saveAttachment(it) } +val LoadedServerShip.settings: ShipSettings + get() = getAttachment() ?: ShipSettings().also { setAttachment(it) } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/util/SplitHandler.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/util/SplitHandler.kt index 48f34c8ee..996df19ef 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/util/SplitHandler.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/util/SplitHandler.kt @@ -6,7 +6,7 @@ import net.minecraft.server.level.ServerLevel import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import org.joml.primitives.AABBi -import org.valkyrienskies.core.api.ships.getAttachment +import org.valkyrienskies.core.api.attachment.getAttachment import org.valkyrienskies.core.api.world.connectivity.ConnectionStatus.CONNECTED import org.valkyrienskies.core.api.world.connectivity.ConnectionStatus.DISCONNECTED import org.valkyrienskies.core.util.expand diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/world/RaycastUtils.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/world/RaycastUtils.kt index 45ccfb945..2a4d81747 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/world/RaycastUtils.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/world/RaycastUtils.kt @@ -20,11 +20,12 @@ import org.joml.primitives.AABBd import org.joml.primitives.AABBdc import org.valkyrienskies.core.api.ships.ClientShip import org.valkyrienskies.core.api.ships.properties.ShipId -import org.valkyrienskies.core.game.ships.ShipObjectClient +import org.valkyrienskies.mod.api.ShipBlockHitResult +import org.valkyrienskies.mod.api.toJOML +import org.valkyrienskies.mod.api.toMinecraft +import org.valkyrienskies.mod.api.transformPosition import org.valkyrienskies.mod.common.getShipsIntersecting import org.valkyrienskies.mod.common.shipObjectWorld -import org.valkyrienskies.mod.common.util.toJOML -import org.valkyrienskies.mod.common.util.toMinecraft import org.valkyrienskies.mod.util.scale import java.util.function.BiFunction import java.util.function.Function @@ -49,7 +50,8 @@ fun Level.clipIncludeShips( var closestHit = vanillaHit var closestHitPos = vanillaHit.location var closestHitDist = closestHitPos.distanceToSqr(ctx.from) - + var closestHitIsInShip: Boolean = false + val clipAABB: AABBdc = AABBd(ctx.from.toJOML(), ctx.to.toJOML()).correctBounds() // Iterate every ship, find do the raycast in ship space, @@ -61,22 +63,35 @@ fun Level.clipIncludeShips( } val worldToShip = (ship as? ClientShip)?.renderTransform?.worldToShip ?: ship.worldToShip val shipToWorld = (ship as? ClientShip)?.renderTransform?.shipToWorld ?: ship.shipToWorld - val shipStart = worldToShip.transformPosition(ctx.from.toJOML()).toMinecraft() - val shipEnd = worldToShip.transformPosition(ctx.to.toJOML()).toMinecraft() + val shipStart = worldToShip.transformPosition(ctx.from) + val shipEnd = worldToShip.transformPosition(ctx.to) val shipHit = clip(ctx, shipStart, shipEnd) - val shipHitPos = shipToWorld.transformPosition(shipHit.location.toJOML()).toMinecraft() + val shipHitPos = shipToWorld.transformPosition(shipHit.location) val shipHitDist = shipHitPos.distanceToSqr(ctx.from) if (shipHitDist < closestHitDist && shipHit.type != HitResult.Type.MISS) { closestHit = shipHit closestHitPos = shipHitPos closestHitDist = shipHitDist + closestHitIsInShip = true } } - if (shouldTransformHitPos) { - closestHit.location = closestHitPos + if (closestHitIsInShip) { + val shipBlockHitResult = ShipBlockHitResult.create( + hitResult = closestHit, + locationInShip = closestHit.location, + locationInWorld = closestHitPos + ) + + if (shouldTransformHitPos) { + shipBlockHitResult.useLocationInWorld() + } else { + shipBlockHitResult.useLocationInShip() + } + + closestHit = shipBlockHitResult } return closestHit diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/compat/Weather2Compat.kt b/common/src/main/kotlin/org/valkyrienskies/mod/compat/Weather2Compat.kt index 816c3e920..73be914f9 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/compat/Weather2Compat.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/compat/Weather2Compat.kt @@ -2,7 +2,7 @@ package org.valkyrienskies.mod.compat import net.minecraft.server.level.ServerLevel import org.joml.Vector3d -import org.valkyrienskies.core.api.ships.getAttachment +import org.valkyrienskies.core.api.attachment.getAttachment import org.valkyrienskies.mod.common.config.VSGameConfig import org.valkyrienskies.mod.common.shipObjectWorld import org.valkyrienskies.mod.common.util.GameTickForceApplier @@ -22,7 +22,7 @@ object Weather2Compat { val vec = Vector3d() level.shipObjectWorld.loadedShips.forEach { ship -> - val forces = ship.getAttachment()!! + val forces = ship.getAttachment() ?: return@forEach val com = ship.inertiaData.centerOfMassInShip diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/util/VectorConversionsMC.kt b/common/src/main/kotlin/org/valkyrienskies/mod/util/VectorConversionsMC.kt index 0a9f1eb5a..f5b89811e 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/util/VectorConversionsMC.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/util/VectorConversionsMC.kt @@ -1,4 +1,5 @@ package org.valkyrienskies.mod.common.util + import com.mojang.blaze3d.vertex.PoseStack import net.minecraft.core.BlockPos import net.minecraft.core.Direction @@ -26,24 +27,56 @@ import org.joml.primitives.AABBdc // region JOML +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.set(). " + + "Remove the import org.valkyrienskies.mod.common.util.set", + replaceWith = ReplaceWith( + "this.set(v)", + "org.valkyrienskies.mod.api.set" + ) +) fun Vector3i.set(v: Vec3i) = also { x = v.x y = v.y z = v.z } +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.set(). " + + "Remove the import org.valkyrienskies.mod.common.util.set", + replaceWith = ReplaceWith( + "this.set(v)", + "org.valkyrienskies.mod.api.set" + ) +) fun Vector3d.set(v: Vec3i) = also { x = v.x.toDouble() y = v.y.toDouble() z = v.z.toDouble() } +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.set(). " + + "Remove the import org.valkyrienskies.mod.common.util.set", + replaceWith = ReplaceWith( + "this.set(v)", + "org.valkyrienskies.mod.api.set" + ) +) fun Vector3f.set(v: Vec3i) = also { x = v.x.toFloat() y = v.y.toFloat() z = v.z.toFloat() } +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.set(). " + + "Remove the import org.valkyrienskies.mod.common.util.set", + replaceWith = ReplaceWith( + "this.set(v)", + "org.valkyrienskies.mod.api.set" + ) +) fun Vector3d.set(v: Position) = also { x = v.x() y = v.y() @@ -52,6 +85,14 @@ fun Vector3d.set(v: Position) = also { fun Vec3i.toDoubles() = Vec3(x.toDouble(), y.toDouble(), z.toDouble()) +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.set(). " + + "Remove the import org.valkyrienskies.mod.common.util.set", + replaceWith = ReplaceWith( + "this.set(v)", + "org.valkyrienskies.mod.api.set" + ) +) fun AABBd.set(v: AABB) = also { minX = v.minX minY = v.minY @@ -61,37 +102,136 @@ fun AABBd.set(v: AABB) = also { maxZ = v.maxZ } +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toBlockPos(). " + + "Remove the import org.valkyrienskies.mod.common.util.toBlockPos", + replaceWith = ReplaceWith( + "this.toBlockPos()", + "org.valkyrienskies.mod.api.toBlockPos" + ) +) fun Vector3ic.toBlockPos() = BlockPos(x(), y(), z()) + +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toMinecraft(). " + + "Remove the import org.valkyrienskies.mod.common.util.toMinecraft", + replaceWith = ReplaceWith( + "this.toMinecraft()", + "org.valkyrienskies.mod.api.toMinecraft" + ) +) fun Vector3dc.toMinecraft() = Vec3(x(), y(), z()) fun Matrix4d.mul(m: Matrix4fc): Matrix4d = mul(m, this) +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toMinecraft(). " + + "Remove the import org.valkyrienskies.mod.common.util.toMinecraft", + replaceWith = ReplaceWith( + "this.toMinecraft()", + "org.valkyrienskies.mod.api.toMinecraft" + ) +) fun AABBdc.toMinecraft() = AABB(minX(), minY(), minZ(), maxX(), maxY(), maxZ()) + +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toJOML(). " + + "Remove the import org.valkyrienskies.mod.common.util.toJOML", + replaceWith = ReplaceWith( + "this.toJOML()", + "org.valkyrienskies.mod.api.toJOML" + ) +) fun AABB.toJOML() = AABBd().set(this) +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toChunkPos(). " + + "Remove the import org.valkyrienskies.mod.common.util.toChunkPos", + replaceWith = ReplaceWith( + "this.toChunkPos()", + "org.valkyrienskies.mod.api.toChunkPos" + ) +) fun Vector2ic.toMinecraft() = ChunkPos(x(), y()) + +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toJOML(). " + + "Remove the import org.valkyrienskies.mod.common.util.toJOML", + replaceWith = ReplaceWith( + "this.toJOML()", + "org.valkyrienskies.mod.api.toJOML" + ) +) fun ChunkPos.toJOML() = Vector2i().set(this) +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toJOML(). " + + "Remove the import org.valkyrienskies.mod.common.util.toJOML", + replaceWith = ReplaceWith( + "this.toJOML()", + "org.valkyrienskies.mod.api.toJOML" + ) +) fun Vec3.toJOML() = Vector3d().set(this) +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.set(). " + + "Remove the import org.valkyrienskies.mod.common.util.set", + replaceWith = ReplaceWith( + "this.set(v)", + "org.valkyrienskies.mod.api.set" + ) +) fun Vector3d.set(v: Vec3) = also { x = v.x y = v.y z = v.z } +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.set(). " + + "Remove the import org.valkyrienskies.mod.common.util.set", + replaceWith = ReplaceWith( + "this.set(pos)", + "org.valkyrienskies.mod.api.set" + ) +) fun Vector2i.set(pos: ChunkPos) = also { x = pos.x y = pos.z } +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.transformDirection(). " + + "Remove the import org.valkyrienskies.mod.common.util.transformDirection", + replaceWith = ReplaceWith( + "transformDirection(v, dest)", + "org.valkyrienskies.mod.api.transformDirection" + ) +) @JvmOverloads fun Matrix4dc.transformDirection(v: Vec3i, dest: Vector3d = Vector3d()) = transformDirection(dest.set(v.x.toDouble(), v.y.toDouble(), v.z.toDouble())) +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.transformDirection(). " + + "Remove the import org.valkyrienskies.mod.common.util.transformDirection", + replaceWith = ReplaceWith( + "transformDirection(dir, dest)", + "org.valkyrienskies.mod.api.transformDirection" + ) +) @JvmOverloads fun Matrix4dc.transformDirection(dir: Direction, dest: Vector3d = Vector3d()) = transformDirection(dir.normal, dest) +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.transform(). " + + "Remove the import org.valkyrienskies.mod.common.util.transform", + replaceWith = ReplaceWith( + "transform(v)", + "org.valkyrienskies.mod.api.transform" + ) +) fun Matrix4dc.transform(v: Vector4f) = v.also { it.set( (m00() * v.x() + m01() * v.y() + m02() * v.z() + m03() * v.w()).toFloat(), @@ -101,6 +241,14 @@ fun Matrix4dc.transform(v: Vector4f) = v.also { ) } +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.transformPosition(). " + + "Remove the import org.valkyrienskies.mod.common.util.transformPosition", + replaceWith = ReplaceWith( + "transformPosition(v)", + "org.valkyrienskies.mod.api.transformPosition" + ) +) fun Matrix4dc.transformPosition(v: Vec3): Vec3 { return transformPosition(v.toJOML()).toMinecraft() } @@ -109,6 +257,14 @@ fun Matrix4dc.transformPosition(v: Vec3): Vec3 { // region Minecraft +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.multiply(). " + + "Remove the import org.valkyrienskies.mod.common.util.multiply", + replaceWith = ReplaceWith( + "this.multiply(modelTransform, normalTransform)", + "org.valkyrienskies.mod.api.multiply" + ) +) fun PoseStack.multiply(modelTransform: Matrix4dc, normalTransform: Quaterniondc) = also { val last = last() @@ -119,17 +275,67 @@ fun PoseStack.multiply(modelTransform: Matrix4dc, normalTransform: Quaterniondc) last.normal().set(newNormal) } +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.multiply(). " + + "Remove the import org.valkyrienskies.mod.common.util.multiply", + replaceWith = ReplaceWith( + "this.multiply(modelTransform)", + "org.valkyrienskies.mod.api.multiply" + ) +) fun PoseStack.multiply(modelTransform: Matrix4dc) = also { val last = last() val newPose = Matrix4d().set(last.pose()).mul(modelTransform) last.pose().set(newPose) } +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toJOML(). " + + "Remove the import org.valkyrienskies.mod.common.util.toJOML", + replaceWith = ReplaceWith( + "this.toJOML()", + "org.valkyrienskies.mod.api.toJOML" + ) +) fun Vec3i.toJOML() = Vector3i().set(this) + +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toJOMLd(). " + + "Remove the import org.valkyrienskies.mod.common.util.toJOMLd", + replaceWith = ReplaceWith( + "this.toJOMLd()", + "org.valkyrienskies.mod.api.toJOMLd" + ) +) fun Vec3i.toJOMLD() = Vector3d().set(this) + +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toJOMLf(). " + + "Remove the import org.valkyrienskies.mod.common.util.toJOMLF", + replaceWith = ReplaceWith( + "this.toJOMLf()", + "org.valkyrienskies.mod.api.toJOMLf" + ) +) fun Vec3i.toJOMLF() = Vector3f().set(this) +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toJOML(). " + + "Remove the import org.valkyrienskies.mod.common.util.toJOML", + replaceWith = ReplaceWith( + "this.toJOML()", + "org.valkyrienskies.mod.api.toJOML" + ) +) fun Position.toJOML() = Vector3d().set(this) +@Deprecated( + message = "Moved. Java users switch to ValkyrienSkies.toFloat(). " + + "Remove the import org.valkyrienskies.mod.common.util.toFloat", + replaceWith = ReplaceWith( + "this.toFloat()", + "org.valkyrienskies.mod.api.toFloat" + ) +) fun Quaterniondc.toFloat() = Quaternionf(x(), y(), z(), w()) // endregion diff --git a/common/src/main/resources/valkyrienskies-common.mixins.json b/common/src/main/resources/valkyrienskies-common.mixins.json index fd9df3730..b8686d87f 100644 --- a/common/src/main/resources/valkyrienskies-common.mixins.json +++ b/common/src/main/resources/valkyrienskies-common.mixins.json @@ -57,6 +57,11 @@ "mod_compat.bluemap.MixinBmMap", "mod_compat.bluemap.MixinHiresModelManager", "mod_compat.bluemap.MixinWorld", + "mod_compat.cc_tweaked.MixinTurtleBrain", + "mod_compat.cc_tweaked.MixinTurtleMoveCommand", + "mod_compat.cc_tweaked.MixinWirelessModemPeripheral", + "mod_compat.cc_tweaked.MixinWirelessNetwork", + "mod_compat.cc_tweaked.MixinSpeakerSound", "mod_compat.create.IMixinDeployerHandler", "mod_compat.create.IMixinDeployerMovementBehaviour", "mod_compat.create.MixinAirCurrent", @@ -95,6 +100,7 @@ "mod_compat.create.pr.MixinSeatBlock", "mod_compat.create_big_cannons.MixinPitchOrientedContraptionEntity", "mod_compat.create_utilities.MixinVoidLinkBehaviour", + "mod_compat.ftb_chunks.MixinClaimedChunkManagerImpl", "mod_compat.immersive_portals.MixinIpNewChunkTrackingGraph", "mod_compat.reachentityattributes.MixinReachEntityAttributes", "server.MinecraftServerAccessor", @@ -127,7 +133,6 @@ "client.gui.screens.MixinConnectScreen", "client.multiplayer.MixinClientPacketListener", "client.player.MixinLocalPlayer", - "feature.huge_bounding_box_fix.MixinPlayer", "client.renderer.MixinGameRenderer", "client.renderer.MixinLevelRenderer", "client.world.MixinClientChunkCache", @@ -137,6 +142,7 @@ "feature.fix_render_chunk_sorting.MixinRenderChunk", "feature.fluid_camera_fix.MixinCamera", "feature.hit_outline.MixinLevelRenderer", + "feature.huge_bounding_box_fix.MixinPlayer", "feature.render_blockentity_distance_check.MixinBlockEntityRenderDispatcher", "feature.render_leashes.MixinMobRenderer", "feature.render_pathfinding.MixinDebugRenderer", @@ -151,6 +157,7 @@ "feature.transform_particles.MixinLevelRenderer", "feature.transform_particles.MixinParticle", "feature.vs2_alpha_hud.MixinGui", + "mod_compat.cc_tweaked.MixinSpeakerSound", "mod_compat.create.client.MixinAABBOutline", "mod_compat.create.client.MixinBlockClusterOutline", "mod_compat.create.client.MixinCarriageContraptionInstance", diff --git a/fabric/build.gradle b/fabric/build.gradle index ca1017bcb..6f901f162 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -73,9 +73,6 @@ dependencies { include("com.fasterxml:classmate:1.5.1") implementation("com.fasterxml:classmate:1.5.1") - // CC Restitched - modCompileOnly("maven.modrinth:cc-tweaked:${cc_tweaked_version}") - // EMF compat modCompileOnly("curse.maven:entity-model-features-844662:5696901") modCompileOnly("curse.maven:entity-texture-features-fabric-568563:5697084") diff --git a/fabric/gradle.properties b/fabric/gradle.properties index 9ad47341d..492f12d7c 100644 --- a/fabric/gradle.properties +++ b/fabric/gradle.properties @@ -25,9 +25,6 @@ no_indium_version=1.1.0+1.20 #https://modrinth.com/mod/sodium/versions sodium_version = mc1.20.1-0.5.8 -# https://modrinth.com/mod/cc-tweaked/version/Zoo9N9Dv -cc_tweaked_version = 1.113.1-fabric - kotlin_fabric_version = 1.10.10+kotlin.1.9.10 # https://modrinth.com/mod/indium/version/1.0.9+mc1.19.2 diff --git a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinSpeakerSound.java b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinSpeakerSound.java deleted file mode 100644 index fe62b1155..000000000 --- a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinSpeakerSound.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.valkyrienskies.mod.fabric.mixin.compat.cc_restitched; - -import dan200.computercraft.client.sound.SpeakerSound; -import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; -import net.minecraft.client.resources.sounds.AbstractSoundInstance; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.RandomSource; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.NotNull; -import org.joml.Vector3d; -import org.joml.Vector3dc; -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.CallbackInfo; -import org.valkyrienskies.core.api.ships.Ship; -import org.valkyrienskies.mod.client.audio.VelocityTickableSoundInstance; -import org.valkyrienskies.mod.common.VSGameUtilsKt; - -@Mixin(SpeakerSound.class) -public abstract class MixinSpeakerSound extends AbstractSoundInstance implements VelocityTickableSoundInstance { - @Unique private SpeakerPosition speakerPosition; - @Unique private Ship ship; - - protected MixinSpeakerSound(ResourceLocation arg, SoundSource arg2, RandomSource arg3) { - super(arg, arg2, arg3); - } - - @Inject( - method = "setPosition", - at = @At("RETURN"), - remap = false - ) - private void isOnShip(SpeakerPosition position, CallbackInfo ci) { - this.speakerPosition = position; - this.ship = VSGameUtilsKt.getShipManagingPos(position.level(), position.position()); - if (this.ship != null) { - Vec3 worldPos = VSGameUtilsKt.toWorldCoordinates(speakerPosition.level(), speakerPosition.position()); - x = worldPos.x; - y = worldPos.y; - z = worldPos.z; - } - } - - @Inject( - method = "tick", - at = @At("HEAD") - ) - private void updateWorldPos(CallbackInfo ci) { - if (this.ship != null) { - Vec3 worldPos = VSGameUtilsKt.toWorldCoordinates(speakerPosition.level(), speakerPosition.position()); - x = worldPos.x; - y = worldPos.y; - z = worldPos.z; - } - } - - @NotNull - @Override - public Vector3dc getVelocity() { - return ship != null ? ship.getVelocity() : new Vector3d(); - } -} diff --git a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinTurtleBrain.java b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinTurtleBrain.java deleted file mode 100644 index 881fa21f0..000000000 --- a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinTurtleBrain.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.valkyrienskies.mod.fabric.mixin.compat.cc_restitched; - -import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity; -import dan200.computercraft.shared.turtle.core.TurtleBrain; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Vec3i; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.joml.Matrix4dc; -import org.joml.Vector3d; -import org.joml.Vector3dc; -import org.joml.primitives.AABBic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Pseudo; -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.ModifyVariable; -import org.valkyrienskies.core.api.ships.Ship; -import org.valkyrienskies.mod.common.VSGameUtilsKt; -import org.valkyrienskies.mod.common.config.VSGameConfig; -import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; - -@Pseudo -@Mixin(TurtleBrain.class) -public abstract class MixinTurtleBrain { - @Shadow(remap = false) - public abstract TurtleBlockEntity getOwner(); - - @Shadow(remap = false) - public abstract void setOwner(TurtleBlockEntity owner); - - @Shadow - public abstract Level getLevel(); - - @ModifyVariable( - method = "teleportTo(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Z", - at = @At(value = "HEAD"), - index = 2, - argsOnly = true, - remap = false - ) - private BlockPos ValkyrienSkies2$teleportToBlockPos(final BlockPos pos) { - final TurtleBlockEntity currentOwner = getOwner(); - final BlockPos oldPos = currentOwner.getAccess().getPosition(); - final Level world = getLevel(); - - final Ship ship = VSGameUtilsKt.getShipManagingPos(world, oldPos); - if (ship != null) { - // THERE IS A SHIP - final Direction d = getNewDirection(ship, currentOwner.getDirection()); - if (!doesShipContainPoint(ship, pos)) { - // POSITION IS OUTSIDE THE SHIP'S AABB - - currentOwner.setDirection(d); - setOwner(currentOwner); - - if (!isShipScaled(ship)) { - // SHIP IS NOT SCALED - - return getWorldPosFromShipPos(ship, pos); - } else if (turtlesLeaveScaledShips()) { - // SHIP IS SCALED AND TURTLES CAN LEAVE SCALED SHIPS - - return getWorldPosFromShipPos(ship, pos); - } - } - } - return pos; - } - - // CUSTOM METHODS - - @Unique - private static Direction getNewDirection(final Ship ship, final Direction direction) { - final Matrix4dc matrix = ship.getShipToWorld(); - final Vec3i turtleDirectionVector = direction.getNormal(); - final Vector3d directionVec = - matrix.transformDirection(turtleDirectionVector.getX(), turtleDirectionVector.getY(), - turtleDirectionVector.getZ(), new Vector3d()); - final Direction dir = Direction.getNearest(directionVec.x, directionVec.y, directionVec.z); - - return dir; - } - - @Unique - private static boolean turtlesLeaveScaledShips() { - return VSGameConfig.SERVER.getComputerCraft().getCanTurtlesLeaveScaledShips(); - } - - @Unique - private static boolean isShipScaled(final Ship ship) { - final Vector3dc scale = ship.getTransform().getShipToWorldScaling(); - final Vector3dc normalScale = new Vector3d(1.000E+0, 1.000E+0, 1.000E+0); - return !scale.equals(normalScale); - } - - @Unique - private static boolean doesShipContainPoint(final Ship ship, final BlockPos pos) { - final AABBic shipAABB = ship.getShipAABB(); - - final AABB t = new AABB(shipAABB.maxX(), shipAABB.maxY(), shipAABB.maxZ(), shipAABB.minX(), shipAABB.minY(), - shipAABB.minZ()); - return t.intersects(new AABB(pos)); - } - - @Unique - private static BlockPos getWorldPosFromShipPos(final Ship ship, final BlockPos pos) { - final Vec3 tPos = VectorConversionsMCKt.toMinecraft( - VSGameUtilsKt.toWorldCoordinates(ship, pos.getX() + 0.5, pos.getY() + 0.5, - pos.getZ() + 0.5)); - final BlockPos newPos = BlockPos.containing(tPos); - return newPos; - } -} diff --git a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinTurtleMoveCommand.java b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinTurtleMoveCommand.java deleted file mode 100644 index c4d0e3bc9..000000000 --- a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinTurtleMoveCommand.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.valkyrienskies.mod.fabric.mixin.compat.cc_restitched; - -import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.shared.turtle.core.TurtleMoveCommand; -import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import java.util.List; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; -import org.joml.Vector3d; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Pseudo; -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 org.valkyrienskies.core.api.ships.Ship; -import org.valkyrienskies.mod.common.VSGameUtilsKt; - -@Pseudo -@Mixin(TurtleMoveCommand.class) -public abstract class MixinTurtleMoveCommand { - @Inject(method = "canEnter", at = @At("RETURN"), remap = false, cancellable = true) - private static void ValkyrienSkies2$canEnter( - final TurtlePlayer turtlePlayer, final ServerLevel world, final BlockPos position, final CallbackInfoReturnable cir) { - if (cir.getReturnValue().isSuccess()) { - final Ship ship = VSGameUtilsKt.getShipManagingPos(world, position); - if (ship == null) { - final Ship iShip = VSGameUtilsKt.getShipManagingPos(world, getShipPosFromWorldPos(world, position)); - if (iShip != null) { - cir.setReturnValue(TurtleCommandResult.failure("ship")); - } - } else { - final ChunkPos chunk = world.getChunkAt(position).getPos(); - if (!ship.getChunkClaim().contains(chunk.x, chunk.z)) { - cir.setReturnValue(TurtleCommandResult.failure("out of ship")); - } - } - } - } - - //CUSTOM METHODS - @Unique - private static Vector3d getShipPosFromWorldPos(final Level world, final BlockPos position) { - final List detectedShips = - VSGameUtilsKt.transformToNearbyShipsAndWorld(world, position.getX() + 0.5, position.getY() + 0.5, - position.getZ() + 0.5, 0.1); - for (final Vector3d vec : detectedShips) { - if (vec != null) { - return vec; - } - } - return new Vector3d(position.getX(), position.getY(), position.getZ()); - } -} diff --git a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinWirelessModemPeripheral.java b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinWirelessModemPeripheral.java deleted file mode 100644 index 5c71ec9bf..000000000 --- a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinWirelessModemPeripheral.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.valkyrienskies.mod.fabric.mixin.compat.cc_restitched; - -import com.llamalad7.mixinextras.injector.wrapoperation.Operation; -import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; -import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; -import net.minecraft.world.phys.Vec3; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Pseudo; -import org.spongepowered.asm.mixin.injection.At; -import org.valkyrienskies.mod.common.VSGameUtilsKt; - -@Pseudo -@Mixin(WirelessModemPeripheral.class) -public abstract class MixinWirelessModemPeripheral { - @WrapOperation( - method = "getRange", - at = @At( - value = "INVOKE", - target = "Ldan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral;getPosition()Lnet/minecraft/world/phys/Vec3;" - ) - ) - public Vec3 ValkyrienSkies$getPosition(WirelessModemPeripheral instance, Operation original){ - return VSGameUtilsKt.toWorldCoordinates(instance.getLevel(), original.call(instance)); - } -} diff --git a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinWirelessNetwork.java b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinWirelessNetwork.java deleted file mode 100644 index e1365b4c6..000000000 --- a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/cc_restitched/MixinWirelessNetwork.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.valkyrienskies.mod.fabric.mixin.compat.cc_restitched; - -import dan200.computercraft.api.network.Packet; -import dan200.computercraft.api.network.PacketReceiver; -import dan200.computercraft.api.network.PacketSender; -import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; -import net.minecraft.world.phys.Vec3; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Pseudo; -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.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.valkyrienskies.mod.common.VSGameUtilsKt; - -@Pseudo -@Mixin(WirelessNetwork.class) -public class MixinWirelessNetwork { - @Unique - private static PacketReceiver shipReceiver; - @Unique - private static PacketSender shipSender; - - @Redirect( - method = "tryTransmit", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/world/phys/Vec3;distanceToSqr(Lnet/minecraft/world/phys/Vec3;)D" - ) - ) - private static double ValkyrienSkies$distanceToSqr(final Vec3 instance, final Vec3 d) { - return VSGameUtilsKt.squaredDistanceBetweenInclShips(shipReceiver.getLevel(), instance.x, instance.y, - instance.z, d.x, d.y, d.z); - } - - @Inject(at = @At("HEAD"), method = "tryTransmit", remap = false) - private static void ValkyrienSkies2$tryTransmit(final PacketReceiver receiver, final Packet packet, - final double range, - final boolean interdimensional, final CallbackInfo ci) { - shipReceiver = receiver; - shipSender = packet.sender(); - } -} diff --git a/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/common/ContraptionShipyardEntityHandlerFabric.kt b/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/common/ContraptionShipyardEntityHandlerFabric.kt index 81b8f43ac..94e9ae0f9 100644 --- a/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/common/ContraptionShipyardEntityHandlerFabric.kt +++ b/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/common/ContraptionShipyardEntityHandlerFabric.kt @@ -4,6 +4,7 @@ import com.simibubi.create.content.contraptions.AbstractContraptionEntity import net.minecraft.core.BlockPos import net.minecraft.world.entity.Entity import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate +import org.valkyrienskies.core.api.VsBeta import org.valkyrienskies.core.api.ships.ContraptionWingProvider import org.valkyrienskies.core.api.ships.LoadedServerShip import org.valkyrienskies.core.api.ships.Ship @@ -12,10 +13,11 @@ import org.valkyrienskies.mod.common.block.WingBlock import org.valkyrienskies.mod.common.entity.handling.AbstractShipyardEntityHandler object ContraptionShipyardEntityHandlerFabric: AbstractShipyardEntityHandler() { + @OptIn(VsBeta::class) override fun freshEntityInShipyard(entity: Entity, ship: Ship) { if (entity is AbstractContraptionEntity && ship is LoadedServerShip) { entity as ContraptionWingProvider - val attachment = ship.getAttachment(WingManager::class.java)!! + val attachment = ship.wingManager ?: return entity.wingGroupId = attachment.createWingGroup() entity.contraption.blocks.forEach { (pos: BlockPos, blockInfo: StructureTemplate.StructureBlockInfo) -> val block = blockInfo.state.block @@ -29,10 +31,11 @@ object ContraptionShipyardEntityHandlerFabric: AbstractShipyardEntityHandler() { } } + @OptIn(VsBeta::class) override fun entityRemovedFromShipyard(entity: Entity, ship: Ship) { if (entity is AbstractContraptionEntity && ship is LoadedServerShip) { entity as ContraptionWingProvider - val attachment = ship.getAttachment(WingManager::class.java)!! + val attachment = ship.wingManager ?: return attachment.deleteWingGroup(entity.wingGroupId) entity.wingGroupId = -1 } diff --git a/fabric/src/main/resources/valkyrienskies-fabric.mixins.json b/fabric/src/main/resources/valkyrienskies-fabric.mixins.json index 0ffafcc15..698264511 100644 --- a/fabric/src/main/resources/valkyrienskies-fabric.mixins.json +++ b/fabric/src/main/resources/valkyrienskies-fabric.mixins.json @@ -3,10 +3,6 @@ "package": "org.valkyrienskies.mod.fabric.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ - "compat.cc_restitched.MixinTurtleBrain", - "compat.cc_restitched.MixinTurtleMoveCommand", - "compat.cc_restitched.MixinWirelessModemPeripheral", - "compat.cc_restitched.MixinWirelessNetwork", "compat.create.MixinBlockBreakingKineticTileEntity", "compat.create.MixinBlocks", "compat.create.MixinChuteBlockEntity", @@ -21,7 +17,6 @@ ], "client": [ "client.render.MixinLevelRenderer", - "compat.cc_restitched.MixinSpeakerSound", "compat.create.client.MixinContraptionHandlerClient", "compat.create.client.MixinContraptionRenderInfo", "compat.create.client.MixinCullingBlockEntityIterator", diff --git a/forge/build.gradle b/forge/build.gradle index b51c33772..9a7099bbd 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -80,9 +80,6 @@ dependencies { modImplementation("curse.maven:weather-storms-tornadoes-237746:5244118") modImplementation("curse.maven:coroutil-237749:5096038") - // CC Tweaked - modCompileOnly("maven.modrinth:cc-tweaked:${cc_tweaked_version}") - // EMF compat modCompileOnly("curse.maven:entity-model-features-844662:5696899") modCompileOnly("curse.maven:entity-texture-features-fabric-568563:5697083") diff --git a/forge/gradle.properties b/forge/gradle.properties index d7a683d93..f4ae8d801 100644 --- a/forge/gradle.properties +++ b/forge/gradle.properties @@ -13,7 +13,7 @@ registrate_version = MC1.20-1.3.3 # https://modmaven.dev/teamtwilight/twilightforest/ twilightforest_version = 4.3.2145 -cc_tweaked_version = 1.109.0-forge + #Extra # https://modrinth.com/mod/tis3d/version/MC1.19.2-forge-1.7.4 tis3d_version = MC1.20.1-forge-1.7.5 diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinTurtleBrain.java b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinTurtleBrain.java deleted file mode 100644 index 7370c4797..000000000 --- a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinTurtleBrain.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.valkyrienskies.mod.forge.mixin.compat.cc_tweaked; - -import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity; -import dan200.computercraft.shared.turtle.core.TurtleBrain; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.core.Vec3i; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.joml.Matrix4dc; -import org.joml.Vector3d; -import org.joml.Vector3dc; -import org.joml.primitives.AABBic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Pseudo; -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.ModifyVariable; -import org.valkyrienskies.core.api.ships.Ship; -import org.valkyrienskies.mod.common.VSGameUtilsKt; -import org.valkyrienskies.mod.common.config.VSGameConfig; -import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; - -@Pseudo -@Mixin(TurtleBrain.class) -public abstract class MixinTurtleBrain { - @Shadow(remap = false) - public abstract TurtleBlockEntity getOwner(); - - @Shadow(remap = false) - public abstract void setOwner(TurtleBlockEntity owner); - - @Shadow - public abstract Level getLevel(); - - @ModifyVariable( - method = "teleportTo(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;)Z", - at = @At(value = "HEAD"), - index = 2, - argsOnly = true, - remap = false - ) - private BlockPos ValkyrienSkies2$teleportToBlockPos(final BlockPos pos) { - final TurtleBlockEntity currentOwner = getOwner(); - final BlockPos oldPos = currentOwner.getAccess().getPosition(); - final Level world = getLevel(); - - final Ship ship = VSGameUtilsKt.getShipManagingPos(world, oldPos); - if (ship != null) { - // THERE IS A SHIP - final Direction d = getNewDirection(ship, currentOwner.getDirection()); - if (!doesShipContainPoint(ship, pos)) { - // POSITION IS OUTSIDE THE SHIP'S AABB - - currentOwner.setDirection(d); - setOwner(currentOwner); - - if (!isShipScaled(ship)) { - // SHIP IS NOT SCALED - - return getWorldPosFromShipPos(ship, pos); - } else if (turtlesLeaveScaledShips()) { - // SHIP IS SCALED AND TURTLES CAN LEAVE SCALED SHIPS - - return getWorldPosFromShipPos(ship, pos); - } - } - } - return pos; - } - - // CUSTOM METHODS - - @Unique - private static Direction getNewDirection(final Ship ship, final Direction direction) { - final Matrix4dc matrix = ship.getShipToWorld(); - final Vec3i turtleDirectionVector = direction.getNormal(); - final Vector3d directionVec = - matrix.transformDirection(turtleDirectionVector.getX(), turtleDirectionVector.getY(), - turtleDirectionVector.getZ(), new Vector3d()); - final Direction dir = Direction.getNearest(directionVec.x, directionVec.y, directionVec.z); - - return dir; - } - - @Unique - private static boolean turtlesLeaveScaledShips() { - return VSGameConfig.SERVER.getComputerCraft().getCanTurtlesLeaveScaledShips(); - } - - @Unique - private static boolean isShipScaled(final Ship ship) { - final Vector3dc scale = ship.getTransform().getShipToWorldScaling(); - final Vector3dc normalScale = new Vector3d(1.000E+0, 1.000E+0, 1.000E+0); - return !scale.equals(normalScale); - } - - @Unique - private static boolean doesShipContainPoint(final Ship ship, final BlockPos pos) { - final AABBic shipAABB = ship.getShipAABB(); - - final AABB t = new AABB(shipAABB.maxX(), shipAABB.maxY(), shipAABB.maxZ(), shipAABB.minX(), shipAABB.minY(), - shipAABB.minZ()); - return t.intersects(new AABB(pos)); - } - - @Unique - private static BlockPos getWorldPosFromShipPos(final Ship ship, final BlockPos pos) { - final Vec3 tPos = VectorConversionsMCKt.toMinecraft( - VSGameUtilsKt.toWorldCoordinates(ship, pos.getX() + 0.5, pos.getY() + 0.5, - pos.getZ() + 0.5)); - final BlockPos newPos = BlockPos.containing(tPos); - return newPos; - } -} diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinTurtleMoveCommand.java b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinTurtleMoveCommand.java deleted file mode 100644 index 43530fe09..000000000 --- a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/MixinTurtleMoveCommand.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.valkyrienskies.mod.forge.mixin.compat.cc_tweaked; - -import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.shared.turtle.core.TurtleMoveCommand; -import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; -import org.joml.Vector3d; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Pseudo; -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 org.valkyrienskies.core.api.ships.Ship; -import org.valkyrienskies.mod.common.VSGameUtilsKt; - -import java.util.List; - -@Pseudo -@Mixin(TurtleMoveCommand.class) -public abstract class MixinTurtleMoveCommand { - @Inject(method = "canEnter", at = @At("RETURN"), remap = false, cancellable = true) - private static void ValkyrienSkies2$canEnter( - final TurtlePlayer turtlePlayer, final ServerLevel world, final BlockPos position, final CallbackInfoReturnable cir) { - if (cir.getReturnValue().isSuccess()) { - final Ship ship = VSGameUtilsKt.getShipManagingPos(world, position); - if (ship == null) { - final Ship iShip = VSGameUtilsKt.getShipManagingPos(world, getShipPosFromWorldPos(world, position)); - if (iShip != null) { - cir.setReturnValue(TurtleCommandResult.failure("ship")); - } - } else { - final ChunkPos chunk = world.getChunkAt(position).getPos(); - if (!ship.getChunkClaim().contains(chunk.x, chunk.z)) { - cir.setReturnValue(TurtleCommandResult.failure("out of ship")); - } - } - } - } - - //CUSTOM METHODS - @Unique - private static Vector3d getShipPosFromWorldPos(final Level world, final BlockPos position) { - final List detectedShips = - VSGameUtilsKt.transformToNearbyShipsAndWorld(world, position.getX() + 0.5, position.getY() + 0.5, - position.getZ() + 0.5, 0.1); - for (final Vector3d vec : detectedShips) { - if (vec != null) { - return vec; - } - } - return new Vector3d(position.getX(), position.getY(), position.getZ()); - } -} diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/README.MD b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/README.MD deleted file mode 100644 index 86cfc1995..000000000 --- a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/cc_tweaked/README.MD +++ /dev/null @@ -1,15 +0,0 @@ -Minimal ComputerCraft Compatibility Mixins - -- MixinSpeakerSound - - Fixes Speakers on Ships not playing sounds in worldspace but in Shipyard -- MixinTurtleBrain - - Fails Movement if the turtle is in worldspace and the target position is a - ship (returns "ship") - - Fails Movement if the turtle is on ship and the target position is outside - a ship's ActiveChunkSet (returns "out of ship") -- MixinTurtleMoveCommand - - Allows a Turtle to Leave Ships if the target position is outside of ship's - VoxelAABB and ship is not scaled up or down -- MixinWirelessNetwork - - Fixes Modems not being able to communicate from/to ships despite being - within range diff --git a/forge/src/main/kotlin/org/valkyrienskies/mod/forge/common/ContraptionShipyardEntityHandlerForge.kt b/forge/src/main/kotlin/org/valkyrienskies/mod/forge/common/ContraptionShipyardEntityHandlerForge.kt index 2770a0b09..7f3c3130d 100644 --- a/forge/src/main/kotlin/org/valkyrienskies/mod/forge/common/ContraptionShipyardEntityHandlerForge.kt +++ b/forge/src/main/kotlin/org/valkyrienskies/mod/forge/common/ContraptionShipyardEntityHandlerForge.kt @@ -15,7 +15,7 @@ object ContraptionShipyardEntityHandlerForge: AbstractShipyardEntityHandler() { override fun freshEntityInShipyard(entity: Entity, ship: Ship) { if (entity is AbstractContraptionEntity && ship is LoadedServerShip) { entity as ContraptionWingProvider - val attachment = ship.getAttachment(WingManager::class.java)!! + val attachment = ship.wingManager ?: return entity.wingGroupId = attachment.createWingGroup() entity.contraption.blocks.forEach { (pos: BlockPos, blockInfo: StructureTemplate.StructureBlockInfo) -> val block = blockInfo.state.block @@ -32,7 +32,7 @@ object ContraptionShipyardEntityHandlerForge: AbstractShipyardEntityHandler() { override fun entityRemovedFromShipyard(entity: Entity, ship: Ship) { if (entity is AbstractContraptionEntity && ship is LoadedServerShip) { entity as ContraptionWingProvider - val attachment = ship.getAttachment(WingManager::class.java)!! + val attachment = ship.wingManager ?: return attachment.deleteWingGroup(entity.wingGroupId) entity.wingGroupId = -1 } diff --git a/forge/src/main/resources/valkyrienskies-forge.mixins.json b/forge/src/main/resources/valkyrienskies-forge.mixins.json index 9b4c2593c..7cc6933bd 100644 --- a/forge/src/main/resources/valkyrienskies-forge.mixins.json +++ b/forge/src/main/resources/valkyrienskies-forge.mixins.json @@ -4,10 +4,6 @@ "compatibilityLevel": "JAVA_17", "plugin": "org.valkyrienskies.mod.forge.mixin.ValkyrienSkiesForgeMixinPlugin", "mixins": [ - "compat.cc_tweaked.MixinTurtleBrain", - "compat.cc_tweaked.MixinTurtleMoveCommand", - "compat.cc_tweaked.MixinWirelessModemPeripheral", - "compat.cc_tweaked.MixinWirelessNetwork", "compat.create.MixinBlockBreakingKineticTileEntity", "compat.create.MixinBlocks", "compat.create.MixinChuteBlockEntity", @@ -28,7 +24,6 @@ ], "client": [ "client.render.MixinLevelRenderer", - "compat.cc_tweaked.MixinSpeakerSound", "compat.create.client.MixinContraptionHandlerClient", "compat.create.client.MixinContraptionRenderInfo", "compat.create.client.MixinFlwContraption", diff --git a/gradle.properties b/gradle.properties index 2c91a7fe9..b19536aea 100644 --- a/gradle.properties +++ b/gradle.properties @@ -28,7 +28,10 @@ createbigcannons_version= 0.5.2.a create_utilities_version=0.2.1+1.20.1 energy_version=2.3.0 -vs_core_version=1.1.0+2a62e6a823 +# https://modrinth.com/mod/cc-tweaked/version/Zoo9N9Dv +cc_tweaked_version = 1.113.1-fabric + +vs_core_version=1.1.0+6dba85260a # Prevent kotlin from autoincluding stdlib as a dependency, which breaks # gradle's composite builds (includeBuild) for some reason. We'll add it manually kotlin.stdlib.default.dependency=false