diff --git a/common/build.gradle b/common/build.gradle index 4b0d5a6b3..2de1338c5 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -17,6 +17,8 @@ dependencies { exclude module: "fastutil" } + 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 diff --git a/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java b/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java index 94b1c5eb3..7b5178cfc 100644 --- a/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java +++ b/common/src/main/java/org/valkyrienskies/mod/mixin/entity/MixinEntity.java @@ -31,7 +31,6 @@ import org.valkyrienskies.core.api.ships.LoadedShip; import org.valkyrienskies.core.api.ships.Ship; import org.valkyrienskies.core.api.ships.properties.ShipTransform; -import org.valkyrienskies.core.impl.game.ships.ShipObjectClient; import org.valkyrienskies.mod.common.entity.ShipMountedToData; import org.valkyrienskies.mod.common.VSGameUtilsKt; import org.valkyrienskies.mod.common.util.EntityDraggingInformation; @@ -112,8 +111,8 @@ private void preGetEyePosition(final float partialTicks, final CallbackInfoRetur final LoadedShip shipMountedTo = shipMountedToData.getShipMountedTo(); final ShipTransform shipTransform; - if (shipMountedTo instanceof ShipObjectClient) { - shipTransform = ((ShipObjectClient) shipMountedTo).getRenderTransform(); + if (shipMountedTo instanceof ClientShip) { + shipTransform = ((ClientShip) shipMountedTo).getRenderTransform(); } else { shipTransform = shipMountedTo.getShipTransform(); } 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 fce1429bb..1e79554e9 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 @@ -124,6 +124,14 @@ public VSPipeline getVsPipeline() { ) ) private void postCreateLevels(final CallbackInfo ci) { + // Register blocks + if (!MassDatapackResolver.INSTANCE.getRegisteredBlocks()) { + final List blockStateList = new ArrayList<>(Block.BLOCK_STATE_REGISTRY.size()); + Block.BLOCK_STATE_REGISTRY.forEach((blockStateList::add)); + MassDatapackResolver.INSTANCE.registerAllBlockStates(blockStateList); + ValkyrienSkiesMod.getVsCore().registerBlockStates(MassDatapackResolver.INSTANCE.getBlockStateData()); + } + // Load ship data from the world storage final ShipSavedData shipSavedData = overworld().getDataStorage() .computeIfAbsent(ShipSavedData::load, ShipSavedData.Companion::createEmpty, ShipSavedData.SAVED_DATA_ID); @@ -140,18 +148,6 @@ private void postCreateLevels(final CallbackInfo ci) { // Create ship world and VS Pipeline vsPipeline = shipSavedData.getPipeline(); - // Register blocks - if (!MassDatapackResolver.INSTANCE.getRegisteredBlocks()) { - final List blockStateList = new ArrayList<>(Block.BLOCK_STATE_REGISTRY.size()); - Block.BLOCK_STATE_REGISTRY.forEach((blockStateList::add)); - MassDatapackResolver.INSTANCE.registerAllBlockStates(blockStateList); - } - vsPipeline.registerBlocks( - MassDatapackResolver.INSTANCE.getSolidBlockStates(), - MassDatapackResolver.INSTANCE.getLiquidBlockStates(), - MassDatapackResolver.INSTANCE.getBlockStateData() - ); - KrunchSupport.INSTANCE.setKrunchSupported(!vsPipeline.isUsingDummyPhysics()); shipWorld = vsPipeline.getShipWorld(); 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 c98ced9b7..20bf2a70d 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 @@ -7,7 +7,6 @@ import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -48,13 +47,10 @@ import org.valkyrienskies.core.api.ships.LoadedServerShip; import org.valkyrienskies.core.api.ships.Wing; import org.valkyrienskies.core.api.ships.WingManager; -import org.valkyrienskies.core.api.ships.datastructures.ShipConnDataAttachment; import org.valkyrienskies.core.apigame.world.ServerShipWorldCore; import org.valkyrienskies.core.apigame.world.chunks.TerrainUpdate; -import org.valkyrienskies.core.util.datastructures.Breakage; import org.valkyrienskies.mod.common.IShipObjectWorldServerProvider; import org.valkyrienskies.mod.common.VSGameUtilsKt; -import org.valkyrienskies.mod.common.assembly.SubShipAssemblyKt; import org.valkyrienskies.mod.common.block.WingBlock; import org.valkyrienskies.mod.common.util.VSServerLevel; import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; @@ -248,23 +244,6 @@ private void postTick(final BooleanSupplier shouldKeepTicking, final CallbackInf voxelShapeUpdates ); - // Process pending ship breakages - for (final LoadedServerShip loadedShip : shipObjectWorld.getLoadedShips()) { - if (loadedShip.getAttachment(ShipConnDataAttachment.class) instanceof ShipConnDataAttachment) { - ShipConnDataAttachment connData = loadedShip.getAttachment(ShipConnDataAttachment.class); - assert connData != null; - HashSet shipBreakages = (HashSet) connData.getBreakages(); - Iterator breakageIterator = shipBreakages.iterator(); - - while (breakageIterator.hasNext()) { - Object breakage = breakageIterator.next(); - if (breakage instanceof Breakage breaking) { - SubShipAssemblyKt.splitShip(VectorConversionsMCKt.toBlockPos(breaking.component1()), breaking.component2(), self, loadedShip); - breakageIterator.remove(); - } - } - } - } } @Override diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/api/VsAPI.kt b/common/src/main/kotlin/org/valkyrienskies/mod/api/VsAPI.kt new file mode 100644 index 000000000..270bf4ebc --- /dev/null +++ b/common/src/main/kotlin/org/valkyrienskies/mod/api/VsAPI.kt @@ -0,0 +1,56 @@ +package org.valkyrienskies.mod.api + +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.level.ServerLevel +import net.minecraft.world.entity.Entity + +import org.jetbrains.annotations.ApiStatus.* +import org.valkyrienskies.core.api.VsCoreApi +import org.valkyrienskies.core.api.event.ListenableEvent +import org.valkyrienskies.core.api.ships.* +import org.valkyrienskies.mod.api.events.PostRenderShipEvent +import org.valkyrienskies.mod.api.events.PreRenderShipEvent +import org.valkyrienskies.mod.api.events.RegisterBlockStateEvent + +@NonExtendable +interface VsApi : VsCoreApi { + + /** + * This event gets called when it's time to register physics block states for Minecraft block states. + */ + @get:Experimental + val registerBlockStateEvent: ListenableEvent + + @get:Experimental + val preRenderShipEvent: ListenableEvent + + @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. + * + * If either parameter is null, this will return null. + * + * @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]. + * + * @param pos A block position in the Shipyard + */ + fun getShipManagingBlock(level: Level?, pos: BlockPos?): Ship? + + fun getShipManagingChunk(level: Level?, pos: ChunkPos?): Ship? + + fun getShipManagingChunk(level: Level?, chunkX: Int, chunkZ: Int): Ship? +} diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/api/events/PostRenderShipEvent.kt b/common/src/main/kotlin/org/valkyrienskies/mod/api/events/PostRenderShipEvent.kt new file mode 100644 index 000000000..33bbd6de3 --- /dev/null +++ b/common/src/main/kotlin/org/valkyrienskies/mod/api/events/PostRenderShipEvent.kt @@ -0,0 +1,6 @@ +package org.valkyrienskies.mod.api.events + +import org.jetbrains.annotations.ApiStatus.Experimental + +@Experimental +interface PostRenderShipEvent diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/api/events/PreRenderShipEvent.kt b/common/src/main/kotlin/org/valkyrienskies/mod/api/events/PreRenderShipEvent.kt new file mode 100644 index 000000000..2d99dbf51 --- /dev/null +++ b/common/src/main/kotlin/org/valkyrienskies/mod/api/events/PreRenderShipEvent.kt @@ -0,0 +1,6 @@ +package org.valkyrienskies.mod.api.events + +import org.jetbrains.annotations.ApiStatus.Experimental + +@Experimental +interface PreRenderShipEvent diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/api/events/RegisterBlockStateEvent.kt b/common/src/main/kotlin/org/valkyrienskies/mod/api/events/RegisterBlockStateEvent.kt new file mode 100644 index 000000000..12800615b --- /dev/null +++ b/common/src/main/kotlin/org/valkyrienskies/mod/api/events/RegisterBlockStateEvent.kt @@ -0,0 +1,25 @@ +package org.valkyrienskies.mod.api.events + +import net.minecraft.world.level.block.state.BlockState +import org.jetbrains.annotations.ApiStatus.Experimental +import org.valkyrienskies.core.api.physics.blockstates.LiquidState +import org.valkyrienskies.core.api.physics.blockstates.SolidState + +@Experimental +interface RegisterBlockStateEvent { + + fun newLiquidStateBuilder(): LiquidState.Builder + fun buildLiquidState(block: LiquidState.Builder.() -> Unit): LiquidState + fun newSolidStateBuilder(): SolidState.Builder + fun buildSolidState(block: SolidState.Builder.() -> Unit): SolidState + + fun register(state: BlockState, solidState: SolidState) + fun register(state: BlockState, liquidState: LiquidState) + + /** + * Registers the Minecraft [state] to be represented by [LiquidState] and [SolidState] in the same block. + * This is useful for e.g., a waterlogged chest, where the [liquidState] would be water and the [solidState] would + * be the chest shape. + */ + fun register(state: BlockState, liquidState: LiquidState, solidState: SolidState) +} diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/api_impl/events/RegisterBlockStateEventImpl.kt b/common/src/main/kotlin/org/valkyrienskies/mod/api_impl/events/RegisterBlockStateEventImpl.kt new file mode 100644 index 000000000..683019ebe --- /dev/null +++ b/common/src/main/kotlin/org/valkyrienskies/mod/api_impl/events/RegisterBlockStateEventImpl.kt @@ -0,0 +1,36 @@ +package org.valkyrienskies.mod.api_impl.events + +import net.minecraft.world.level.block.state.BlockState +import org.valkyrienskies.core.api.physics.blockstates.LiquidState +import org.valkyrienskies.core.api.physics.blockstates.SolidState +import org.valkyrienskies.core.apigame.physics.blockstates.VsBlockState +import org.valkyrienskies.mod.api.events.RegisterBlockStateEvent +import org.valkyrienskies.mod.common.ValkyrienSkiesMod.vsCore + +class RegisterBlockStateEventImpl : RegisterBlockStateEvent { + val toRegister = mutableListOf>() + + override fun newLiquidStateBuilder(): LiquidState.Builder = + vsCore.newLiquidStateBuilder() + + override fun buildLiquidState(block: LiquidState.Builder.() -> Unit): LiquidState = + vsCore.newLiquidStateBuilder().apply(block).build() + + override fun newSolidStateBuilder(): SolidState.Builder = + vsCore.newSolidStateBuilder() + + override fun buildSolidState(block: SolidState.Builder.() -> Unit): SolidState = + vsCore.newSolidStateBuilder().apply(block).build() + + override fun register(state: BlockState, solidState: SolidState) { + toRegister.add(Pair(state, VsBlockState(solidState, null))) + } + + override fun register(state: BlockState, liquidState: LiquidState) { + toRegister.add(Pair(state, VsBlockState(null, liquidState))) + } + + override fun register(state: BlockState, liquidState: LiquidState, solidState: SolidState) { + toRegister.add(Pair(state, VsBlockState(solidState, liquidState))) + } +} 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 new file mode 100644 index 000000000..3749d133e --- /dev/null +++ b/common/src/main/kotlin/org/valkyrienskies/mod/api_impl/events/VSApiImpl.kt @@ -0,0 +1,44 @@ +package org.valkyrienskies.mod.api_impl.events + +import net.minecraft.client.gui.screens.Screen +import net.minecraft.core.BlockPos +import net.minecraft.world.entity.Entity +import net.minecraft.world.level.ChunkPos +import net.minecraft.world.level.Level +import org.valkyrienskies.core.api.ships.Ship +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.getShipManagingPos +import org.valkyrienskies.mod.compat.clothconfig.VSClothConfig + +class VsApiImpl : VsApi { + + 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 { + return VSClothConfig.createConfigScreenFor(parent, *configs) + } + + + override fun getShipManagingBlock(level: Level?, pos: BlockPos?): Ship? { + return pos?.let { level?.getShipManagingPos(it) } + } + + override fun getShipManagingChunk(level: Level?, pos: ChunkPos?): Ship? { + return pos?.let { level?.getShipManagingPos(it) } + } + + override fun getShipManagingChunk(level: Level?, chunkX: Int, chunkZ: Int): Ship? { + return level?.getShipManagingPos(chunkX, chunkZ) + } +} 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 4a6ce7419..129d47e3a 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/BlockStateInfoProvider.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/BlockStateInfoProvider.kt @@ -17,11 +17,6 @@ import org.valkyrienskies.core.apigame.world.chunks.BlockType import org.valkyrienskies.mod.common.block.WingBlock import org.valkyrienskies.mod.common.config.MassDatapackResolver import org.valkyrienskies.mod.common.hooks.VSGameEvents -import org.valkyrienskies.physics_api.Lod1BlockStateId -import org.valkyrienskies.physics_api.Lod1LiquidBlockStateId -import org.valkyrienskies.physics_api.Lod1SolidBlockStateId -import org.valkyrienskies.physics_api.voxel.Lod1LiquidBlockState -import org.valkyrienskies.physics_api.voxel.Lod1SolidBlockState import java.util.function.IntFunction // Other mods can then provide weights and types based on their added content @@ -35,10 +30,6 @@ interface BlockStateInfoProvider { // Get the id of the block state fun getBlockStateType(blockState: BlockState): BlockType? - - val solidBlockStates: List - val liquidBlockStates: List - val blockStateData: List> } object BlockStateInfo { diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/DefaultBlockStateInfoProvider.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/DefaultBlockStateInfoProvider.kt index e408f6cf6..fc8ebaf03 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/DefaultBlockStateInfoProvider.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/DefaultBlockStateInfoProvider.kt @@ -1,36 +1,26 @@ package org.valkyrienskies.mod.common +import net.minecraft.world.level.block.Blocks +import net.minecraft.world.level.block.LiquidBlock import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.level.material.Material import org.valkyrienskies.core.apigame.world.chunks.BlockType -import org.valkyrienskies.physics_api.Lod1BlockStateId -import org.valkyrienskies.physics_api.Lod1LiquidBlockStateId -import org.valkyrienskies.physics_api.Lod1SolidBlockStateId -import org.valkyrienskies.physics_api.voxel.Lod1LiquidBlockState -import org.valkyrienskies.physics_api.voxel.Lod1SolidBlockState object DefaultBlockStateInfoProvider : BlockStateInfoProvider { override val priority: Int get() = Int.MIN_VALUE - override val solidBlockStates: List - get() = TODO() - override val liquidBlockStates: List - get() = TODO() - override val blockStateData: List> - get() = TODO() override fun getBlockStateMass(blockState: BlockState): Double { if (blockState.isAir) return 0.0 - // By default make blocks weight 100 kg - return 100.0 + // By default make blocks weight 1000 kg + return 1000.0 } override fun getBlockStateType(blockState: BlockState): BlockType { if (blockState.isAir) return vsCore.blockTypes.air - val blockMaterial = blockState.material - if (blockMaterial.isLiquid) - return if (blockMaterial == Material.LAVA) vsCore.blockTypes.lava else vsCore.blockTypes.water - return if (blockMaterial.isSolid) vsCore.blockTypes.solid else vsCore.blockTypes.noCollision + val block = blockState.block + if (block is LiquidBlock) + return if (block == Blocks.LAVA) vsCore.blockTypes.lava else vsCore.blockTypes.water + return if (blockState.material.isSolid) vsCore.blockTypes.solid else vsCore.blockTypes.air } } 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 9368ad3fd..d917c4797 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/VSGameUtils.kt @@ -208,7 +208,7 @@ inline fun Level?.transformToNearbyShipsAndWorld( cb(posInWorld.x(), posInWorld.y(), posInWorld.z()) } - for (nearbyShip in shipObjectWorld.allShips.getIntersecting(aabb)) { + for (nearbyShip in shipObjectWorld.allShips.getIntersecting(aabb, this!!.dimensionId)) { if (nearbyShip == currentShip) continue val posInShip = nearbyShip.worldToShip.transformPosition(posInWorld, temp0) cb(posInShip.x(), posInShip.y(), posInShip.z()) @@ -393,8 +393,7 @@ fun Level?.getWorldCoordinates(blockPos: BlockPos, pos: Vector3d): Vector3d { } fun Level.getShipsIntersecting(aabb: AABB): Iterable = getShipsIntersecting(aabb.toJOML()) -fun Level.getShipsIntersecting(aabb: AABBdc): Iterable = allShips.getIntersecting(aabb).filter { it.chunkClaimDimension == dimensionId } - +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 { 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 6dac43e54..f5f20b0b7 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/ValkyrienSkiesMod.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/ValkyrienSkiesMod.kt @@ -8,8 +8,6 @@ import net.minecraft.world.level.block.entity.BlockEntityType import org.valkyrienskies.core.api.ships.setAttachment import org.valkyrienskies.core.apigame.VSCore import org.valkyrienskies.core.apigame.VSCoreClient -import org.valkyrienskies.core.impl.config.VSConfigClass -import org.valkyrienskies.core.impl.config.VSCoreConfig import org.valkyrienskies.core.impl.hooks.VSEvents import org.valkyrienskies.mod.common.blockentity.TestHingeBlockEntity import org.valkyrienskies.mod.common.config.VSGameConfig @@ -50,8 +48,7 @@ object ValkyrienSkiesMod { VSGamePackets.register() VSGamePackets.registerHandlers() - VSConfigClass.registerConfig("vs_core", VSCoreConfig::class.java) - VSConfigClass.registerConfig("vs", VSGameConfig::class.java) + core.registerConfigLegacy("vs", VSGameConfig::class.java) VSEvents.ShipLoadEvent.on { event -> event.ship.setAttachment(GameTickForceApplier()) } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/AssemblyUtil.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/AssemblyUtil.kt new file mode 100644 index 000000000..78199a624 --- /dev/null +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/AssemblyUtil.kt @@ -0,0 +1,147 @@ +package org.valkyrienskies.mod.common.assembly + +import net.minecraft.core.BlockPos +import net.minecraft.core.Direction +import net.minecraft.nbt.CompoundTag +import net.minecraft.util.Mth +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.state.BlockState +import net.minecraft.world.level.chunk.LevelChunk +import net.minecraft.world.ticks.ScheduledTick +import org.joml.Vector3d +import org.joml.Vector3i + +private val AIR = Blocks.AIR.defaultBlockState() +object AssemblyUtil { + + fun setBlock(level: Level, pos: BlockPos, state: BlockState?) { + val chunk = level.getChunk(pos) as LevelChunk + val section = chunk.getSection(chunk.getSectionIndex(pos.y)) + val oldState = level.getBlockState(pos) + section.setBlockState(pos.x and 15, pos.y and 15, pos.z and 15, state) + ShipAssembler.triggerBlockChange(level, pos, oldState, state) + } + + fun removeBlock(level: Level, pos: BlockPos) { + level.removeBlockEntity(pos) + setBlock(level, pos, Blocks.AIR.defaultBlockState()) + } + + fun copyBlock(level: Level, from: BlockPos?, to: BlockPos) { + val state = level.getBlockState(from) + val blockentity = level.getBlockEntity(from) + setBlock(level, to, state) + + // Transfer pending schedule-ticks + if (level.blockTicks.hasScheduledTick(from, state.block)) { + level.blockTicks.schedule(ScheduledTick(state.block, to, 0, 0)) + } + + // Transfer block-entity data + if (state.hasBlockEntity() && blockentity != null) { + val data: CompoundTag = blockentity.saveWithId() + level.setBlockEntity(blockentity) + val newBlockentity = level.getBlockEntity(to) + newBlockentity?.load(data) + } + } + + fun updateBlock(level: Level, fromPos: BlockPos, toPos: BlockPos, toState: BlockState) { + + // 75 = flag 1 (block update) & flag 2 (send to clients) + flag 8 (force rerenders) + val flags = 11 + + //updateNeighbourShapes recurses through nearby blocks, recursionLeft is the limit + val recursionLeft = 511 + + level.setBlocksDirty(fromPos, toState, AIR) + level.sendBlockUpdated(fromPos, toState, AIR, flags) + level.blockUpdated(fromPos, AIR.block) + // This handles the update for neighboring blocks in worldspace + AIR.updateIndirectNeighbourShapes(level, fromPos, flags, recursionLeft - 1) + AIR.updateNeighbourShapes(level, fromPos, flags, recursionLeft) + AIR.updateIndirectNeighbourShapes(level, fromPos, flags, recursionLeft) + //This updates lighting for blocks in worldspace + level.chunkSource.lightEngine.checkBlock(fromPos) + + level.setBlocksDirty(toPos, AIR, toState) + level.sendBlockUpdated(toPos, AIR, toState, flags) + level.blockUpdated(toPos, toState.block) + if (!level.isClientSide && toState.hasAnalogOutputSignal()) { + level.updateNeighbourForOutputSignal(toPos, toState.block) + } + //This updates lighting for blocks in shipspace + level.chunkSource.lightEngine.checkBlock(toPos) + } + + fun toBlockPos(x: Double, y: Double, z: Double): BlockPos { + return BlockPos(Mth.floor(x), Math.floor(y).toInt(), Math.floor(z).toInt()) + } + + fun toBlockPos(vec: Vector3d): BlockPos { + return toBlockPos(vec.x, vec.y, vec.z) + } + + fun getVecDirection(v: Vector3i): Direction { + var axis = Direction.Axis.X + if (v.y() != 0) axis = Direction.Axis.Y + if (v.z() != 0) axis = Direction.Axis.Z + val direction = if (v.x + v.y + v.z > 0) Direction.AxisDirection.POSITIVE else Direction.AxisDirection.NEGATIVE + return Direction.fromAxisAndDirection(axis, direction) + } + + fun getMinCorner(pos1: BlockPos, pos2: BlockPos): BlockPos { + return BlockPos( + Math.min(pos1.x, pos2.x), + Math.min(pos1.y, pos2.y), + Math.min(pos1.z, pos2.z) + ) + } + + fun getMaxCorner(pos1: BlockPos, pos2: BlockPos): BlockPos { + return BlockPos( + Math.max(pos1.x, pos2.x), + Math.max(pos1.y, pos2.y), + Math.max(pos1.z, pos2.z) + ) + } + + fun getMiddle(pos1: BlockPos, pos2: BlockPos): Vector3i { + val middleX = Math.min(pos1.x, pos2.x).toDouble() + (Math.max(pos1.x, pos2.x) - Math.min( + pos1.x, + pos2.x + ) + 1) / 2 + val middleY = Math.min(pos1.y, pos2.y).toDouble() + (Math.max(pos1.y, pos2.y) - Math.min( + pos1.y, + pos2.y + ) + 1) / 2 + val middleZ = Math.min(pos1.z, pos2.z).toDouble() + (Math.max(pos1.z, pos2.z) - Math.min( + pos1.z, + pos2.z + ) + 1) / 2 + return Vector3i(middleX.toInt(), middleY.toInt(), middleZ.toInt()) + } + + fun getMiddle(pos1: Vector3d, pos2: Vector3d): Vector3d { + val middleX = Math.min(pos1.x, pos2.x) + (Math.max(pos1.x, pos2.x) - Math.min( + pos1.x, + pos2.x + )) / 2.0 + val middleY = Math.min(pos1.y, pos2.y) + (Math.max(pos1.y, pos2.y) - Math.min( + pos1.y, + pos2.y + )) / 2.0 + val middleZ = Math.min(pos1.z, pos2.z) + (Math.max(pos1.z, pos2.z) - Math.min( + pos1.z, + pos2.z + )) / 2.0 + return Vector3d(middleX, middleY, middleZ) + } + + + + + +} 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 bb8aac7ab..f79def783 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 @@ -12,7 +12,6 @@ import net.minecraft.world.level.ChunkPos 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.impl.networking.simple.registerClientHandler import org.valkyrienskies.core.util.pollUntilEmpty import org.valkyrienskies.mod.common.getShipManagingPos import org.valkyrienskies.mod.common.isChunkInShipyard @@ -44,12 +43,14 @@ class SeamlessChunksManager(private val listener: ClientPacketListener) { private val stalledChunks = LongOpenHashSet() init { - PacketStopChunkUpdates::class.registerClientHandler { (chunks) -> - chunks.forEach { stalledChunks.add(it.toMinecraft().toLong()) } - } - PacketRestartChunkUpdates::class.registerClientHandler { packet -> - Minecraft.getInstance().execute { - onRestartUpdates(packet) + with(vsCore.simplePacketNetworking) { + PacketStopChunkUpdates::class.registerClientHandler { (chunks) -> + chunks.forEach { stalledChunks.add(it.toMinecraft().toLong()) } + } + PacketRestartChunkUpdates::class.registerClientHandler { packet -> + Minecraft.getInstance().execute { + onRestartUpdates(packet) + } } } 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 new file mode 100644 index 000000000..7ee1c79b1 --- /dev/null +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/ShipAssembler.kt @@ -0,0 +1,115 @@ +package org.valkyrienskies.mod.common.assembly + +import net.minecraft.core.BlockPos +import net.minecraft.server.level.ServerLevel +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.Blocks +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.ships.ServerShip +import org.valkyrienskies.core.api.ships.Ship +import org.valkyrienskies.core.impl.game.ShipTeleportDataImpl +import org.valkyrienskies.mod.common.BlockStateInfo.onSetBlock +import org.valkyrienskies.mod.common.dimensionId +import org.valkyrienskies.mod.common.getShipObjectManagingPos +import org.valkyrienskies.mod.common.shipObjectWorld + +object ShipAssembler { + + fun triggerBlockChange(level: Level?, pos: BlockPos?, prevState: BlockState?, newState: BlockState?) { + onSetBlock(level!!, pos!!, prevState!!, newState!!) + } + + fun isValidShipBlock(state: BlockState?): Boolean { + if (state != null) { + //return !state.tags.anyMatch { it== VsShipAssemblerTags.FORBIDDEN_ASSEMBLE } + return !state.isAir + } + return true + } + + + fun assembleToShip(level: Level, blocks: List, removeOriginal: Boolean, scale: Double): ServerShip { + assert(level is ServerLevel) { "Can't manage contraptions on client side!" } + val sLevel: ServerLevel = level as ServerLevel + if (blocks.isEmpty()) { + throw IllegalArgumentException() + } + + val existingShip = sLevel.getShipObjectManagingPos(blocks.find { !sLevel.getBlockState(it).isAir } ?: throw IllegalArgumentException()) + + var structureCornerMin: BlockPos = blocks[0] + var structureCornerMax: BlockPos = blocks[0] + var hasSolids = false + + // Calculate bounds of the area containing all blocks adn check for solids and invalid blocks + for (itPos in blocks) { + if (isValidShipBlock(level.getBlockState(itPos))) { + structureCornerMin = AssemblyUtil.getMinCorner(structureCornerMin, itPos) + structureCornerMax = AssemblyUtil.getMaxCorner(structureCornerMax, itPos) + hasSolids = true + } + } + if (!hasSolids) throw IllegalArgumentException("No solid blocks found in the structure") + val contraptionOGPos: Vector3ic = AssemblyUtil.getMiddle(structureCornerMin, structureCornerMax) + // Create new contraption at center of bounds + val contraptionWorldPos: Vector3i = if (existingShip != null) { + val doubleVer = existingShip.shipToWorld.transformPosition(Vector3d(contraptionOGPos)).floor() + Vector3i(doubleVer.x.toInt(), doubleVer.y.toInt(), doubleVer.z.toInt()) + } else { + Vector3i(contraptionOGPos) + } + //val contraptionPosition = ContraptionPosition(Quaterniond(Vec3d(0.0, 1.0, 1.0), 0.0), contraptionWorldPos, null) + + val newShip: Ship = (level as ServerLevel).server.shipObjectWorld + .createNewShipAtBlock(contraptionWorldPos, false, scale, level.dimensionId) + + // Stone for safety reasons + + val contraptionShipPos = newShip.worldToShip.transformPosition(Vector3d(contraptionWorldPos.x.toDouble(),contraptionWorldPos.y.toDouble(),contraptionWorldPos.z.toDouble())) + val contraptionBlockPos = BlockPos(contraptionShipPos.x.toInt(),contraptionShipPos.y.toInt(),contraptionShipPos.z.toInt()) + + + // Copy blocks and check if the center block got replaced (is default a stone block) + var centerBlockReplaced = false + for (itPos in blocks) { + if (isValidShipBlock(level.getBlockState(itPos))) { + val relative: BlockPos = itPos.subtract( BlockPos(contraptionOGPos.x(),contraptionOGPos.y(),contraptionOGPos.z())) + val shipPos: BlockPos = contraptionBlockPos.offset(relative) + AssemblyUtil.copyBlock(level, itPos, shipPos) + if (relative == BlockPos.ZERO) centerBlockReplaced = true + } + } + + // If center block got not replaced, remove the stone block + if (!centerBlockReplaced) { + level.setBlock(contraptionBlockPos, Blocks.AIR.defaultBlockState(), 3) + } + + // Remove original blocks + if (removeOriginal) { + for (itPos in blocks) { + if (isValidShipBlock(level.getBlockState(itPos))) { + AssemblyUtil.removeBlock(level, itPos) + } + } + } + + // Trigger updates on both contraptions + for (itPos in blocks) { + val relative: BlockPos = itPos.subtract(BlockPos(contraptionOGPos.x(),contraptionOGPos.y(),contraptionOGPos.z())) + val shipPos: BlockPos = contraptionBlockPos.offset(relative) + AssemblyUtil.updateBlock(level,itPos,shipPos,level.getBlockState(shipPos)) + } + + + sLevel.server.shipObjectWorld + .teleportShip(newShip as ServerShip, ShipTeleportDataImpl(Vector3d(contraptionWorldPos.x.toDouble(),contraptionWorldPos.y.toDouble(),contraptionWorldPos.z.toDouble()))) + + return newShip as ServerShip + } + + +} diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/ShipAssembly.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/ShipAssembly.kt index 8df8aea74..b3ea1c640 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/ShipAssembly.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/ShipAssembly.kt @@ -5,10 +5,9 @@ import net.minecraft.server.level.ServerLevel import net.minecraft.world.level.ChunkPos import org.joml.Vector3d import org.valkyrienskies.core.api.ships.ServerShip -import org.valkyrienskies.core.util.datastructures.DenseBlockPosSet import org.valkyrienskies.core.impl.game.ships.ShipData import org.valkyrienskies.core.impl.game.ships.ShipTransformImpl -import org.valkyrienskies.core.impl.networking.simple.sendToClient +import org.valkyrienskies.core.util.datastructures.DenseBlockPosSet import org.valkyrienskies.mod.common.dimensionId import org.valkyrienskies.mod.common.executeIf import org.valkyrienskies.mod.common.isTickingChunk @@ -16,93 +15,20 @@ import org.valkyrienskies.mod.common.networking.PacketRestartChunkUpdates import org.valkyrienskies.mod.common.networking.PacketStopChunkUpdates import org.valkyrienskies.mod.common.playerWrapper 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.vsCore import org.valkyrienskies.mod.util.relocateBlock import org.valkyrienskies.mod.util.updateBlock +@Deprecated("Use ShipAssembler.assembleToShip instead") fun createNewShipWithBlocks( centerBlock: BlockPos, blocks: DenseBlockPosSet, level: ServerLevel ): ServerShip { if (blocks.isEmpty()) throw IllegalArgumentException() - val ship = level.shipObjectWorld.createNewShipAtBlock(centerBlock.toJOML(), false, 1.0, level.dimensionId) - - val shipChunkX = ship.chunkClaim.xMiddle - val shipChunkZ = ship.chunkClaim.zMiddle - - val worldChunkX = centerBlock.x shr 4 - val worldChunkZ = centerBlock.z shr 4 - - val deltaX = worldChunkX - shipChunkX - val deltaZ = worldChunkZ - shipChunkZ - - val chunksToBeUpdated = mutableMapOf>() - blocks.forEachChunk { x, _, z, _ -> - val sourcePos = ChunkPos(x, z) - val destPos = ChunkPos(x - deltaX, z - deltaZ) - chunksToBeUpdated[sourcePos] = Pair(sourcePos, destPos) - } - val chunkPairs = chunksToBeUpdated.values.toList() - val chunkPoses = chunkPairs.flatMap { it.toList() } - val chunkPosesJOML = chunkPoses.map { it.toJOML() } - - // Send a list of all the chunks that we plan on updating to players, so that they - // defer all updates until assembly is finished - level.players().forEach { player -> - PacketStopChunkUpdates(chunkPosesJOML).sendToClient(player.playerWrapper) - } - - // Use relocateBlock to copy all the blocks into the ship - blocks.forEachChunk { chunkX, chunkY, chunkZ, chunk -> - val sourceChunk = level.getChunk(chunkX, chunkZ) - val destChunk = level.getChunk(chunkX - deltaX, chunkZ - deltaZ) - - chunk.forEach { x, y, z -> - val fromPos = BlockPos((sourceChunk.pos.x shl 4) + x, (chunkY shl 4) + y, (sourceChunk.pos.z shl 4) + z) - val toPos = BlockPos((destChunk.pos.x shl 4) + x, (chunkY shl 4) + y, (destChunk.pos.z shl 4) + z) - - relocateBlock(sourceChunk, fromPos, destChunk, toPos, false, ship) - } - } - - // Use updateBlock to update blocks after copying - blocks.forEachChunk { chunkX, chunkY, chunkZ, chunk -> - val sourceChunk = level.getChunk(chunkX, chunkZ) - val destChunk = level.getChunk(chunkX - deltaX, chunkZ - deltaZ) - - chunk.forEach { x, y, z -> - val fromPos = BlockPos((sourceChunk.pos.x shl 4) + x, (chunkY shl 4) + y, (sourceChunk.pos.z shl 4) + z) - val toPos = BlockPos((destChunk.pos.x shl 4) + x, (chunkY shl 4) + y, (destChunk.pos.z shl 4) + z) - - updateBlock(destChunk.level, fromPos, toPos, destChunk.getBlockState(toPos)) - } - } - - // Calculate the position of the block that the player clicked after it has been assembled - val centerInShip = Vector3d( - ((shipChunkX shl 4) + (centerBlock.x and 15)).toDouble(), - centerBlock.y.toDouble(), - ((shipChunkZ shl 4) + (centerBlock.z and 15)).toDouble() - ) - - // The ship's position has shifted from the center block since we assembled the ship, compensate for that - val centerBlockPosInWorld = ship.inertiaData.centerOfMassInShip.sub(centerInShip, Vector3d()) - .add(ship.transform.positionInWorld) - - // Put the ship into the compensated position, so that all the assembled blocks stay in the same place - // TODO: AAAAAAAAA THIS IS HORRIBLE how can the API support this? - (ship as ShipData).transform = (ship.transform as ShipTransformImpl).copy(positionInWorld = centerBlockPosInWorld) - - level.server.executeIf( - // This condition will return true if all modified chunks have been both loaded AND - // chunk update packets were sent to players - { chunkPoses.all(level::isTickingChunk) } - ) { - // Once all the chunk updates are sent to players, we can tell them to restart chunk updates - level.players().forEach { player -> - PacketRestartChunkUpdates(chunkPosesJOML).sendToClient(player.playerWrapper) - } - } + val blockList: MutableList = mutableListOf() - return ship + blocks.toList().forEach { blockList.add(it.toBlockPos()) } + return ShipAssembler.assembleToShip(level, blockList, true, 1.0) } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/SubShipAssembly.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/SubShipAssembly.kt deleted file mode 100644 index ff859a5c1..000000000 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/assembly/SubShipAssembly.kt +++ /dev/null @@ -1,140 +0,0 @@ -package org.valkyrienskies.mod.common.assembly - -import net.minecraft.core.BlockPos -import net.minecraft.server.level.ServerLevel -import net.minecraft.world.level.ChunkPos -import org.joml.Vector3d -import org.joml.Vector3dc -import org.valkyrienskies.core.api.ships.ServerShip -import org.valkyrienskies.core.impl.game.ships.ShipData -import org.valkyrienskies.core.impl.game.ships.ShipTransformImpl -import org.valkyrienskies.core.impl.networking.simple.sendToClient -import org.valkyrienskies.core.util.datastructures.DenseBlockPosSet -import org.valkyrienskies.core.util.x -import org.valkyrienskies.mod.common.dimensionId -import org.valkyrienskies.mod.common.executeIf -import org.valkyrienskies.mod.common.hooks.VSGameEvents -import org.valkyrienskies.mod.common.isTickingChunk -import org.valkyrienskies.mod.common.networking.PacketRestartChunkUpdates -import org.valkyrienskies.mod.common.networking.PacketStopChunkUpdates -import org.valkyrienskies.mod.common.playerWrapper -import org.valkyrienskies.mod.common.shipObjectWorld -import org.valkyrienskies.mod.common.util.settings -import org.valkyrienskies.mod.common.util.toJOML -import org.valkyrienskies.mod.common.util.toJOMLD -import org.valkyrienskies.mod.util.relocateBlock -import org.valkyrienskies.mod.util.updateBlock - -fun splitShip(centerBlock: BlockPos, blocks: DenseBlockPosSet, level: ServerLevel, originalShip: ServerShip): ServerShip { - if (blocks.isEmpty()) throw IllegalArgumentException() - - val ship = level.shipObjectWorld.createNewShipAtBlock(centerBlock.toJOML(), false, 1.0, level.dimensionId) - - val shipChunkX = ship.chunkClaim.xMiddle - val shipChunkZ = ship.chunkClaim.zMiddle - - val worldChunkX = centerBlock.x shr 4 - val worldChunkZ = centerBlock.z shr 4 - - val deltaX = worldChunkX - shipChunkX - val deltaZ = worldChunkZ - shipChunkZ - - val chunksToBeUpdated = mutableMapOf>() - blocks.forEachChunk { x, _, z, _ -> - val sourcePos = ChunkPos(x, z) - val destPos = ChunkPos(x - deltaX, z - deltaZ) - chunksToBeUpdated[sourcePos] = Pair(sourcePos, destPos) - } - val chunkPairs = chunksToBeUpdated.values.toList() - val chunkPoses = chunkPairs.flatMap { it.toList() } - val chunkPosesJOML = chunkPoses.map { it.toJOML() } - - // Send a list of all the chunks that we plan on updating to players, so that they - // defer all updates until assembly is finished - level.players().forEach { player -> - PacketStopChunkUpdates(chunkPosesJOML).sendToClient(player.playerWrapper) - } - - // Use relocateBlock to copy all the blocks into the ship - blocks.forEachChunk { chunkX, chunkY, chunkZ, chunk -> - val sourceChunk = level.getChunk(chunkX, chunkZ) - val destChunk = level.getChunk(chunkX - deltaX, chunkZ - deltaZ) - - chunk.forEach { x, y, z -> - val fromPos = BlockPos((sourceChunk.pos.x shl 4) + x, (chunkY shl 4) + y, (sourceChunk.pos.z shl 4) + z) - val toPos = BlockPos((destChunk.pos.x shl 4) + x, (chunkY shl 4) + y, (destChunk.pos.z shl 4) + z) - - relocateBlock(sourceChunk, fromPos, destChunk, toPos, false, ship) - } - } - - // Use updateBlock to update blocks after copying - blocks.forEachChunk { chunkX, chunkY, chunkZ, chunk -> - val sourceChunk = level.getChunk(chunkX, chunkZ) - val destChunk = level.getChunk(chunkX - deltaX, chunkZ - deltaZ) - - chunk.forEach { x, y, z -> - val fromPos = BlockPos((sourceChunk.pos.x shl 4) + x, (chunkY shl 4) + y, (sourceChunk.pos.z shl 4) + z) - val toPos = BlockPos((destChunk.pos.x shl 4) + x, (chunkY shl 4) + y, (destChunk.pos.z shl 4) + z) - - updateBlock(destChunk.level, fromPos, toPos, destChunk.getBlockState(toPos)) - } - } - - // Calculate the position of the block that the player clicked after it has been assembled - val centerInShip = Vector3d( - ((shipChunkX shl 4) + (centerBlock.x and 15)).toDouble(), - centerBlock.y.toDouble(), - ((shipChunkZ shl 4) + (centerBlock.z and 15)).toDouble() - ) - - // The ship's position has shifted from the center block since we assembled the ship, compensate for that - val centerBlockPosInWorld = ship.inertiaData.centerOfMassInShip.sub(centerInShip, Vector3d()) - .add(ship.transform.positionInWorld) - - // Put the ship into the compensated position, so that all the assembled blocks stay in the same place - // TODO: AAAAAAAAA THIS IS HORRIBLE how can the API support this? - (ship as ShipData).transform = (ship.transform as ShipTransformImpl).copy(positionInWorld = centerBlockPosInWorld) - - level.server.executeIf( - // This condition will return true if all modified chunks have been both loaded AND - // chunk update packets were sent to players - { chunkPoses.all(level::isTickingChunk) } - ) { - // Once all the chunk updates are sent to players, we can tell them to restart chunk updates - level.players().forEach { player -> - PacketRestartChunkUpdates(chunkPosesJOML).sendToClient(player.playerWrapper) - } - } - - val shipChunkXUpdated = ship.chunkClaim.xMiddle - val shipChunkZUpdated = ship.chunkClaim.zMiddle - - val centerPosCentered = centerBlock.toJOMLD().add(0.5, 0.5, 0.5) - - val centerInShipUpdated: Vector3dc = Vector3d( - ((shipChunkXUpdated shl 4) + (centerBlock.x and 15).toDouble()), - centerBlock.y.toDouble(), - (shipChunkZUpdated shl 4) + (centerBlock.z and 15).toDouble() - ) - - val scaling = ship.transform.shipToWorldScaling - val offset: Vector3dc = - ship.inertiaData.centerOfMassInShip.sub(centerInShipUpdated, Vector3d()) - - val posInWorld = originalShip.transform.shipToWorld.transformPosition(centerPosCentered.add(offset, Vector3d()), Vector3d()) - val rotInWorld = originalShip.transform.shipToWorldRotation - val velVec = Vector3d(originalShip.velocity) - val omegaVec = Vector3d(originalShip.omega) - - val newShipTransform = ShipTransformImpl(posInWorld, ship.inertiaData.centerOfMassInShip, rotInWorld, scaling) - - ship.transform = newShipTransform - ship.physicsData.linearVelocity = velVec - ship.physicsData.angularVelocity = omegaVec - - val event = VSGameEvents.ShipSplitEvent(originalShip.id, ship.id, blocks) - VSGameEvents.shipSplit.emit(event) - - return ship -} 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 ccadba0f1..6ec62527c 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 @@ -18,12 +18,16 @@ import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.material.FluidState import net.minecraft.world.level.material.Fluids import net.minecraft.world.phys.shapes.VoxelShape -import org.joml.Vector3f -import org.joml.Vector3i +import org.joml.Vector3d +import org.joml.primitives.AABBi +import org.joml.primitives.AABBic +import org.valkyrienskies.core.api.physics.blockstates.BoxesBlockShape +import org.valkyrienskies.core.api.physics.blockstates.CollisionPoint +import org.valkyrienskies.core.api.physics.blockstates.LiquidState +import org.valkyrienskies.core.api.physics.blockstates.SolidBlockShape +import org.valkyrienskies.core.apigame.physics.blockstates.VsBlockState import org.valkyrienskies.core.apigame.world.chunks.BlockType import org.valkyrienskies.core.game.VSBlockType -import org.valkyrienskies.core.impl.collision.Lod1SolidShapeUtils -import org.valkyrienskies.core.impl.game.BlockTypeImpl import org.valkyrienskies.mod.common.BlockStateInfoProvider import org.valkyrienskies.mod.common.ValkyrienSkiesMod import org.valkyrienskies.mod.common.hooks.VSGameEvents @@ -31,18 +35,7 @@ import org.valkyrienskies.mod.common.vsCore import org.valkyrienskies.mod.mixin.accessors.world.level.block.SlabBlockAccessor import org.valkyrienskies.mod.mixin.accessors.world.level.block.StairBlockAccessor import org.valkyrienskies.mod.util.logger -import org.valkyrienskies.physics_api.Lod1BlockStateId -import org.valkyrienskies.physics_api.Lod1LiquidBlockStateId -import org.valkyrienskies.physics_api.Lod1SolidBlockStateId -import org.valkyrienskies.physics_api.voxel.CollisionPoint -import org.valkyrienskies.physics_api.voxel.Lod1LiquidBlockState -import org.valkyrienskies.physics_api.voxel.Lod1SolidBlockState -import org.valkyrienskies.physics_api.voxel.Lod1SolidBoxesCollisionShape -import org.valkyrienskies.physics_api.voxel.Lod1SolidCollisionShape -import org.valkyrienskies.physics_api.voxel.LodBlockBoundingBox import java.util.Optional -import kotlin.math.max -import kotlin.math.min import kotlin.math.roundToInt private data class VSBlockStateInfo( @@ -56,10 +49,9 @@ private data class VSBlockStateInfo( object MassDatapackResolver : BlockStateInfoProvider { private val map = hashMapOf() - private val _solidBlockStates: MutableList = ArrayList() - private val _liquidBlockStates: MutableList = ArrayList() - private val _blockStateData: MutableList> = ArrayList() - private val blockStateToId: MutableMap = HashMap() + private val mcBlockStateToVs: MutableMap = HashMap() + + val blockStateData: Collection = mcBlockStateToVs.values val loader get() = VSMassDataLoader() @@ -74,19 +66,14 @@ object MassDatapackResolver : BlockStateInfoProvider { override fun getBlockStateMass(blockState: BlockState): Double? = map[Registry.BLOCK.getKey(blockState.block)]?.mass - override fun getBlockStateType(blockState: BlockState): VSBlockType? = - blockStateToId[blockState]!! + override fun getBlockStateType(blockState: BlockState): BlockType? { + val vsState = mcBlockStateToVs[blockState] ?: return null + return vsCore.blockTypes.getType(vsState) + } var registeredBlocks = false private set - override val solidBlockStates: List - get() = _solidBlockStates - override val liquidBlockStates: List - get() = _liquidBlockStates - override val blockStateData: List> - get() = _blockStateData - class VSMassDataLoader : SimpleJsonResourceReloadListener(Gson(), "vs_mass") { private val tags = mutableListOf() @@ -180,38 +167,38 @@ object MassDatapackResolver : BlockStateInfoProvider { } - private fun generateStairCollisionShapes(stairShapes: Array): Map { + private fun generateStairCollisionShapes(stairShapes: Array): Map { val testPoints = listOf( - CollisionPoint(Vector3f(.25f, .25f, .25f), .25f), - CollisionPoint(Vector3f(.25f, .25f, .75f), .25f), - CollisionPoint(Vector3f(.25f, .75f, .25f), .25f), - CollisionPoint(Vector3f(.25f, .75f, .75f), .25f), - CollisionPoint(Vector3f(.75f, .25f, .25f), .25f), - CollisionPoint(Vector3f(.75f, .25f, .75f), .25f), - CollisionPoint(Vector3f(.75f, .75f, .25f), .25f), - CollisionPoint(Vector3f(.75f, .75f, .75f), .25f), + CollisionPoint(.25f, .25f, .25f, .25f), + CollisionPoint(.25f, .25f, .75f, .25f), + CollisionPoint(.25f, .75f, .25f, .25f), + CollisionPoint(.25f, .75f, .75f, .25f), + CollisionPoint(.75f, .25f, .25f, .25f), + CollisionPoint(.75f, .25f, .75f, .25f), + CollisionPoint(.75f, .75f, .25f, .25f), + CollisionPoint(.75f, .75f, .75f, .25f), ) val testBoxes = listOf( - LodBlockBoundingBox.createVSBoundingBox(0, 0, 0, 7, 7, 7), - LodBlockBoundingBox.createVSBoundingBox(0, 0, 8, 7, 7, 15), - LodBlockBoundingBox.createVSBoundingBox(0, 8, 0, 7, 15, 7), - LodBlockBoundingBox.createVSBoundingBox(0, 8, 8, 7, 15, 15), - LodBlockBoundingBox.createVSBoundingBox(8, 0, 0, 15, 7, 7), - LodBlockBoundingBox.createVSBoundingBox(8, 0, 8, 15, 7, 15), - LodBlockBoundingBox.createVSBoundingBox(8, 8, 0, 15, 15, 7), - LodBlockBoundingBox.createVSBoundingBox(8, 8, 8, 15, 15, 15), + AABBi(0, 0, 0, 7, 7, 7), + AABBi(0, 0, 8, 7, 7, 15), + AABBi(0, 8, 0, 7, 15, 7), + AABBi(0, 8, 8, 7, 15, 15), + AABBi(8, 0, 0, 15, 7, 7), + AABBi(8, 0, 8, 15, 7, 15), + AABBi(8, 8, 0, 15, 15, 7), + AABBi(8, 8, 8, 15, 15, 15), ) - val map: MutableMap = HashMap() + val map: MutableMap = HashMap() stairShapes.forEach { stairShape -> val points: MutableList = ArrayList() - val positiveBoxes: MutableList = ArrayList() - val negativeBoxes: MutableList = ArrayList() + val positiveBoxes: MutableList = ArrayList() + val negativeBoxes: MutableList = ArrayList() testPoints.forEachIndexed { index, testPoint -> var added = false stairShape.forAllBoxes { minX, minY, minZ, maxX, maxY, maxZ -> - if (testPoint.pos.x() in minX .. maxX && testPoint.pos.y() in minY .. maxY && testPoint.pos.z() in minZ .. maxZ) { + if (testPoint.x in minX .. maxX && testPoint.y in minY .. maxY && testPoint.z in minZ .. maxZ) { points.add(testPoint) added = true return@forAllBoxes @@ -223,52 +210,39 @@ object MassDatapackResolver : BlockStateInfoProvider { negativeBoxes.add(testBoxes[index]) } } - val minTotalAABB = Vector3i(positiveBoxes[0].minX.toInt(), positiveBoxes[0].minY.toInt(), positiveBoxes[0].minZ.toInt()) - val maxTotalAABB = Vector3i(positiveBoxes[0].maxX.toInt(), positiveBoxes[0].maxY.toInt(), positiveBoxes[0].maxZ.toInt()) - for (i in 1 until positiveBoxes.size) { - minTotalAABB.x = min(minTotalAABB.x, positiveBoxes[i].minX.toInt()) - minTotalAABB.y = min(minTotalAABB.y, positiveBoxes[i].minY.toInt()) - minTotalAABB.z = min(minTotalAABB.z, positiveBoxes[i].minZ.toInt()) - maxTotalAABB.x = max(maxTotalAABB.x, positiveBoxes[i].maxX.toInt()) - maxTotalAABB.y = max(maxTotalAABB.y, positiveBoxes[i].maxY.toInt()) - maxTotalAABB.z = max(maxTotalAABB.z, positiveBoxes[i].maxZ.toInt()) - } - val overallBox = LodBlockBoundingBox.createVSBoundingBox( - minTotalAABB.x.toByte(), minTotalAABB.y.toByte(), minTotalAABB.z.toByte(), maxTotalAABB.x.toByte(), - maxTotalAABB.y.toByte(), maxTotalAABB.z.toByte() - ) - val collisionShape = Lod1SolidBoxesCollisionShape( - overallBoundingBox = overallBox, - collisionPoints = points, - solidBoxes = Lod1SolidShapeUtils.mergeBoxes(positiveBoxes), - negativeBoxes = Lod1SolidShapeUtils.mergeBoxes(negativeBoxes), - ) + + val collisionShape = vsCore.newSolidStateBoxesShapeBuilder() + .addCollisionPoints(points) + .addPositiveBoxes(vsCore.solidShapeUtils.mergeBoxes(positiveBoxes)) + .addNegativeBoxes(vsCore.solidShapeUtils.mergeBoxes(negativeBoxes)) + .build() + map[stairShape] = collisionShape } return map } - private fun generateShapeFromVoxel(voxelShape: VoxelShape): Lod1SolidBoxesCollisionShape? { - val posBoxes = ArrayList() + private fun generateShapeFromVoxel(voxelShape: VoxelShape): BoxesBlockShape? { + val posBoxes = ArrayList() var failed = false var maxBoxesToTest = 20 voxelShape.forAllBoxes { minX, minY, minZ, maxX, maxY, maxZ -> if (failed) { return@forAllBoxes } - val lodMinX = (minX * 16).roundToInt().toByte() - val lodMinY = (minY * 16).roundToInt().toByte() - val lodMinZ = (minZ * 16).roundToInt().toByte() - val lodMaxX = ((maxX * 16).roundToInt() - 1).toByte() - val lodMaxY = ((maxY * 16).roundToInt() - 1).toByte() - val lodMaxZ = ((maxZ * 16).roundToInt() - 1).toByte() + val lodMinX = (minX * 16).roundToInt() + val lodMinY = (minY * 16).roundToInt() + val lodMinZ = (minZ * 16).roundToInt() + val lodMaxX = ((maxX * 16).roundToInt() - 1) + val lodMaxY = ((maxY * 16).roundToInt() - 1) + val lodMaxZ = ((maxZ * 16).roundToInt() - 1) if (lodMinX !in 0..15 || lodMinY !in 0..15 || lodMinZ !in 0..15 || lodMaxX !in 0..15 || lodMaxY !in 0..15 || lodMaxZ !in 0..15) { // Out of range failed = true return@forAllBoxes } else { posBoxes.add( - LodBlockBoundingBox.createVSBoundingBox(lodMinX, lodMinY, lodMinZ, lodMaxX, lodMaxY, lodMaxZ) + AABBi(lodMinX, lodMinY, lodMinZ, lodMaxX, lodMaxY, lodMaxZ) ) } if (maxBoxesToTest == 0) { @@ -278,68 +252,33 @@ object MassDatapackResolver : BlockStateInfoProvider { } } return if (!failed) { - Lod1SolidShapeUtils.generateShapeFromBoxes(posBoxes) + try { + vsCore.solidShapeUtils.generateShapeFromBoxes(posBoxes) + } catch (ex: IllegalArgumentException) { + println("WTF ERROR WHILE PROCESSING $voxelShape") + null + } } else { null } } fun registerAllBlockStates(blockStates: Iterable) { - val fullLodBoundingBox = LodBlockBoundingBox.createVSBoundingBox(0, 0, 0, 15, 15, 15) + val fullLodBoundingBox = AABBi(0, 0, 0, 15, 15, 15) val fullBlockCollisionPoints = listOf( - CollisionPoint(Vector3f(.25f, .25f, .25f), .25f), - CollisionPoint(Vector3f(.25f, .25f, .75f), .25f), - CollisionPoint(Vector3f(.25f, .75f, .25f), .25f), - CollisionPoint(Vector3f(.25f, .75f, .75f), .25f), - CollisionPoint(Vector3f(.75f, .25f, .25f), .25f), - CollisionPoint(Vector3f(.75f, .25f, .75f), .25f), - CollisionPoint(Vector3f(.75f, .75f, .25f), .25f), - CollisionPoint(Vector3f(.75f, .75f, .75f), .25f), + CollisionPoint(.25f, .25f, .25f, .25f), + CollisionPoint(.25f, .25f, .75f, .25f), + CollisionPoint(.25f, .75f, .25f, .25f), + CollisionPoint(.25f, .75f, .75f, .25f), + CollisionPoint(.75f, .25f, .25f, .25f), + CollisionPoint(.75f, .25f, .75f, .25f), + CollisionPoint(.75f, .75f, .25f, .25f), + CollisionPoint(.75f, .75f, .75f, .25f), ) - val fullBlockCollisionShape = Lod1SolidBoxesCollisionShape( - overallBoundingBox = fullLodBoundingBox, - collisionPoints = fullBlockCollisionPoints, - solidBoxes = listOf(fullLodBoundingBox), - negativeBoxes = listOf(), - ) - - // Add default block states - run { - // region Add default solid block state - val solidBlockState = Lod1SolidBlockState( - collisionShape = fullBlockCollisionShape, - elasticity = DEFAULT_ELASTICITY.toFloat(), - friction = DEFAULT_FRICTION.toFloat(), - hardness = DEFAULT_HARDNESS.toFloat(), - lod1SolidBlockStateId = BlockTypeImpl.SOLID.toInt(), - ) - _solidBlockStates.add(solidBlockState) - _blockStateData.add(Triple(BlockTypeImpl.SOLID.toInt(), BlockTypeImpl.AIR.toInt(), BlockTypeImpl.SOLID.toInt())) - // endregion - - // region Add default water/lava liquid block states - val waterBlockState = Lod1LiquidBlockState( - boundingBox = fullLodBoundingBox, - density = 1000.0f, - dragCoefficient = 0.3f, - fluidVel = Vector3f(), - lod1LiquidBlockStateId = BlockTypeImpl.WATER.toInt(), - ) - - val lavaBlockState = Lod1LiquidBlockState( - boundingBox = fullLodBoundingBox, - density = 10000.0f, - dragCoefficient = 1.0f, - fluidVel = Vector3f(), - lod1LiquidBlockStateId = BlockTypeImpl.LAVA.toInt(), - ) - - _liquidBlockStates.add(waterBlockState) - _liquidBlockStates.add(lavaBlockState) - _blockStateData.add(Triple(BlockTypeImpl.AIR.toInt(), BlockTypeImpl.WATER.toInt(), BlockTypeImpl.WATER.toInt())) - _blockStateData.add(Triple(BlockTypeImpl.AIR.toInt(), BlockTypeImpl.LAVA.toInt(), BlockTypeImpl.LAVA.toInt())) - // endregion - } + val fullBlockCollisionShape = vsCore.newSolidStateBoxesShapeBuilder() + .addCollisionPoints(fullBlockCollisionPoints) + .addPositiveBox(fullLodBoundingBox) + .build() // A dummy world used to get the VoxelShape for each block state val dummyBlockGetter = object: BlockGetter { @@ -359,55 +298,46 @@ object MassDatapackResolver : BlockStateInfoProvider { StairBlockAccessor.getTopShapes() + StairBlockAccessor.getBottomShapes() + SlabBlockAccessor.getBottomAABB() + SlabBlockAccessor.getTopAABB() ) - // Setup initial conditions for future ids - var nextSolidId = 2 - var nextFluidId = 4 - var nextVoxelStateId = 4 - - val generatedCollisionShapesMap = HashMap() - val liquidMaterialToDensityMap = mapOf(Fluids.WATER to Pair(1000.0f, 0.3f), Fluids.LAVA to Pair(10000.0f, 1.0f), Fluids.FLOWING_WATER to Pair(1000.0f, 0.3f), Fluids.FLOWING_LAVA to Pair(10000.0f, 1.0f)) + val generatedCollisionShapesMap = HashMap() + val liquidMaterialToDensityMap = mapOf(Fluids.WATER to Pair(1000.0, 0.3), Fluids.LAVA to Pair(10000.0, 1.0), Fluids.FLOWING_WATER to Pair(1000.0, 0.3), Fluids.FLOWING_LAVA to Pair(10000.0, 1.0)) - val fluidStateToBlockTypeMap = HashMap>() + val fluidStateToBlockTypeMap = HashMap() // Get the id of the fluid state/create a new fluid state if necessary - fun getFluidState(fluidState: FluidState): Pair { + // Get the id of the fluid state/create a new fluid state if necessary + fun getFluidState(fluidState: FluidState): LiquidState { val cached = fluidStateToBlockTypeMap[fluidState] if (cached != null) return cached - val maxY = ((fluidState.ownHeight * 16.0).roundToInt() - 1).coerceIn(0, 15).toByte() - val fluidBox = LodBlockBoundingBox.createVSBoundingBox(0, 0, 0, 15, maxY, 15) - if (fluidState.type in liquidMaterialToDensityMap) { + val maxY = ((fluidState.ownHeight * 16.0).roundToInt() - 1).coerceIn(0, 15) + val fluidBox = AABBi(0, 0, 0, 15, maxY, 15) + return if (fluidState.type in liquidMaterialToDensityMap) { val (density, dragCoefficient) = liquidMaterialToDensityMap[fluidState.type]!! - val newFluidBlockState = Lod1LiquidBlockState( - boundingBox = fluidBox, - density = density, - dragCoefficient = dragCoefficient, - fluidVel = Vector3f(), - lod1LiquidBlockStateId = nextFluidId++, - ) - val stateId = nextVoxelStateId++ - _liquidBlockStates.add(newFluidBlockState) - _blockStateData.add(Triple(BlockTypeImpl.AIR.toInt(), newFluidBlockState.lod1LiquidBlockStateId, stateId)) - val blockTypeNew = BlockTypeImpl(stateId) - fluidStateToBlockTypeMap[fluidState] = newFluidBlockState.lod1LiquidBlockStateId to blockTypeNew - return newFluidBlockState.lod1LiquidBlockStateId to blockTypeNew + val newFluidBlockState = vsCore.newLiquidStateBuilder() + .boxShape(fluidBox) + .density(density) + .dragCoefficient(dragCoefficient) + .velocity(Vector3d()) + .build() + + newFluidBlockState } else { // Default - return BlockTypeImpl.WATER.toInt() to BlockTypeImpl.WATER + vsCore.blockTypes.waterState.liquidState!! } } blockStates.forEach { blockState: BlockState -> - val blockType: BlockType + val vsBlockState: VsBlockState if (blockState.isAir) { - blockType = vsCore.blockTypes.air + vsBlockState = vsCore.blockTypes.airState } else { val blockMaterial = blockState.material - blockType = if (blockMaterial.isLiquid) { - getFluidState(blockState.fluidState).second + vsBlockState = if (blockMaterial.isLiquid) { + VsBlockState(null, getFluidState(blockState.fluidState)) } else if (blockMaterial.isSolid) { val voxelShape = blockState.getShape(dummyBlockGetter, BlockPos.ZERO) - val collisionShape: Lod1SolidCollisionShape = if (voxelShapeToCollisionShapeMap.contains(voxelShape)) { + val collisionShape: SolidBlockShape = if (voxelShapeToCollisionShapeMap.contains(voxelShape)) { voxelShapeToCollisionShapeMap[voxelShape]!! } else if (generatedCollisionShapesMap.contains(voxelShape)) { if (generatedCollisionShapesMap[voxelShape] != null) { @@ -424,31 +354,25 @@ object MassDatapackResolver : BlockStateInfoProvider { val vsBlockStateInfo = map[Registry.BLOCK.getKey(blockState.block)] // Create new solid block state - val solidStateId = nextSolidId++ - val newSolidBlockState = Lod1SolidBlockState( - collisionShape = collisionShape, - elasticity = vsBlockStateInfo?.elasticity?.toFloat() ?: DEFAULT_ELASTICITY.toFloat(), - friction = vsBlockStateInfo?.friction?.toFloat() ?: DEFAULT_FRICTION.toFloat(), - hardness = DEFAULT_HARDNESS.toFloat(), - lod1SolidBlockStateId = solidStateId, - ) - _solidBlockStates.add(newSolidBlockState) - - // Create new voxel state - val blockStateId = nextVoxelStateId++ - - var fluidId = BlockTypeImpl.AIR.toInt() - if (!blockState.fluidState.isEmpty) { - fluidId = getFluidState(blockState.fluidState).first + val solidState = vsCore.newSolidStateBuilder() + .shape(collisionShape) + .elasticity(vsBlockStateInfo?.elasticity ?: DEFAULT_ELASTICITY) + .friction(vsBlockStateInfo?.friction ?: DEFAULT_FRICTION) + .hardness(DEFAULT_HARDNESS) + .build() + + val fluidState = if (!blockState.fluidState.isEmpty) { + getFluidState(blockState.fluidState) + } else { + null } - _blockStateData.add(Triple(solidStateId, fluidId, blockStateId)) - BlockTypeImpl(blockStateId) + VsBlockState(solidState, fluidState) } else { - vsCore.blockTypes.air + vsCore.blockTypes.airState } } - blockStateToId[blockState] = blockType + mcBlockStateToVs[blockState] = vsBlockState } registeredBlocks = true 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 fb62268ca..34da4e64b 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 @@ -12,13 +12,13 @@ import net.minecraft.world.phys.Vec3 import org.joml.Vector3f import org.valkyrienskies.core.api.ships.LoadedServerShip import org.valkyrienskies.core.api.ships.setAttachment -import org.valkyrienskies.core.impl.networking.simple.sendToServer import org.valkyrienskies.mod.api.SeatedControllingPlayer import org.valkyrienskies.mod.common.config.VSKeyBindings import org.valkyrienskies.mod.common.getShipManagingPos import org.valkyrienskies.mod.common.getShipObjectManagingPos import org.valkyrienskies.mod.common.isBlockInShipyard import org.valkyrienskies.mod.common.networking.PacketPlayerDriving +import org.valkyrienskies.mod.common.vsCore open class ShipMountingEntity(type: EntityType, level: Level) : Entity(type, level) { // Decides if this entity controls the ship it is in. @@ -96,7 +96,9 @@ open class ShipMountingEntity(type: EntityType, level: Level impulse.x = if (left == right) 0.0f else if (left) 1.0f else -1.0f impulse.y = if (up == down) 0.0f else if (up) 1.0f else -1.0f - PacketPlayerDriving(impulse, sprint, cruise).sendToServer() + with(vsCore.simplePacketNetworking) { + PacketPlayerDriving(impulse, sprint, cruise).sendToServer() + } } override fun getControllingPassenger(): Entity? { diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/VSPhysicsEntity.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/VSPhysicsEntity.kt index b636d67ff..9adbc52d4 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/VSPhysicsEntity.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/VSPhysicsEntity.kt @@ -26,7 +26,6 @@ import org.valkyrienskies.core.apigame.world.ServerShipWorldCore import org.valkyrienskies.core.impl.game.ShipTeleportDataImpl import org.valkyrienskies.core.impl.game.ships.ShipInertiaDataImpl import org.valkyrienskies.core.impl.game.ships.ShipObjectClientWorld -import org.valkyrienskies.core.impl.game.ships.ShipObjectServerWorld import org.valkyrienskies.core.impl.game.ships.ShipTransformImpl import org.valkyrienskies.core.impl.util.serialization.VSJacksonUtil import org.valkyrienskies.mod.common.dimensionId @@ -141,7 +140,7 @@ open class VSPhysicsEntity(type: EntityType, level: Level) : En } val physicsEntityDataAsBytes: ByteArray = compoundTag.getByteArray(PHYS_DATA_NBT_KEY) val oldPhysicsEntityData = getMapper().readValue(physicsEntityDataAsBytes) - val newShipId = (level.shipObjectWorld as ShipObjectServerWorld).allocateShipId(level.dimensionId) + val newShipId = (level.shipObjectWorld as ServerShipWorldCore).allocateShipId(level.dimensionId) val newPhysicsEntityData = oldPhysicsEntityData.copyPhysicsEntityDataWithNewId(newShipId) // Change the shipId to be something new setPhysicsEntityData(newPhysicsEntityData) @@ -198,7 +197,7 @@ open class VSPhysicsEntity(type: EntityType, level: Level) : En if (physicsEntityServerCopy != null) { val newPos = Vector3d(d, e, f) val teleportData = ShipTeleportDataImpl(newPos = newPos) - (this.level.shipObjectWorld as ShipObjectServerWorld).teleportPhysicsEntity(this.physicsEntityServer!!, teleportData) + (this.level.shipObjectWorld as ServerShipWorldCore).teleportPhysicsEntity(this.physicsEntityServer!!, teleportData) } else { physicsEntityData!!.transform = ShipTransformImpl.create( Vector3d(d, e, f), diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/handling/VSEntityManager.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/handling/VSEntityManager.kt index 8a45a3a62..f7ac714cc 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/handling/VSEntityManager.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/entity/handling/VSEntityManager.kt @@ -5,10 +5,10 @@ import net.minecraft.core.Registry import net.minecraft.resources.ResourceLocation import net.minecraft.world.entity.Entity import net.minecraft.world.entity.EntityType -import org.valkyrienskies.core.impl.networking.simple.sendToClient import org.valkyrienskies.mod.common.ValkyrienSkiesMod import org.valkyrienskies.mod.common.networking.PacketSyncVSEntityTypes import org.valkyrienskies.mod.common.util.MinecraftPlayer +import org.valkyrienskies.mod.common.vsCore import org.valkyrienskies.mod.compat.CreateCompat import java.time.Duration import kotlin.text.RegexOption.IGNORE_CASE @@ -98,7 +98,8 @@ object VSEntityManager { i to namedEntityHandlers[handler].toString() } .toMap() - - PacketSyncVSEntityTypes(entityTypes).sendToClient(player) + with (vsCore.simplePacketNetworking) { + PacketSyncVSEntityTypes(entityTypes).sendToClient(player) + } } } diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/hooks/VSGameEvents.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/hooks/VSGameEvents.kt index ae181f6dd..6a5608cc3 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/hooks/VSGameEvents.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/hooks/VSGameEvents.kt @@ -8,7 +8,7 @@ import net.minecraft.client.renderer.LevelRenderer.RenderChunkInfo import net.minecraft.client.renderer.RenderType import org.valkyrienskies.core.api.ships.ClientShip import org.valkyrienskies.core.api.ships.properties.ShipId -import org.valkyrienskies.core.impl.util.events.EventEmitterImpl +import org.valkyrienskies.core.util.events.EventEmitterImpl import org.valkyrienskies.core.util.datastructures.DenseBlockPosSet object VSGameEvents { 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 7c1efeb1b..4be65f6eb 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 @@ -6,25 +6,23 @@ import net.minecraft.server.level.ServerPlayer import org.valkyrienskies.core.api.ships.LoadedServerShip import org.valkyrienskies.core.api.ships.getAttachment import org.valkyrienskies.core.api.ships.setAttachment -import org.valkyrienskies.core.impl.networking.simple.register -import org.valkyrienskies.core.impl.networking.simple.registerClientHandler -import org.valkyrienskies.core.impl.networking.simple.registerServerHandler import org.valkyrienskies.mod.api.SeatedControllingPlayer import org.valkyrienskies.mod.common.entity.ShipMountingEntity import org.valkyrienskies.mod.common.entity.handling.VSEntityManager import org.valkyrienskies.mod.common.getShipObjectManagingPos import org.valkyrienskies.mod.common.util.MinecraftPlayer +import org.valkyrienskies.mod.common.vsCore object VSGamePackets { - fun register() { + fun register() = with(vsCore.simplePacketNetworking) { PacketPlayerDriving::class.register() PacketStopChunkUpdates::class.register() PacketRestartChunkUpdates::class.register() PacketSyncVSEntityTypes::class.register() } - fun registerHandlers() { + fun registerHandlers() = with(vsCore.simplePacketNetworking) { PacketPlayerDriving::class.registerServerHandler { driving, iPlayer -> val player = (iPlayer as MinecraftPlayer).player as ServerPlayer val seat = player.vehicle as? ShipMountingEntity diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityShipCollisionUtils.kt b/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityShipCollisionUtils.kt index 89b3128f8..4b4109ae1 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityShipCollisionUtils.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/common/util/EntityShipCollisionUtils.kt @@ -13,7 +13,6 @@ import org.joml.primitives.AABBd import org.joml.primitives.AABBdc import org.valkyrienskies.core.api.ships.Ship import org.valkyrienskies.core.apigame.collision.ConvexPolygonc -import org.valkyrienskies.core.impl.collision.k.createPolygonFromAABB import org.valkyrienskies.core.util.extend import org.valkyrienskies.mod.common.getShipsIntersecting import org.valkyrienskies.mod.common.shipObjectWorld @@ -125,7 +124,7 @@ object EntityShipCollisionUtils { world.getBlockCollisions(entity, entityBoundingBoxInShipCoordinates.toMinecraft()) shipBlockCollisionStream.forEach { voxelShape: VoxelShape -> voxelShape.forAllBoxes { minX, minY, minZ, maxX, maxY, maxZ -> - val shipPolygon: ConvexPolygonc = createPolygonFromAABB( + val shipPolygon: ConvexPolygonc = vsCore.entityPolygonCollider.createPolygonFromAABB( AABBd(minX, minY, minZ, maxX, maxY, maxZ), shipTransform.shipToWorld, shipObject.id diff --git a/common/src/main/kotlin/org/valkyrienskies/mod/compat/clothconfig/VSClothConfig.kt b/common/src/main/kotlin/org/valkyrienskies/mod/compat/clothconfig/VSClothConfig.kt index e5fed4518..9bbe733a6 100644 --- a/common/src/main/kotlin/org/valkyrienskies/mod/compat/clothconfig/VSClothConfig.kt +++ b/common/src/main/kotlin/org/valkyrienskies/mod/compat/clothconfig/VSClothConfig.kt @@ -17,14 +17,16 @@ import net.minecraft.network.chat.Component import net.minecraft.network.chat.TextComponent import org.apache.commons.lang3.StringUtils import org.valkyrienskies.core.impl.config.SidedVSConfigClass -import org.valkyrienskies.core.impl.config.VSConfigClass import org.valkyrienskies.core.impl.util.serialization.VSJacksonUtil +import org.valkyrienskies.mod.common.vsCore import java.util.Optional object VSClothConfig { @JvmStatic - fun createConfigScreenFor(parent: Screen, vararg configClasses: VSConfigClass): Screen { + fun createConfigScreenFor(parent: Screen, vararg configClassesJ: Class<*>): Screen { + val configClasses = configClassesJ.map(vsCore::getRegisteredConfigLegacy) + return ConfigBuilder.create().apply { parentScreen = parent @@ -109,7 +111,7 @@ object VSClothConfig { val enum: ArrayNode? = schema["enum"] as? ArrayNode val type = schema["type"].asText() - val tooltip: TextComponent? = null + val tooltip: Component? = null when { type == "integer" -> { @@ -241,7 +243,7 @@ object VSClothConfig { val newValue = try { mapper.readTree(str) } catch (ex: JsonProcessingException) { - return@setErrorSupplier Optional.of(TextComponent(ex.message)) + return@setErrorSupplier Optional.of(TextComponent(ex.message ?: "")) } getValidationMessageComponent(newValue) diff --git a/fabric/build.gradle b/fabric/build.gradle index 06289659f..1a08cab74 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -58,8 +58,16 @@ dependencies { exclude module: "fastutil" exclude module: "kotlin-stdlib-jdk8" // Don't shade kotlin-stdlib-jdk8, even though vs-core depends on it exclude module: "jsonschema.module.addon" + + exclude group: "com.google.guava" } + def jacksonVersion = '2.14.0' + + + include("com.fasterxml:classmate:1.5.1") + implementation("com.fasterxml:classmate:1.5.1") + // CC Restitched modImplementation("curse.maven:cc-restitched-462672:3838648") diff --git a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/create/client/MixinTrackBlockOutline.java b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/create/client/MixinTrackBlockOutline.java index b5700a44b..535f54ba1 100644 --- a/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/create/client/MixinTrackBlockOutline.java +++ b/fabric/src/main/java/org/valkyrienskies/mod/fabric/mixin/compat/create/client/MixinTrackBlockOutline.java @@ -24,8 +24,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.valkyrienskies.core.api.ships.ClientShip; import org.valkyrienskies.core.api.ships.Ship; -import org.valkyrienskies.core.impl.game.ships.ShipObjectClient; import org.valkyrienskies.mod.common.VSClientGameUtils; import org.valkyrienskies.mod.common.VSGameUtilsKt; import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; @@ -58,8 +58,8 @@ private static PoseStack redirectTransformStackTranslate(final PoseStack ms) { final Level level = Minecraft.getInstance().level; if (level != null && valkyrienskies$vec != null) { - final ShipObjectClient ship; - if ((ship = (ShipObjectClient) VSGameUtilsKt.getShipManagingPos(level, valkyrienskies$vec)) != null) { + final ClientShip ship; + if ((ship = (ClientShip) VSGameUtilsKt.getShipManagingPos(level, valkyrienskies$vec)) != null) { final Quaterniond rotation = new Quaterniond().identity(); final Quaterniond yawQuat = new Quaterniond().rotateY(valkyrienskies$angles.y); final Quaterniond pitchQuat = new Quaterniond().rotateX(valkyrienskies$angles.x); @@ -117,8 +117,8 @@ private static void harvest(final LevelRenderer context, final Camera info, fina private static void redirectTranslate(final PoseStack instance, final double d, final double e, final double f) { final Level level = Minecraft.getInstance().level; if (level != null) { - final ShipObjectClient ship; - if ((ship = (ShipObjectClient) VSGameUtilsKt.getShipManagingPos(level, + final ClientShip ship; + if ((ship = (ClientShip) VSGameUtilsKt.getShipManagingPos(level, valkyrienskies$hitResult.getBlockPos())) != null) { final Vec3 camPos = valkyrienskies$info.getPosition(); VSClientGameUtils.transformRenderWithShip(ship.getRenderTransform(), instance, diff --git a/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/compat/modmenu/ValkyrienModMenu.kt b/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/compat/modmenu/ValkyrienModMenu.kt index bdd81fbdf..9c31462e1 100644 --- a/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/compat/modmenu/ValkyrienModMenu.kt +++ b/fabric/src/main/kotlin/org/valkyrienskies/mod/fabric/compat/modmenu/ValkyrienModMenu.kt @@ -2,8 +2,7 @@ package org.valkyrienskies.mod.fabric.compat.modmenu import com.terraformersmc.modmenu.api.ConfigScreenFactory import com.terraformersmc.modmenu.api.ModMenuApi -import org.valkyrienskies.core.impl.config.VSConfigClass.Companion.getRegisteredConfig -import org.valkyrienskies.core.impl.config.VSCoreConfig +import org.valkyrienskies.core.impl.config_impl.VSCoreConfig import org.valkyrienskies.mod.common.config.VSGameConfig import org.valkyrienskies.mod.compat.clothconfig.VSClothConfig @@ -12,8 +11,8 @@ class ValkyrienModMenu : ModMenuApi { return ConfigScreenFactory { parent -> VSClothConfig.createConfigScreenFor( parent, - getRegisteredConfig(VSCoreConfig::class.java), - getRegisteredConfig(VSGameConfig::class.java) + VSCoreConfig::class.java, + VSGameConfig::class.java ) } } diff --git a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/create/client/MixinTrackBlockOutline.java b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/create/client/MixinTrackBlockOutline.java index ee8ccdd53..599b00336 100644 --- a/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/create/client/MixinTrackBlockOutline.java +++ b/forge/src/main/java/org/valkyrienskies/mod/forge/mixin/compat/create/client/MixinTrackBlockOutline.java @@ -6,7 +6,6 @@ import com.simibubi.create.content.trains.track.TrackBlockOutline.BezierPointSelection; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.core.BlockPos; import net.minecraft.world.level.Level; @@ -23,8 +22,8 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.valkyrienskies.core.api.ships.ClientShip; import org.valkyrienskies.core.api.ships.Ship; -import org.valkyrienskies.core.impl.game.ships.ShipObjectClient; import org.valkyrienskies.mod.common.VSClientGameUtils; import org.valkyrienskies.mod.common.VSGameUtilsKt; import org.valkyrienskies.mod.common.util.VectorConversionsMCKt; @@ -54,8 +53,8 @@ private static PoseStack redirectTransformStackTranslate(final PoseStack ms) { final Level level = Minecraft.getInstance().level; if (level != null && valkyrienskies$vec != null) { - final ShipObjectClient ship; - if ((ship = (ShipObjectClient) VSGameUtilsKt.getShipManagingPos(level, valkyrienskies$vec)) != null) { + final ClientShip ship; + if ((ship = (ClientShip) VSGameUtilsKt.getShipManagingPos(level, valkyrienskies$vec)) != null) { final Quaterniond rotation = new Quaterniond().identity(); final Quaterniond yawQuat = new Quaterniond().rotateY(valkyrienskies$angles.y); final Quaterniond pitchQuat = new Quaterniond().rotateX(valkyrienskies$angles.x); @@ -110,8 +109,8 @@ private static void harvest(DrawSelectionEvent.HighlightBlock event, CallbackInf private static void redirectTranslate(final PoseStack instance, final double d, final double e, final double f) { final Level level = Minecraft.getInstance().level; if (level != null) { - final ShipObjectClient ship; - if ((ship = (ShipObjectClient) VSGameUtilsKt.getShipManagingPos(level, + final ClientShip ship; + if ((ship = (ClientShip) VSGameUtilsKt.getShipManagingPos(level, valkyrienskies$hitResult.getBlockPos())) != null) { final Vec3 camPos = valkyrienskies$info.getPosition(); VSClientGameUtils.transformRenderWithShip(ship.getRenderTransform(), instance, diff --git a/forge/src/main/kotlin/org/valkyrienskies/mod/forge/common/ValkyrienSkiesModForge.kt b/forge/src/main/kotlin/org/valkyrienskies/mod/forge/common/ValkyrienSkiesModForge.kt index 9591baa35..b72fa2397 100644 --- a/forge/src/main/kotlin/org/valkyrienskies/mod/forge/common/ValkyrienSkiesModForge.kt +++ b/forge/src/main/kotlin/org/valkyrienskies/mod/forge/common/ValkyrienSkiesModForge.kt @@ -27,8 +27,7 @@ import net.minecraftforge.registries.DeferredRegister import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.registries.RegistryObject import org.valkyrienskies.core.apigame.VSCoreFactory -import org.valkyrienskies.core.impl.config.VSConfigClass -import org.valkyrienskies.core.impl.config.VSCoreConfig +import org.valkyrienskies.core.impl.config_impl.VSCoreConfig import org.valkyrienskies.mod.client.EmptyRenderer import org.valkyrienskies.mod.client.VSPhysicsEntityRenderer import org.valkyrienskies.mod.common.ValkyrienSkiesMod @@ -103,8 +102,8 @@ class ValkyrienSkiesModForge { ConfigGuiFactory { _, parent -> VSClothConfig.createConfigScreenFor( parent, - VSConfigClass.getRegisteredConfig(VSCoreConfig::class.java), - VSConfigClass.getRegisteredConfig(VSGameConfig::class.java) + VSCoreConfig::class.java, + VSGameConfig::class.java ) } } diff --git a/gradle.properties b/gradle.properties index d62d57b88..c51b57cb5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ forge_version=1.18.2-40.2.4 create_fabric_version=0.5.1-f-build.1333+mc1.18.2 flywheel_version_fabric=0.6.9-38 createbigcannons_version= 0.5.2-nightly-e815ca4 -vs_core_version=1.1.0+e26d9059c0 +vs_core_version=1.1.0+da86725858 # 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