diff --git a/build.gradle b/build.gradle index b176a7695..2039440a0 100644 --- a/build.gradle +++ b/build.gradle @@ -246,7 +246,17 @@ repositories { maven { url = "https://cursemaven.com" content { - includeGroup "curse.maven" + includeGroup("curse.maven") + } + } + maven { + url = "https://maven.valkyrienskies.org" + content { + includeGroup("org.valkyrienskies") + includeGroup("org.valkyrienskies.core") + includeGroup("com.github.LlamaLad7") + includeGroup("com.github.Rubydesic") + includeGroup("org.mapstruct") } } } @@ -331,8 +341,8 @@ dependencies { // DimStorage compileOnly fg.deobf("curse.maven:dimstorage-353882:${dimstorage_version}") compileOnly fg.deobf("curse.maven:edivadlib-638508:${edivadlib_version}") - runtimeOnly fg.deobf("curse.maven:dimstorage-353882:${dimstorage_version}") - runtimeOnly fg.deobf("curse.maven:edivadlib-638508:${edivadlib_version}") + // runtimeOnly fg.deobf("curse.maven:dimstorage-353882:${dimstorage_version}") + // runtimeOnly fg.deobf("curse.maven:edivadlib-638508:${edivadlib_version}") //Powah compileOnly fg.deobf("curse.maven:powah-633483:${powah_version}") @@ -340,7 +350,7 @@ dependencies { runtimeOnly fg.deobf("me.shedaniel.cloth:cloth-config-forge:8.2.88") runtimeOnly fg.deobf("dev.architectury:architectury-forge:6.2.43") - // Crash utilities. Used to debug the chunky turtle. Can be uncommented if not needed + // Crash utilities. Used to debug the chunky turtle. Can be commented if not needed runtimeOnly fg.deobf("curse.maven:crash-utilities-371813:4406293") testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_version}" @@ -361,6 +371,25 @@ dependencies { // Create Crafts & Additions compileOnly fg.deobf("curse.maven:createaddition-439890:5099757") // runtimeOnly fg.deobf("curse.maven:createaddition-439890:5099757") + + // Valkyrien Skies 2 + implementation("org.joml:joml:1.10.4") { + transitive = false + } + implementation("org.joml:joml-primitives:1.10.0") { + transitive = false + } + // implementation fg.deobf("org.valkyrienskies:valkyrienskies-119-common:${vs2_version}") + implementation fg.deobf("org.valkyrienskies:valkyrienskies-119-forge:${vs2_version}") { + transitive = false + } + compileOnly "org.valkyrienskies.core:api:${vs_core_version}" + compileOnly "org.valkyrienskies.core:api-game:${vs_core_version}" + compileOnly "org.valkyrienskies.core:util:${vs_core_version}" + compileOnly "org.valkyrienskies.core:impl:${vs_core_version}" + runtimeOnly fg.deobf("curse.maven:valkyrien-skies-258371:${valkyrien_skies_version}") + runtimeOnly fg.deobf("curse.maven:eureka-ships-654384:${eureka_ships_version}") + runtimeOnly fg.deobf("curse.maven:clockwork-807792:${clockwork_version}") } diff --git a/gradle.properties b/gradle.properties index 740b947f1..8f7c36183 100644 --- a/gradle.properties +++ b/gradle.properties @@ -37,6 +37,11 @@ ae2additions_version=4646599 kotlinforforge_version=3.12.0 appliedmekanistics_version=4734608 dimstorage_version=3927875 +valkyrien_skies_version=4994898 +eureka_ships_version=5321628 +clockwork_version=5171528 +vs2_version=2.1.2-beta.1+a04911c932 +vs_core_version=1.1.0+2a62e6a823 # Mod dependencies which are needed for other mods # For minecolonies diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java b/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java index 5bdce0093..6f00434c1 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/APAddons.java @@ -2,14 +2,18 @@ import de.srendi.advancedperipherals.AdvancedPeripherals; import de.srendi.advancedperipherals.common.addons.refinedstorage.RefinedStorage; +import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.InterModComms; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.mod.common.VSGameUtilsKt; import top.theillusivec4.curios.api.CuriosApi; import top.theillusivec4.curios.api.SlotResult; import top.theillusivec4.curios.api.SlotTypeMessage; @@ -26,6 +30,7 @@ public class APAddons { public static final String MEKANISM_MODID = "mekanism"; public static final String AE_ADDITIONS_MODID = "ae2additions"; public static final String APP_MEKANISTICS_MODID = "appmek"; + public static final String VALKYRIEN_SKIES_MODID = "valkyrienskies"; public static boolean curiosLoaded; public static boolean refinedStorageLoaded; @@ -34,6 +39,7 @@ public class APAddons { public static boolean mekanismLoaded; public static boolean aeAdditionsLoaded; public static boolean appMekLoaded; + public static boolean vs2Loaded; // Use static so these checks run as early as possible, so we can use them for our registries static { @@ -45,6 +51,7 @@ public class APAddons { aeThingsLoaded = modList.isLoaded(AE_THINGS_MODID); aeAdditionsLoaded = modList.isLoaded(AE_ADDITIONS_MODID); appMekLoaded = modList.isLoaded(APP_MEKANISTICS_MODID); + vs2Loaded = modList.isLoaded(VALKYRIEN_SKIES_MODID); if (refinedStorageLoaded) RefinedStorage.instance = new RefinedStorage(); @@ -71,4 +78,18 @@ public static ItemStack getCurioGlasses(Player player) { return curioSlots.get(0).stack(); } + + public static boolean isBlockOnShip(Level level, BlockPos pos) { + if (!vs2Loaded) { + return false; + } + return VSGameUtilsKt.isBlockInShipyard(level, pos); + } + + public static Ship getVS2Ship(Level level, BlockPos pos) { + if (!vs2Loaded) { + return null; + } + return VSGameUtilsKt.getShipObjectManagingPos(level, pos); + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java index 2d9ccb553..b3a9d8e7a 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/IntegrationPeripheralProvider.java @@ -23,7 +23,7 @@ public class IntegrationPeripheralProvider implements IPeripheralProvider { - private static final String[] SUPPORTED_MODS = new String[]{"botania", "create", "mekanism", "powah", "dimstorage"}; + private static final String[] SUPPORTED_MODS = new String[]{"botania", "create", "mekanism", "powah", "dimstorage", "valkyrienskies"}; private static final PriorityQueue integrations = new PriorityQueue<>(Comparator.comparingInt(IPeripheralIntegration::getPriority)); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java index 9e8e0ac0f..54217cede 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/operations/SphereOperation.java @@ -9,7 +9,8 @@ public enum SphereOperation implements IPeripheralOperation { SCAN_BLOCKS(2_000, 8, 16, 0.17), - SCAN_ENTITIES(2_000, 8, 16, 0.17); + SCAN_ENTITIES(2_000, 8, 16, 0.17), + SCAN_SHIPS(2_500, 8 * 3, 16 * 10 /* common view distance */, 0.17); private final int defaultCooldown; private final int defaultMaxFreeRadius; diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java index c99e9442b..287c94e4e 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/IPeripheralOwner.java @@ -9,6 +9,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,6 +24,11 @@ public interface IPeripheralOwner { @NotNull BlockPos getPos(); + @NotNull + default Vec3 getCenterPos() { + return Vec3.atCenterOf(getPos()); + } + @NotNull Direction getFacing(); @NotNull FrontAndTop getOrientation(); diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java index ee9153f06..7c3f431ec 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/owner/PocketPeripheralOwner.java @@ -12,6 +12,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import org.apache.commons.lang3.NotImplementedException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,6 +51,14 @@ public BlockPos getPos() { return owner.blockPosition(); } + @NotNull + @Override + public Vec3 getCenterPos() { + Entity owner = pocket.getEntity(); + if (owner == null) return new Vec3(0, 0, 0); + return owner.position(); + } + @NotNull @Override public Direction getFacing() { diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java index 5b0490c4b..5cd928762 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/ChatBoxPeripheral.java @@ -240,7 +240,7 @@ public final MethodResult sendFormattedMessage(@NotNull IArguments arguments) th if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.getLevel().dimension() != dimension) { continue; } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getWorldPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage); } } @@ -272,7 +272,7 @@ public final MethodResult sendMessage(@NotNull IArguments arguments) throws LuaE if (!APConfig.PERIPHERALS_CONFIG.chatBoxMultiDimensional.get() && player.getLevel().dimension() != dimension) { continue; } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getWorldPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage); } } @@ -319,7 +319,7 @@ public final MethodResult sendFormattedMessageToPlayer(@NotNull IArguments argum return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getWorldPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage); } return MethodResult.of(true); @@ -377,7 +377,7 @@ public final MethodResult sendFormattedToastToPlayer(@NotNull IArguments argumen return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getWorldPos(), getLevel(), player, range, maxRange)) { ToastToClientPacket packet = new ToastToClientPacket(titleComponent, preparedMessage); APNetworking.sendTo(packet, player); } @@ -416,7 +416,7 @@ public final MethodResult sendMessageToPlayer(@NotNull IArguments arguments) thr return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getWorldPos(), getLevel(), player, range, maxRange)) { player.sendSystemMessage(preparedMessage, false); } return MethodResult.of(true); @@ -455,7 +455,7 @@ public final MethodResult sendToastToPlayer(@NotNull IArguments arguments) throw return MethodResult.of(false, "NOT_SAME_DIMENSION"); } - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, maxRange)) { + if (CoordUtil.isInRange(getWorldPos(), getLevel(), player, range, maxRange)) { ToastToClientPacket packet = new ToastToClientPacket(Component.literal(title), preparedMessage); APNetworking.sendTo(packet, player); } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DistanceDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DistanceDetectorPeripheral.java index 706579f7e..bf1f63655 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DistanceDetectorPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/DistanceDetectorPeripheral.java @@ -119,7 +119,7 @@ public enum DetectionType { private final boolean block, entity; - private DetectionType(boolean block, boolean entity) { + DetectionType(boolean block, boolean entity) { this.block = block; this.entity = entity; } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java index 0d8d07078..24b4b4930 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/EnvironmentDetectorPeripheral.java @@ -4,7 +4,6 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.pocket.IPocketAccess; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; @@ -18,7 +17,6 @@ import de.srendi.advancedperipherals.common.util.LuaConverter; import de.srendi.advancedperipherals.lib.peripherals.BasePeripheral; import de.srendi.advancedperipherals.lib.peripherals.IPeripheralPlugin; -import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceKey; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; @@ -31,6 +29,7 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.levelgen.WorldgenRandom; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.player.SleepingTimeCheckEvent; import net.minecraftforge.eventbus.api.Event; @@ -50,8 +49,9 @@ public class EnvironmentDetectorPeripheral extends BasePeripheral plugin : PERIPHERAL_PLUGINS) + for (Function plugin : PERIPHERAL_PLUGINS) { addPlugin(plugin.apply(owner)); + } } public EnvironmentDetectorPeripheral(PeripheralBlockEntity tileEntity) { @@ -87,24 +87,24 @@ public boolean isEnabled() { @LuaFunction(mainThread = true) public final String getBiome() { - Optional> biome = getLevel().getBiome(getPos()).unwrapKey(); + Optional> biome = getLevel().getBiome(this.getWorldBlockPos()).unwrapKey(); return biome.map(biomeResourceKey -> biomeResourceKey.location().toString()).orElse("unknown"); } @LuaFunction(mainThread = true) public final int getSkyLightLevel() { - return getLevel().getBrightness(LightLayer.SKY, getPos().offset(0, 1, 0)); + return getLevel().getBrightness(LightLayer.SKY, this.getWorldBlockPos().offset(0, 1, 0)); } @LuaFunction(mainThread = true) public final int getBlockLightLevel() { - return getLevel().getBrightness(LightLayer.BLOCK, getPos().offset(0, 1, 0)); + return getLevel().getBrightness(LightLayer.BLOCK, this.getWorldBlockPos().offset(0, 1, 0)); } @LuaFunction(mainThread = true) public final int getDayLightLevel() { Level level = getLevel(); - int i = level.getBrightness(LightLayer.SKY, getPos().offset(0, 1, 0)) - level.getSkyDarken(); + int i = level.getBrightness(LightLayer.SKY, this.getWorldBlockPos().offset(0, 1, 0)) - level.getSkyDarken(); float f = level.getSunAngle(1.0F); if (i > 0) { float f1 = f < (float) Math.PI ? 0.0F : ((float) Math.PI * 2F); @@ -122,7 +122,7 @@ public final long getTime() { @LuaFunction(mainThread = true) public final boolean isSlimeChunk() { - ChunkPos chunkPos = new ChunkPos(getPos()); + ChunkPos chunkPos = new ChunkPos(this.getWorldBlockPos()); return WorldgenRandom.seedSlimeChunk(chunkPos.x, chunkPos.z, ((WorldGenLevel) getLevel()).getSeed(), 987234911L).nextInt(10) == 0; } @@ -196,17 +196,15 @@ public final boolean isSunny() { } @LuaFunction(mainThread = true) - public final MethodResult scanEntities(@NotNull IComputerAccess access, @NotNull IArguments arguments) throws LuaException { + public final MethodResult scanEntities(@NotNull IArguments arguments) throws LuaException { int radius = arguments.getInt(0); boolean detailed = arguments.count() > 1 ? arguments.getBoolean(1) : false; return withOperation(SCAN_ENTITIES, new SphereOperationContext(radius), context -> { - if (radius > SCAN_ENTITIES.getMaxCostRadius()) - return MethodResult.of(null, "Radius exceeds max value"); - return null; + return context.getRadius() > SCAN_ENTITIES.getMaxCostRadius() ? MethodResult.of(null, "Radius exceeds max value") : null; }, context -> { - BlockPos pos = owner.getPos(); - AABB box = new AABB(pos); - List> entities = getLevel().getEntities((Entity) null, box.inflate(radius), entity -> entity instanceof LivingEntity && entity.isAlive()).stream().map(entity -> LuaConverter.completeEntityWithPositionToLua(entity, pos, detailed)).toList(); + Vec3 pos = this.getWorldPos(); + AABB box = new AABB(pos, pos); + List> entities = getLevel().getEntities((Entity) null, box.inflate(context.getRadius() + 0.5), entity -> entity instanceof LivingEntity && entity.isAlive()).stream().map(entity -> LuaConverter.completeEntityWithPositionToLua(entity, pos, detailed)).toList(); return MethodResult.of(entities); }, null); } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/GeoScannerPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/GeoScannerPeripheral.java index c94496149..449256acb 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/GeoScannerPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/GeoScannerPeripheral.java @@ -24,6 +24,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.Tags; import net.minecraftforge.registries.ForgeRegistries; import org.jetbrains.annotations.NotNull; @@ -60,13 +61,12 @@ public GeoScannerPeripheral(IPocketAccess pocket) { this(new PocketPeripheralOwner(pocket)); } - private static List> scan(Level level, BlockPos center, int radius) { - List> result = new ArrayList<>(); + private static List> scan(List> result, Level level, Vec3 center, int radius) { ScanUtils.relativeTraverseBlocks(level, center, radius, (state, pos) -> { HashMap data = new HashMap<>(6); - data.put("x", pos.getX()); - data.put("y", pos.getY()); - data.put("z", pos.getZ()); + data.put("x", pos.x); + data.put("y", pos.y); + data.put("z", pos.z); Block block = state.getBlock(); ResourceLocation name = ForgeRegistries.BLOCKS.getKey(block); @@ -103,7 +103,7 @@ public final MethodResult cost(int radius) { public final MethodResult chunkAnalyze() throws LuaException { return withOperation(SCAN_BLOCKS, SCAN_BLOCKS.free(), null, ignored -> { Level level = getLevel(); - LevelChunk chunk = level.getChunkAt(getPos()); + LevelChunk chunk = level.getChunkAt(getWorldBlockPos()); ChunkPos chunkPos = chunk.getPos(); HashMap data = new HashMap<>(); for (int x = chunkPos.getMinBlockX(); x <= chunkPos.getMaxBlockX(); x++) { @@ -131,6 +131,18 @@ public final MethodResult scan(@NotNull IArguments arguments) throws LuaExceptio return MethodResult.of(null, "Radius is exceed max value"); } return null; - }, context -> MethodResult.of(scan(getLevel(), getPos(), context.getRadius())), null); + }, context -> { + List> result = new ArrayList<>(); + scan(result, getLevel(), getCenterPos(), context.getRadius()); + if (isOnShip()) { + int i = result.size(); + scan(result, getLevel(), getWorldPos(), context.getRadius()); + for (; i < result.size(); i++) { + Map data = result.get(i); + data.put("notOnShip", true); + } + } + return MethodResult.of(result); + }, null); } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/PlayerDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/PlayerDetectorPeripheral.java index 8b10eb742..75bf454d4 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/PlayerDetectorPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/PlayerDetectorPeripheral.java @@ -19,8 +19,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.server.ServerLifecycleHooks; import java.util.*; @@ -67,10 +67,12 @@ public final MethodResult getPlayersInCoords(Map firstCoord, Map sec ResourceKey dimension = getLevel().dimension(); for (ServerPlayer player : getPlayers()) { - if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) + if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) { continue; - if (CoordUtil.isInRange(getPos(), player, getLevel(), firstPos, secondPos, MAX_RANGE)) + } + if (CoordUtil.isInRange(getWorldPos(), player, getLevel(), firstPos, secondPos, MAX_RANGE)) { playersName.add(player.getName().getString()); + } } return MethodResult.of(playersName); } @@ -81,10 +83,9 @@ public final List getPlayersInCubic(int x, int y, int z) { ResourceKey dimension = getLevel().dimension(); for (ServerPlayer player : getPlayers()) { - if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) - continue; - if (CoordUtil.isInRange(getPos(), getLevel(), player, x, y, z, MAX_RANGE)) + if (player.getLevel().dimension() == dimension && CoordUtil.isInRange(getWorldPos(), getLevel(), player, x, y, z, MAX_RANGE)) { playersName.add(player.getName().getString()); + } } return playersName; } @@ -95,10 +96,9 @@ public final List getPlayersInRange(int range) { ResourceKey dimension = getLevel().dimension(); for (ServerPlayer player : getPlayers()) { - if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) - continue; - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, MAX_RANGE)) + if (player.getLevel().dimension() == dimension && CoordUtil.isInRange(getWorldPos(), getLevel(), player, range, MAX_RANGE)) { playersName.add(player.getName().getString()); + } } return playersName; } @@ -112,9 +112,12 @@ public final boolean isPlayersInCoords(Map firstCoord, Map secondCoo ResourceKey dimension = getLevel().dimension(); for (ServerPlayer player : getPlayers()) { - if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) + if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) { continue; - if (CoordUtil.isInRange(getPos(), player, getLevel(), firstPos, secondPos, MAX_RANGE)) return true; + } + if (CoordUtil.isInRange(getWorldPos(), player, getLevel(), firstPos, secondPos, MAX_RANGE)) { + return true; + } } return false; } @@ -126,9 +129,9 @@ public final boolean isPlayersInCubic(int x, int y, int z) { ResourceKey dimension = getLevel().dimension(); for (ServerPlayer player : getPlayers()) { - if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) - continue; - if (CoordUtil.isInRange(getPos(), getLevel(), player, x, y, z, MAX_RANGE)) return true; + if (player.getLevel().dimension() == dimension && CoordUtil.isInRange(getWorldPos(), getLevel(), player, x, y, z, MAX_RANGE)) { + return true; + } } return false; } @@ -140,9 +143,9 @@ public final boolean isPlayersInRange(int range) { ResourceKey dimension = getLevel().dimension(); for (ServerPlayer player : getPlayers()) { - if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) - continue; - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, MAX_RANGE)) return true; + if (player.getLevel().dimension() == dimension && CoordUtil.isInRange(getWorldPos(), getLevel(), player, range, MAX_RANGE)) { + return true; + } } return false; } @@ -153,44 +156,27 @@ public final boolean isPlayerInCoords(Map firstCoord, Map secondCoor BlockPos secondPos = LuaConverter.convertToBlockPos(secondCoord); ResourceKey dimension = getLevel().dimension(); - for (Player player : getPlayers()) { - if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) - continue; - if (CoordUtil.isInRange(getPos(), player, getLevel(), firstPos, secondPos, MAX_RANGE)) - if(player.getName().getString().equals(username)) - return true; + ServerPlayer player = getPlayer(username); + if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) { + return false; } - return false; + return CoordUtil.isInRange(getWorldPos(), player, getLevel(), firstPos, secondPos, MAX_RANGE); } @LuaFunction(mainThread = true) public final boolean isPlayerInCubic(int x, int y, int z, String username) { ResourceKey dimension = getLevel().dimension(); - for (Player player : getPlayers()) { - if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) - continue; - if (CoordUtil.isInRange(getPos(), getLevel(), player, x, y, z, MAX_RANGE)) { - if(player.getName().getString().equals(username)) - return true; - } - } - return false; + ServerPlayer player = getPlayer(username); + return player.getLevel().dimension() == dimension && CoordUtil.isInRange(getWorldPos(), getLevel(), player, x, y, z, MAX_RANGE); } @LuaFunction(mainThread = true) public final boolean isPlayerInRange(int range, String username) { ResourceKey dimension = getLevel().dimension(); - for (Player player : getPlayers()) { - if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) - continue; - if (CoordUtil.isInRange(getPos(), getLevel(), player, range, MAX_RANGE)) { - if(player.getName().getString().equals(username)) - return true; - } - } - return false; + ServerPlayer player = getPlayer(username); + return player.getLevel().dimension() == dimension && CoordUtil.isInRange(getWorldPos(), getLevel(), player, range, MAX_RANGE); } @LuaFunction(value = {"getPlayerPos", "getPlayer"}, mainThread = true) @@ -198,23 +184,22 @@ public final Map getPlayerPos(IArguments arguments) throws LuaEx if (!APConfig.PERIPHERALS_CONFIG.playerSpy.get()) throw new LuaException("This function is disabled in the config. Activate it or ask an admin if he can activate it."); ResourceKey dimension = getLevel().dimension(); + Vec3 pos = getWorldPos(); - ServerPlayer existingPlayer = null; - for (ServerPlayer player : getPlayers()) { - if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) - continue; - if (player.getName().getString().equals(arguments.getString(0))) { - if (MAX_RANGE == -1 || CoordUtil.isInRange(getPos(), getLevel(), player, MAX_RANGE, MAX_RANGE)) - existingPlayer = player; - break; - } + ServerPlayer player = getPlayer(arguments.getString(0)); + if (player == null) { + return null; + } + if (!isAllowedMultiDimensional() && player.getLevel().dimension() != dimension) { + return null; + } + if (MAX_RANGE != -1 && !CoordUtil.isInRange(pos, getLevel(), player, MAX_RANGE, MAX_RANGE)) { + return null; } - if (existingPlayer == null) - return Collections.emptyMap(); Map info = new HashMap<>(); - double x = existingPlayer.getX(), y = existingPlayer.getY(), z = existingPlayer.getZ(); + double x = player.getX(), y = player.getY(), z = player.getZ(); if (APConfig.PERIPHERALS_CONFIG.playerSpyRandError.get()) { // We apply random error to the returned player position if so enabled in the configuration. @@ -235,7 +220,7 @@ public final Map getPlayerPos(IArguments arguments) throws LuaEx maxDistance = Math.max(minDistance, maxDistance); // Calculate Euclidean distance between the player locator and the player in question - double distanceFromPlayer = Math.sqrt(Math.pow(x - getPos().getX(), 2) + Math.pow(y - getPos().getY(), 2) + Math.pow(z - getPos().getZ(), 2)); + double distanceFromPlayer = Math.sqrt(Math.pow(x - pos.x, 2) + Math.pow(y - pos.y, 2) + Math.pow(z - pos.z, 2)); distanceFromPlayer -= minDistance; if (distanceFromPlayer > 0) { @@ -255,18 +240,16 @@ public final Map getPlayerPos(IArguments arguments) throws LuaEx info.put("y", Math.floor(y * unit) / unit); info.put("z", Math.floor(z * unit) / unit); if (APConfig.PERIPHERALS_CONFIG.morePlayerInformation.get()) { - info.put("yaw", existingPlayer.yRotO); - info.put("pitch", existingPlayer.xRotO); - info.put("dimension", existingPlayer.getLevel().dimension().location().toString()); - info.put("eyeHeight", existingPlayer.getEyeHeight()); - info.put("health", existingPlayer.getHealth()); - // TODO: remove the next line in next major version - info.put("maxHeatlh", existingPlayer.getMaxHealth()); // keep this for backward compatibility - info.put("maxHealth", existingPlayer.getMaxHealth()); - info.put("airSupply", existingPlayer.getAirSupply()); - info.put("respawnPosition", LuaConverter.posToObject(existingPlayer.getRespawnPosition())); - info.put("respawnDimension", existingPlayer.getRespawnDimension().location().toString()); - info.put("respawnAngle", existingPlayer.getRespawnAngle()); + info.put("yaw", player.yRotO); + info.put("pitch", player.xRotO); + info.put("dimension", player.getLevel().dimension().location().toString()); + info.put("eyeHeight", player.getEyeHeight()); + info.put("health", player.getHealth()); + info.put("maxHealth", player.getMaxHealth()); + info.put("airSupply", player.getAirSupply()); + info.put("respawnPosition", LuaConverter.posToObject(player.getRespawnPosition())); + info.put("respawnDimension", player.getRespawnDimension().location().toString()); + info.put("respawnAngle", player.getRespawnAngle()); } return info; } @@ -274,4 +257,8 @@ public final Map getPlayerPos(IArguments arguments) throws LuaEx private List getPlayers() { return ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers(); } + + private ServerPlayer getPlayer(String name) { + return ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayerByName(name); + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/valkyrienskies/Integration.java b/src/main/java/de/srendi/advancedperipherals/common/addons/valkyrienskies/Integration.java new file mode 100644 index 000000000..a416cbbea --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/valkyrienskies/Integration.java @@ -0,0 +1,11 @@ +package de.srendi.advancedperipherals.common.addons.valkyrienskies; + +import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.EnvironmentDetectorPeripheral; + +public class Integration implements Runnable { + + @Override + public void run() { + EnvironmentDetectorPeripheral.addIntegrationPlugin(ShipScannerPlugin::new); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/valkyrienskies/ShipScannerPlugin.java b/src/main/java/de/srendi/advancedperipherals/common/addons/valkyrienskies/ShipScannerPlugin.java new file mode 100644 index 000000000..eb4ea5749 --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/valkyrienskies/ShipScannerPlugin.java @@ -0,0 +1,78 @@ +package de.srendi.advancedperipherals.common.addons.valkyrienskies; + +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.lua.MethodResult; +import de.srendi.advancedperipherals.common.addons.APAddons; +import de.srendi.advancedperipherals.common.addons.computercraft.operations.SphereOperationContext; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.IPeripheralOwner; +import de.srendi.advancedperipherals.common.util.LuaConverter; +import de.srendi.advancedperipherals.lib.peripherals.BasePeripheralPlugin; +import de.srendi.advancedperipherals.lib.peripherals.IPeripheralOperation; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.phys.Vec3; +import org.joml.Vector3d; +import org.valkyrienskies.core.api.ships.ServerShip; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.mod.common.VSGameUtilsKt; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static de.srendi.advancedperipherals.common.addons.computercraft.operations.SphereOperation.SCAN_SHIPS; + +public class ShipScannerPlugin extends BasePeripheralPlugin { + public ShipScannerPlugin(IPeripheralOwner owner) { + super(owner); + } + + @Override + public IPeripheralOperation[] getOperations() { + return new IPeripheralOperation[]{SCAN_SHIPS}; + } + + @LuaFunction(mainThread = true) + public final MethodResult scanShips(int radius) throws LuaException { + return withOperation(SCAN_SHIPS, new SphereOperationContext(radius), context -> { + return context.getRadius() > SCAN_SHIPS.getMaxCostRadius() ? MethodResult.of(null, "Radius exceeds max value") : null; + }, context -> { + ServerLevel level = (ServerLevel) this.owner.getLevel(); + Vec3 pos = this.owner.getCenterPos(); + Ship ship = APAddons.getVS2Ship(level, new BlockPos(pos)); + if (ship != null) { + Vector3d newPos = ship.getShipToWorld().transformPosition(new Vector3d(pos.x, pos.y, pos.z)); + pos = new Vec3(newPos.x, newPos.y, newPos.z); + } + List shipPoses = VSGameUtilsKt.transformToNearbyShipsAndWorld(level, pos.x, pos.y, pos.z, context.getRadius()); + List> shipDatas = new ArrayList<>(shipPoses.size()); + for (Vector3d p : shipPoses) { + ServerShip s = VSGameUtilsKt.getShipManagingPos(level, p.x, p.y, p.z); + if (ship == null || s.getId() != ship.getId()) { + shipDatas.add(LuaConverter.shipToObject(s, pos)); + } + } + return MethodResult.of(shipDatas); + }, null); + } + + @LuaFunction + public final MethodResult scanShipCost(int radius) { + int estimatedCost = estimateShipCost(radius); + if (estimatedCost < 0) { + return MethodResult.of(null, "Radius exceeds max value"); + } + return MethodResult.of(estimatedCost); + } + + private static int estimateShipCost(int radius) { + if (radius <= SCAN_SHIPS.getMaxFreeRadius()) { + return 0; + } + if (radius > SCAN_SHIPS.getMaxCostRadius()) { + return -1; + } + return SCAN_SHIPS.getCost(SphereOperationContext.of(radius)); + } +} diff --git a/src/main/java/de/srendi/advancedperipherals/common/blocks/blockentities/DistanceDetectorEntity.java b/src/main/java/de/srendi/advancedperipherals/common/blocks/blockentities/DistanceDetectorEntity.java index 3c51cfb97..8858f9126 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/blocks/blockentities/DistanceDetectorEntity.java +++ b/src/main/java/de/srendi/advancedperipherals/common/blocks/blockentities/DistanceDetectorEntity.java @@ -1,5 +1,6 @@ package de.srendi.advancedperipherals.common.blocks.blockentities; +import de.srendi.advancedperipherals.common.addons.APAddons; import de.srendi.advancedperipherals.common.addons.computercraft.peripheral.DistanceDetectorPeripheral; import de.srendi.advancedperipherals.common.blocks.base.BaseBlock; import de.srendi.advancedperipherals.common.blocks.base.PeripheralBlockEntity; @@ -15,6 +16,8 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.*; +import org.joml.Vector3d; +import org.valkyrienskies.core.api.ships.Ship; import org.jetbrains.annotations.NotNull; @@ -134,7 +137,7 @@ public AABB getRenderBoundingBox() { } currentDistance += 1.5f; Direction direction = getBlockState().getValue(BaseBlock.ORIENTATION).front(); - Vec3 blockPos = Vec3.atCenterOf(getBlockPos()); + Vec3 blockPos = Vec3.atCenterOf(this.getBlockPos()); return new AABB(blockPos, blockPos.add(direction.getStepX() * currentDistance, direction.getStepY() * currentDistance, direction.getStepZ() * currentDistance)); } @@ -174,18 +177,44 @@ public ClientboundBlockEntityDataPacket getUpdatePacket() { return ClientboundBlockEntityDataPacket.create(this); } + protected Vec3 getCenterPos() { + Vec3 pos = Vec3.atCenterOf(this.getBlockPos()); + if (!APAddons.vs2Loaded) { + return pos; + } + Ship ship = APAddons.getVS2Ship(this.getLevel(), this.getBlockPos()); + if (ship == null) { + return pos; + } + Vector3d newPos = ship.getShipToWorld().transformPosition(new Vector3d(pos.x, pos.y, pos.z)); + return new Vec3(newPos.x, newPos.y, newPos.z); + } + + protected Vec3 getDirection() { + Vec3 dir = Vec3.atLowerCornerOf(getBlockState().getValue(BaseBlock.ORIENTATION).front().getNormal()); + if (!APAddons.vs2Loaded) { + return dir; + } + Ship ship = APAddons.getVS2Ship(this.getLevel(), this.getBlockPos()); + if (ship == null) { + return dir; + } + Vector3d newDir = ship.getShipToWorld().transformDirection(new Vector3d(dir.x, dir.y, dir.z)); + return new Vec3(newDir.x, newDir.y, newDir.z); + } + public double calculateDistance() { final double maxRange = this.getMaxRange(); - Direction direction = getBlockState().getValue(BaseBlock.ORIENTATION).front(); - Vec3 center = Vec3.atCenterOf(getBlockPos()); + Vec3 direction = getDirection(); + Vec3 center = getCenterPos(); Vec3 from = center; - Vec3 to = from.add(direction.getStepX() * maxRange, direction.getStepY() * maxRange, direction.getStepZ() * maxRange); + Vec3 to = from.add(direction.x * maxRange, direction.y * maxRange, direction.z * maxRange); HitResult result = this.getHitResult(to, from); if (result.getType() == HitResult.Type.MISS) { return -1; } - return getDistanceOnDirection(direction, result.getLocation(), center) - 0.5f; + return result.getLocation().distanceTo(center) - 0.5f; } public double calculateAndUpdateDistance() { @@ -198,13 +227,8 @@ private HitResult getHitResult(Vec3 to, Vec3 from) { Level level = this.getLevel(); return switch (this.detectionType) { case ENTITY -> HitResultUtil.getEntityHitResult(to, from, level); - case BLOCK -> HitResultUtil.getBlockHitResult(to, from, level, this.ignoreTransparent); - case BOTH -> HitResultUtil.getHitResult(to, from, level, this.ignoreTransparent); + case BLOCK -> HitResultUtil.getBlockHitResult(to, from, level, this.ignoreTransparent, this.getBlockPos()); + case BOTH -> HitResultUtil.getHitResult(to, from, level, this.ignoreTransparent, this.getBlockPos()); }; } - - private static float getDistanceOnDirection(Direction direction, Vec3 from, Vec3 to) { - Direction.Axis axis = direction.getAxis(); - return Math.abs((float)(axis.choose(from.x, from.y, from.z) - axis.choose(to.x, to.y, to.z))); - } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/setup/APBlocks.java b/src/main/java/de/srendi/advancedperipherals/common/setup/APBlocks.java index 971a4faf9..cde058649 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/setup/APBlocks.java +++ b/src/main/java/de/srendi/advancedperipherals/common/setup/APBlocks.java @@ -11,9 +11,7 @@ import net.minecraft.world.item.Item; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.Material; import net.minecraftforge.fml.ModList; import net.minecraftforge.registries.RegistryObject; diff --git a/src/main/java/de/srendi/advancedperipherals/common/util/CoordUtil.java b/src/main/java/de/srendi/advancedperipherals/common/util/CoordUtil.java index 4ad348a96..389264ad0 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/util/CoordUtil.java +++ b/src/main/java/de/srendi/advancedperipherals/common/util/CoordUtil.java @@ -9,6 +9,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,7 +28,7 @@ public class CoordUtil { * * @return If the player is in the {@code range} as well as in the {@code maxRange}, or {@code range} and {@code maxRange} are -1 */ - public static boolean isInRange(@Nullable BlockPos pos, @Nullable Level world, @Nullable Player player, int range, int maxRange) { + public static boolean isInRange(@Nullable Vec3 pos, @Nullable Level world, @Nullable Player player, int range, int maxRange) { // There are rare cases where these can be null. For example if a player detector pocket computer runs while not in a player inventory // Fixes https://github.com/SirEndii/AdvancedPeripherals/issues/356 if (pos == null || world == null || player == null) { @@ -49,7 +50,7 @@ public static boolean isInRange(@Nullable BlockPos pos, @Nullable Level world, @ } // To fix issue #439 - private static boolean isPlayerInBlockRange(@NotNull BlockPos pos, @NotNull Level world, @NotNull Player player, double range) { + private static boolean isPlayerInBlockRange(@NotNull Vec3 pos, @NotNull Level world, @NotNull Player player, double range) { if (range != -1 && player.getLevel() != world) return false; @@ -59,13 +60,12 @@ private static boolean isPlayerInBlockRange(@NotNull BlockPos pos, @NotNull Leve ey = y; y = tmp; } - double bx = (double)(pos.getX() + 0.5), by = (double)(pos.getY() + 0.5), bz = (double)(pos.getZ() + 0.5); - return Math.abs(x - bx) <= range && Math.abs(z - bz) <= range && + return Math.abs(x - pos.x) <= range && Math.abs(z - pos.z) <= range && // check both feet position and eye position, and ensure it will work if player is higher than 2 blocks - ((y <= by && by <= ey) || Math.min(Math.abs(y - by), Math.abs(ey - by)) <= range); + ((y <= pos.y && pos.y <= ey) || Math.min(Math.abs(y - pos.y), Math.abs(ey - pos.y)) <= range); } - public static boolean isInRange(@Nullable BlockPos pos, @Nullable Level world, @Nullable Player player, int x, int y, int z, int maxRange) { + public static boolean isInRange(@Nullable Vec3 pos, @Nullable Level world, @Nullable Player player, int x, int y, int z, int maxRange) { if (pos == null || world == null || player == null) return false; @@ -76,7 +76,7 @@ public static boolean isInRange(@Nullable BlockPos pos, @Nullable Level world, @ return isPlayerInBlockRangeXYZ(pos, world, player, (double) x, (double) y, (double) z, maxRange); } - private static boolean isPlayerInBlockRangeXYZ(@NotNull BlockPos pos, @NotNull Level world, @NotNull Player player, double dx, double dy, double dz, int maxRange) { + private static boolean isPlayerInBlockRangeXYZ(@NotNull Vec3 pos, @NotNull Level world, @NotNull Player player, double dx, double dy, double dz, int maxRange) { if (maxRange != -1 && player.getLevel() != world) return false; @@ -86,20 +86,20 @@ private static boolean isPlayerInBlockRangeXYZ(@NotNull BlockPos pos, @NotNull L ey = y; y = tmp; } - double bx = (double)(pos.getX() + 0.5), by = (double)(pos.getY() + 0.5), bz = (double)(pos.getZ() + 0.5); - return Math.abs(x - bx) <= dx && Math.abs(z - bz) <= dz && - ((y <= by && by <= ey) || Math.min(Math.abs(y - by), Math.abs(ey - by)) <= dy); + return Math.abs(x - pos.x) <= dx && Math.abs(z - pos.z) <= dz && + ((y <= pos.y && pos.y <= ey) || Math.min(Math.abs(y - pos.y), Math.abs(ey - pos.y)) <= dy); } - public static boolean isInRange(@Nullable BlockPos blockPos, @Nullable Player player, @Nullable Level world, @NotNull BlockPos firstPos, @NotNull BlockPos secondPos, int maxRange) { - if (blockPos == null || world == null || player == null) + public static boolean isInRange(@Nullable Vec3 pos, @Nullable Player player, @Nullable Level world, @NotNull BlockPos firstPos, @NotNull BlockPos secondPos, int maxRange) { + if (pos == null || world == null || player == null) return false; - double i = Math.abs(player.getX() - blockPos.getX()); - double j = Math.abs(player.getZ() - blockPos.getZ()); + double x = Math.abs(player.getX() - pos.x); + double y = Math.abs(player.getY() - pos.y); + double z = Math.abs(player.getZ() - pos.z); // Check if the distance of the player is within the max range of the player detector // Use manhattan distance, not euclidean distance to keep same behavior than other `isInRange` functions - if (i + j > (maxRange != -1 ? maxRange : Integer.MAX_VALUE)) + if (maxRange != -1 && x + y + z > maxRange) return false; return world.getNearbyPlayers(TargetingConditions.forNonCombat(), null, new AABB(firstPos, secondPos)).contains(player); } diff --git a/src/main/java/de/srendi/advancedperipherals/common/util/HitResultUtil.java b/src/main/java/de/srendi/advancedperipherals/common/util/HitResultUtil.java index 4231a15df..618cf90b2 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/util/HitResultUtil.java +++ b/src/main/java/de/srendi/advancedperipherals/common/util/HitResultUtil.java @@ -30,8 +30,23 @@ public class HitResultUtil { */ @NotNull public static HitResult getHitResult(Vec3 to, Vec3 from, Level level, boolean ignoreTransparent) { - EntityHitResult entityResult = getEntityHitResult(to, from, level); - BlockHitResult blockResult = getBlockHitResult(to, from, level, ignoreTransparent); + return getHitResult(to, from, level, ignoreTransparent, null); + } + + /** + * This method is used to get the hit result of an entity from the start position of a block + * + * @param to the target position/max position + * @param from the source position like a block + * @param level the level + * @param ignoreTransparent if transparent blocks should be ignored + * @param source the source Entity/BlockPos that will be ignored + * @return the hit result. {@link BlockHitResult#miss(Vec3, Direction, BlockPos)} if nothing found + */ + @NotNull + public static HitResult getHitResult(Vec3 to, Vec3 from, Level level, boolean ignoreTransparent, Object source) { + EntityHitResult entityResult = getEntityHitResult(to, from, level, source instanceof Entity ? (Entity) source : null); + BlockHitResult blockResult = getBlockHitResult(to, from, level, ignoreTransparent, source instanceof BlockPos ? (BlockPos) source : null); if (entityResult.getType() == HitResult.Type.MISS) { if (blockResult.getType() == HitResult.Type.MISS) { @@ -61,9 +76,26 @@ public static HitResult getHitResult(Vec3 to, Vec3 from, Level level, boolean ig */ @NotNull public static EntityHitResult getEntityHitResult(Vec3 to, Vec3 from, Level level) { + return getEntityHitResult(to, from, level, null); + } + + /** + * This method is used to get the hit result of an entity from the start position of a block + * This could be used to find an entity from the eyes position of another entity but since + * this method uses one AABB made out of the two coordinates, this would also find any entities + * which are not located in the ray you might want. {@link DistanceDetectorPeripheral#getDistance()} + * + * @param to the target position/max position + * @param from the source position like a block + * @param level the world + * @param source the source Entity that will be ignored + * @return the entity hit result. An empty HitResult with {@link HitResult.Type#MISS} as type if nothing found + */ + @NotNull + public static EntityHitResult getEntityHitResult(Vec3 to, Vec3 from, Level level, Entity source) { AABB checkingBox = new AABB(to, from); - List entities = level.getEntities((Entity) null, checkingBox, (entity) -> true); + List entities = level.getEntities(source, checkingBox, (entity) -> true); Entity nearestEntity = null; Vec3 hitPos = null; @@ -96,7 +128,22 @@ public static EntityHitResult getEntityHitResult(Vec3 to, Vec3 from, Level level */ @NotNull public static BlockHitResult getBlockHitResult(Vec3 to, Vec3 from, Level level, boolean ignoreNoOccluded) { - return level.clip(new AdvancedClipContext(from, to, ignoreNoOccluded ? IgnoreNoOccludedContext.INSTANCE : ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, null, true)); + return getBlockHitResult(to, from, level, ignoreNoOccluded); + } + + /** + * This method is used to get the hit result of a block from the start position of a block + * + * @param to the target position/max position + * @param from the source position + * @param level the world + * @param ignoreNoOccluded if true, the method will ignore blocks which are not occluding like glass + * @param source the source BlockPos that will be ignored + * @return the block hit result. {@link BlockHitResult#miss(Vec3, Direction, BlockPos)} if nothing found + */ + @NotNull + public static BlockHitResult getBlockHitResult(Vec3 to, Vec3 from, Level level, boolean ignoreNoOccluded, BlockPos source) { + return level.clip(new AdvancedClipContext(from, to, ignoreNoOccluded ? IgnoreNoOccludedContext.INSTANCE : ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, null, source)); } public static class EmptyEntityHitResult extends EntityHitResult { @@ -137,18 +184,18 @@ public VoxelShape get(BlockState pState, @NotNull BlockGetter pBlock, @NotNull B private static class AdvancedClipContext extends ClipContext { private final ShapeGetter blockShapeGetter; - private final boolean ignoreSourceBlock; + private final BlockPos source; - protected AdvancedClipContext(Vec3 from, Vec3 to, ShapeGetter blockShapeGetter, Fluid fluidShapeGetter, @Nullable Entity entity, boolean ignoreSourceBlock) { + protected AdvancedClipContext(Vec3 from, Vec3 to, ShapeGetter blockShapeGetter, Fluid fluidShapeGetter, @Nullable Entity entity, BlockPos source) { super(from, to, Block.COLLIDER, fluidShapeGetter, entity); this.blockShapeGetter = blockShapeGetter; - this.ignoreSourceBlock = ignoreSourceBlock; + this.source = source; } @NotNull @Override public VoxelShape getBlockShape(@NotNull BlockState pBlockState, @NotNull BlockGetter pLevel, @NotNull BlockPos pPos) { - if (this.ignoreSourceBlock && pPos.equals(new BlockPos(this.getFrom()))) { + if (this.source != null && this.source.equals(pPos)) { return Shapes.empty(); } return blockShapeGetter.get(pBlockState, pLevel, pPos, this.collisionContext); diff --git a/src/main/java/de/srendi/advancedperipherals/common/util/LuaConverter.java b/src/main/java/de/srendi/advancedperipherals/common/util/LuaConverter.java index a5f759c7d..51ea7661a 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/util/LuaConverter.java +++ b/src/main/java/de/srendi/advancedperipherals/common/util/LuaConverter.java @@ -20,9 +20,18 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.IForgeShearable; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidType; +import org.joml.primitives.AABBic; +import org.joml.Quaterniondc; +import org.joml.Vector3d; +import org.joml.Vector3dc; +import org.valkyrienskies.core.api.ships.ServerShip; +import org.valkyrienskies.core.api.ships.Ship; +import org.valkyrienskies.core.api.ships.properties.ShipInertiaData; +import org.valkyrienskies.core.api.ships.properties.ShipTransform; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -121,15 +130,27 @@ public static Map completeEntityWithPositionToLua(Entity entity, return completeEntityWithPositionToLua(entity, pos, false); } + public static Map completeEntityWithPositionToLua(Entity entity, Vec3 pos) { + return completeEntityWithPositionToLua(entity, pos, false); + } + public static Map completeEntityWithPositionToLua(Entity entity, BlockPos pos, boolean detailed) { return completeEntityWithPositionToLua(entity, ItemStack.EMPTY, pos, detailed); } + public static Map completeEntityWithPositionToLua(Entity entity, Vec3 pos, boolean detailed) { + return completeEntityWithPositionToLua(entity, ItemStack.EMPTY, pos, detailed); + } + public static Map completeEntityWithPositionToLua(Entity entity, ItemStack itemInHand, BlockPos pos, boolean detailed) { + return completeEntityWithPositionToLua(entity, itemInHand, Vec3.atCenterOf(pos), detailed); + } + + public static Map completeEntityWithPositionToLua(Entity entity, ItemStack itemInHand, Vec3 pos, boolean detailed) { Map data = completeEntityToLua(entity, itemInHand, detailed); - data.put("x", entity.getX() - pos.getX()); - data.put("y", entity.getY() - pos.getY()); - data.put("z", entity.getZ() - pos.getZ()); + data.put("x", entity.getX() - pos.x); + data.put("y", entity.getY() - pos.y); + data.put("z", entity.getZ() - pos.z); return data; } @@ -271,4 +292,44 @@ public static Object effectToObject(MobEffectInstance effect) { map.put("amplifier", effect.getAmplifier()); return map; } + + public static Map shipToObject(ServerShip ship, Vec3 pos) { + Map map = new HashMap<>(); + + map.put("id", ship.getId()); + map.put("slug", ship.getSlug()); + + ShipTransform tf = ship.getTransform(); + + Vector3dc worldPos = tf.getShipPositionInWorldCoordinates(); + Vector3dc shipPos = tf.getShipPositionInShipCoordinates(); + map.put("x", worldPos.x() - pos.x); + map.put("y", worldPos.y() - pos.y); + map.put("z", worldPos.z() - pos.z); + Quaterniondc rot = tf.getShipToWorldRotation(); + final double rotX = rot.x(), rotY = rot.y(), rotZ = rot.z(), rotW = rot.w(); + map.put("rotate", Map.of("x", rotX, "y", rotY, "z", rotZ, "w", rotW)); + // Not really correct? + // map.put("pitch", Math.toDegrees(Math.asin(-2 * (rotX * rotZ - rotW * rotY)))); + // map.put("roll", Math.toDegrees(Math.atan2(2 * (rotX * rotY + rotW * rotZ), rotW * rotW + rotX * rotX - rotY * rotY - rotZ * rotZ))); + // map.put("yaw", Math.toDegrees(Math.atan2(2 * (rotY * rotZ + rotW * rotX), rotW * rotW - rotX * rotX - rotY * rotY + rotZ * rotZ))); + + AABBic box = ship.getShipAABB(); + if (box != null) { + map.put("size", Map.of("x", box.maxX() - box.minX(), "y", box.maxY() - box.minY(), "z", box.maxZ() - box.minZ())); + map.put("corner", Map.of("x", shipPos.x() - box.minX(), "y", shipPos.y() - box.minY(), "z", shipPos.z() - box.minZ())); + } + Vector3dc omega = ship.getOmega(); + map.put("omega", Map.of("x", omega.x(), "y", omega.y(), "z", omega.z())); + Vector3dc velocity = ship.getVelocity(); + map.put("isStatic", ship.isStatic()); + map.put("velocity", Map.of("x", velocity.x(), "y", velocity.y(), "z", velocity.z())); + + ShipInertiaData data = ship.getInertiaData(); + map.put("mass", data.getMass()); + Vector3d com = tf.getShipToWorld().transformPosition(data.getCenterOfMassInShipSpace(), new Vector3d()); + map.put("centerOfMass", Map.of("x", com.x - pos.x, "y", com.y - pos.y, "z", com.z - pos.z)); + + return map; + } } diff --git a/src/main/java/de/srendi/advancedperipherals/common/util/ScanUtils.java b/src/main/java/de/srendi/advancedperipherals/common/util/ScanUtils.java index 68a51bcd4..07194d1a7 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/util/ScanUtils.java +++ b/src/main/java/de/srendi/advancedperipherals/common/util/ScanUtils.java @@ -3,32 +3,31 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; import java.util.function.BiConsumer; public class ScanUtils { - public static void relativeTraverseBlocks(Level world, BlockPos center, int radius, BiConsumer consumer) { + public static void relativeTraverseBlocks(Level world, Vec3 center, double radius, BiConsumer consumer) { traverseBlocks(world, center, radius, consumer, true); } - public static void traverseBlocks(Level world, BlockPos center, int radius, BiConsumer consumer) { + public static void traverseBlocks(Level world, Vec3 center, double radius, BiConsumer consumer) { traverseBlocks(world, center, radius, consumer, false); } - public static void traverseBlocks(Level world, BlockPos center, int radius, BiConsumer consumer, boolean relativePosition) { - int x = center.getX(); - int y = center.getY(); - int z = center.getZ(); - for (int oX = x - radius; oX <= x + radius; oX++) { - for (int oY = y - radius; oY <= y + radius; oY++) { - for (int oZ = z - radius; oZ <= z + radius; oZ++) { + public static void traverseBlocks(Level world, Vec3 center, double radius, BiConsumer consumer, boolean relativePosition) { + final double x = center.x, y = center.y, z = center.z; + for (int oX = (int) (x - radius); oX <= (int) (x + radius); oX++) { + for (int oY = (int) (y - radius); oY <= (int) (y + radius); oY++) { + for (int oZ = (int) (z - radius); oZ <= (int) (z + radius); oZ++) { BlockPos subPos = new BlockPos(oX, oY, oZ); BlockState blockState = world.getBlockState(subPos); if (!blockState.isAir()) { if (relativePosition) { - consumer.accept(blockState, new BlockPos(oX - x, oY - y, oZ - z)); + consumer.accept(blockState, new Vec3(oX + 0.5 - center.x, oY + 0.5 - center.y, oZ + 0.5 - center.z)); } else { - consumer.accept(blockState, subPos); + consumer.accept(blockState, new Vec3(oX, oY, oZ)); } } } diff --git a/src/main/java/de/srendi/advancedperipherals/lib/peripherals/BasePeripheral.java b/src/main/java/de/srendi/advancedperipherals/lib/peripherals/BasePeripheral.java index 1f1ac4100..342ffb10e 100644 --- a/src/main/java/de/srendi/advancedperipherals/lib/peripherals/BasePeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/lib/peripherals/BasePeripheral.java @@ -8,6 +8,7 @@ import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IDynamicPeripheral; import dan200.computercraft.api.peripheral.IPeripheral; +import de.srendi.advancedperipherals.common.addons.APAddons; import de.srendi.advancedperipherals.common.addons.computercraft.owner.IPeripheralOwner; import de.srendi.advancedperipherals.common.addons.computercraft.owner.OperationAbility; import de.srendi.advancedperipherals.common.addons.computercraft.owner.PeripheralOwnerAbility; @@ -15,6 +16,10 @@ 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.valkyrienskies.core.api.ships.Ship; + import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -131,10 +136,35 @@ protected BlockPos getPos() { return owner.getPos(); } + protected Vec3 getCenterPos() { + return owner.getCenterPos(); + } + protected Level getLevel() { return owner.getLevel(); } + protected boolean isOnShip() { + return APAddons.vs2Loaded && APAddons.isBlockOnShip(owner.getLevel(), owner.getPos()); + } + + protected Vec3 getWorldPos() { + Vec3 pos = this.getCenterPos(); + if (!APAddons.vs2Loaded) { + return pos; + } + Ship ship = APAddons.getVS2Ship(owner.getLevel(), owner.getPos()); + if (ship == null) { + return pos; + } + Vector3d newPos = ship.getShipToWorld().transformPosition(new Vector3d(pos.x, pos.y, pos.z)); + return new Vec3(newPos.x, newPos.y, newPos.z); + } + + protected final BlockPos getWorldBlockPos() { + return new BlockPos(this.getWorldPos()); + } + protected Direction validateSide(String direction) throws LuaException { return CoordUtil.getDirection(owner.getOrientation(), direction); } diff --git a/src/main/java/de/srendi/advancedperipherals/lib/peripherals/BasePeripheralPlugin.java b/src/main/java/de/srendi/advancedperipherals/lib/peripherals/BasePeripheralPlugin.java new file mode 100644 index 000000000..af158aecc --- /dev/null +++ b/src/main/java/de/srendi/advancedperipherals/lib/peripherals/BasePeripheralPlugin.java @@ -0,0 +1,34 @@ +package de.srendi.advancedperipherals.lib.peripherals; + +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.MethodResult; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.IPeripheralOwner; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.OperationAbility; +import de.srendi.advancedperipherals.common.addons.computercraft.owner.PeripheralOwnerAbility; + +import org.jetbrains.annotations.Nullable; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +public abstract class BasePeripheralPlugin implements IPeripheralPlugin { + protected final IPeripheralOwner owner; + + public BasePeripheralPlugin(IPeripheralOwner owner) { + this.owner = owner; + } + + public IPeripheralOwner getPeripheralOwner() { + return this.owner; + } + + protected MethodResult withOperation(IPeripheralOperation operation, T context, @Nullable IPeripheralCheck check, IPeripheralFunction method, @Nullable Consumer successCallback) throws LuaException { + return withOperation(operation, context, check, method, successCallback, null); + } + + protected MethodResult withOperation(IPeripheralOperation operation, T context, @Nullable IPeripheralCheck check, IPeripheralFunction method, @Nullable Consumer successCallback, @Nullable BiConsumer failCallback) throws LuaException { + OperationAbility operationAbility = this.owner.getAbility(PeripheralOwnerAbility.OPERATION); + if (operationAbility == null) throw new IllegalArgumentException("This shouldn't happen at all"); + return operationAbility.performOperation(operation, context, check, method, successCallback, failCallback); + } +}