Skip to content

Commit

Permalink
Added area assembler, fixed splitting
Browse files Browse the repository at this point in the history
  • Loading branch information
ThePlasticPotato committed Oct 25, 2024
1 parent 68764a2 commit 7c6b8b6
Show file tree
Hide file tree
Showing 13 changed files with 355 additions and 187 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package org.valkyrienskies.mod.common
import com.mojang.serialization.Lifecycle
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.MappedRegistry
import net.minecraft.core.Registry
import net.minecraft.core.Vec3i
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
Expand All @@ -15,15 +13,10 @@ import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import org.valkyrienskies.core.api.ships.Wing
import org.valkyrienskies.core.api.ships.WingManager
import org.valkyrienskies.core.api.world.connectivity.ConnectionStatus.CONNECTED
import org.valkyrienskies.core.api.world.connectivity.ConnectionStatus.DISCONNECTED
import org.valkyrienskies.core.apigame.world.chunks.BlockType
import org.valkyrienskies.core.util.expand
import org.valkyrienskies.mod.common.assembly.ShipAssembler
import org.valkyrienskies.mod.common.block.WingBlock
import org.valkyrienskies.mod.common.config.MassDatapackResolver
import org.valkyrienskies.mod.common.hooks.VSGameEvents
import org.valkyrienskies.mod.common.util.toJOML
import java.util.function.IntFunction

// Other mods can then provide weights and types based on their added content
Expand Down Expand Up @@ -142,172 +135,9 @@ object BlockStateInfo {
newBlockMass
)

if (level is ServerLevel) {
val loadedShip = level.getShipObjectManagingPos(x shr 4, z shr 4)
if (loadedShip != null) {
if (!prevBlockState.isAir && newBlockState.isAir){
val blockNeighbors: HashSet<BlockPos> = HashSet()
for (dir in Direction.entries) {
val shipBox = loadedShip.shipAABB?.expand(1) ?: continue
val neighborPos = BlockPos(x, y, z).relative(dir)
val neighborState = level.getBlockState(neighborPos)
if (!neighborState.isAir && neighborPos != BlockPos(x, y, z) && shipBox.containsPoint(neighborPos.toJOML())) {
blockNeighbors.add(neighborPos)
}
if (true) { //later: check block edge connectivity config
for (secondDir in Direction.entries) {
if (dir.axis != secondDir.axis) {
val secondNeighborPos = neighborPos.relative(secondDir)
val secondNeighborState = level.getBlockState(secondNeighborPos)
if (!secondNeighborState.isAir && secondNeighborPos != BlockPos(x, y, z) && shipBox.containsPoint(neighborPos.toJOML())) {
blockNeighbors.add(secondNeighborPos)
}
if (true) { //later: check block corner connectivity config
for (thirdDir in Direction.entries) {
if (dir.axis != secondDir.axis && dir.axis != thirdDir.axis && secondDir.axis != thirdDir.axis) {
val thirdNeighborPos = secondNeighborPos.relative(thirdDir)
val thirdNeighborState = level.getBlockState(thirdNeighborPos)
if (!thirdNeighborState.isAir && thirdNeighborPos != BlockPos(x, y, z) && shipBox.containsPoint(neighborPos.toJOML())) {
blockNeighbors.add(thirdNeighborPos)
}
}
}
}
}
}
}
}

if (blockNeighbors.isNotEmpty()) {
//find largest remaining component
var largestComponentNode: BlockPos = blockNeighbors.first()
var largestComponentSize: Long = -1

for (neighborPos in blockNeighbors) {
print(level.shipObjectWorld.isIsolatedSolid(neighborPos.x, neighborPos.y, neighborPos.z, level.dimensionId))
if (level.shipObjectWorld.isIsolatedSolid(neighborPos.x, neighborPos.y, neighborPos.z, level.dimensionId) == DISCONNECTED) {
val size = level.shipObjectWorld.getSolidComponentSize(neighborPos.x, neighborPos.y, neighborPos.z, level.dimensionId)
if (size > largestComponentSize) {
largestComponentNode = neighborPos
largestComponentSize = size
}
}
}

if (largestComponentSize == -1L) {
return
}

blockNeighbors.remove(largestComponentNode)

// use largest as base

//find all disconnected components

val disconnected = HashSet<BlockPos>()
for (neighborPos in blockNeighbors) {
if (level.shipObjectWorld.isIsolatedSolid(neighborPos.x, neighborPos.y, neighborPos.z, level.dimensionId) == DISCONNECTED) {
if (neighborPos != largestComponentNode) {
if (level.shipObjectWorld.isConnectedBySolid(largestComponentNode.x, largestComponentNode.y, largestComponentNode.z, neighborPos.x, neighborPos.y, neighborPos.z, level.dimensionId) == DISCONNECTED) {
val component = HashSet<BlockPos>()
disconnected.add(neighborPos)
}
println("this is " + level.shipObjectWorld.isConnectedBySolid(largestComponentNode.x, largestComponentNode.y, largestComponentNode.z, neighborPos.x, neighborPos.y, neighborPos.z, level.dimensionId).toString())
}
}
}

//check if any disconnected components are connected
val toIgnore: HashSet<BlockPos> = HashSet()
for (component in disconnected) {
for (otherComponent in disconnected) {
if (component == otherComponent) {
continue
}
if (level.shipObjectWorld.isConnectedBySolid(component.x, component.y, component.z, otherComponent.x, otherComponent.y, otherComponent.z, level.dimensionId) == CONNECTED) {
if (!toIgnore.contains(otherComponent) && !toIgnore.contains(component)) {
toIgnore.add(component)
}
}
}
}

disconnected.removeAll(toIgnore)

if (disconnected.isEmpty()) {
return
}

//begin the DFSing

val offsetsToCheck: ArrayList<Vec3i> = arrayListOf(
Vec3i(1, 0, 0),
Vec3i(-1, 0, 0),
Vec3i(0, 1, 0),
Vec3i(0, -1, 0),
Vec3i(0, 0, 1),
Vec3i(0, 0, -1)
)
if (true) { //later: check block edge connectivity config
offsetsToCheck.add(Vec3i(1, 1, 0))
offsetsToCheck.add(Vec3i(1, -1, 0))
offsetsToCheck.add(Vec3i(-1, 1, 0))
offsetsToCheck.add(Vec3i(-1, -1, 0))
offsetsToCheck.add(Vec3i(1, 0, 1))
offsetsToCheck.add(Vec3i(1, 0, -1))
offsetsToCheck.add(Vec3i(-1, 0, 1))
offsetsToCheck.add(Vec3i(-1, 0, -1))
offsetsToCheck.add(Vec3i(0, 1, 1))
offsetsToCheck.add(Vec3i(0, 1, -1))
offsetsToCheck.add(Vec3i(0, -1, 1))
offsetsToCheck.add(Vec3i(0, -1, -1))
}
if (true) { //later: check block corner connectivity config
offsetsToCheck.add(Vec3i(1, 1, 1))
offsetsToCheck.add(Vec3i(1, 1, -1))
offsetsToCheck.add(Vec3i(1, -1, 1))
offsetsToCheck.add(Vec3i(1, -1, -1))
offsetsToCheck.add(Vec3i(-1, 1, 1))
offsetsToCheck.add(Vec3i(-1, 1, -1))
offsetsToCheck.add(Vec3i(-1, -1, 1))
offsetsToCheck.add(Vec3i(-1, -1, -1))
}

val toAssemble = HashSet<List<BlockPos>>()

for (starter in disconnected) {
val visited = HashSet<BlockPos>()
val queuedPositions = HashSet<BlockPos>()
queuedPositions.add(starter)

while (queuedPositions.isNotEmpty()) {
val current = queuedPositions.first()
queuedPositions.remove(current)
visited.add(current)
val toCheck = HashSet<BlockPos>()
for (offset in offsetsToCheck) {
toCheck.add(BlockPos(current.x + offset.x, current.y + offset.y, current.z + offset.z))
}
for (check in toCheck) {
if (!visited.contains(check) && !level.getBlockState(check).isAir) {
queuedPositions.add(check)
}
}
}
//if we have visited all blocks in the component, we can split it
toAssemble.add(visited.toList())
}

if (toAssemble.isEmpty()) {
return
}

for (component in toAssemble) {
ShipAssembler.assembleToShip(level, component, true, 1.0)
}
}
}
}
// todo check if splitting is enabled, dolt
if (true) {
ValkyrienSkiesMod.splitHandler.split(level, x, y, z, prevBlockState, newBlockState)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import org.valkyrienskies.mod.common.entity.ShipMountingEntity
import org.valkyrienskies.mod.common.entity.VSPhysicsEntity
import org.valkyrienskies.mod.common.networking.VSGamePackets
import org.valkyrienskies.mod.common.util.GameTickForceApplier
import org.valkyrienskies.mod.common.util.SplitHandler
import org.valkyrienskies.mod.common.util.SplittingDisablerAttachment

object ValkyrienSkiesMod {
const val MOD_ID = "valkyrienskies"
Expand All @@ -28,6 +30,7 @@ object ValkyrienSkiesMod {
lateinit var SHIP_CREATOR_ITEM: Item
lateinit var SHIP_ASSEMBLER_ITEM: Item
lateinit var SHIP_CREATOR_ITEM_SMALLER: Item
lateinit var AREA_ASSEMBLER_ITEM: Item
lateinit var PHYSICS_ENTITY_CREATOR_ITEM: Item
lateinit var SHIP_MOUNTING_ENTITY_TYPE: EntityType<ShipMountingEntity>
lateinit var PHYSICS_ENTITY_TYPE: EntityType<VSPhysicsEntity>
Expand All @@ -42,6 +45,9 @@ object ValkyrienSkiesMod {
@JvmStatic
val vsCoreClient get() = vsCore as VSCoreClient

@JvmStatic
lateinit var splitHandler: SplitHandler

fun init(core: VSCore) {
this.vsCore = core

Expand All @@ -50,8 +56,12 @@ object ValkyrienSkiesMod {
VSGamePackets.registerHandlers()

core.registerConfigLegacy("vs", VSGameConfig::class.java)

splitHandler = SplitHandler(this.vsCore.hooks.enableBlockEdgeConnectivity, this.vsCore.hooks.enableBlockCornerConnectivity)

VSEvents.ShipLoadEvent.on { event ->
event.ship.setAttachment(GameTickForceApplier())
event.ship.setAttachment(SplittingDisablerAttachment(true))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ object AssemblyUtil {

fun removeBlock(level: Level, pos: BlockPos) {
level.removeBlockEntity(pos)
setBlock(level, pos, Blocks.AIR.defaultBlockState())
level.getChunk(pos).setBlockState(pos, Blocks.AIR.defaultBlockState(), false)
}

fun copyBlock(level: Level, from: BlockPos, to: BlockPos) {
val state = level.getBlockState(from)
val blockentity = level.getBlockEntity(from)
setBlock(level, to, state)
level.getChunk(to).setBlockState(to, state, false)

// Transfer pending schedule-ticks
if (level.blockTicks.hasScheduledTick(from, state.block)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@ 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.Vector3dc
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.api.ships.getAttachment
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
import org.valkyrienskies.mod.common.util.SplittingDisablerAttachment
import org.valkyrienskies.mod.common.util.toJOMLD
import org.valkyrienskies.mod.util.logger

object ShipAssembler {

Expand All @@ -31,11 +36,11 @@ object ShipAssembler {
}


fun assembleToShip(level: Level, blocks: List<BlockPos>, removeOriginal: Boolean, scale: Double): ServerShip {
assert(level is ServerLevel) { "Can't manage contraptions on client side!" }
fun assembleToShip(level: Level, blocks: List<BlockPos>, removeOriginal: Boolean, scale: Double = 1.0, shouldDisableSplitting: Boolean = false): ServerShip {
assert(level is ServerLevel) { "Can't create ships clientside!" }
val sLevel: ServerLevel = level as ServerLevel
if (blocks.isEmpty()) {
throw IllegalArgumentException()
throw IllegalArgumentException("No blocks to assemble.")
}

val existingShip = sLevel.getShipObjectManagingPos(blocks.find { !sLevel.getBlockState(it).isAir } ?: throw IllegalArgumentException())
Expand Down Expand Up @@ -66,7 +71,10 @@ object ShipAssembler {
val newShip: Ship = (level as ServerLevel).server.shipObjectWorld
.createNewShipAtBlock(contraptionWorldPos, false, scale, level.dimensionId)

// Stone for safety reasons
if (shouldDisableSplitting) {
level.shipObjectWorld.loadedShips.getById(newShip.id)?.getAttachment<SplittingDisablerAttachment>()?.disableSplitting()

}

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())
Expand All @@ -84,9 +92,9 @@ object ShipAssembler {
}

// If center block got not replaced, remove the stone block
if (!centerBlockReplaced) {
level.setBlock(contraptionBlockPos, Blocks.AIR.defaultBlockState(), 3)
}
// if (!centerBlockReplaced) {
// level.setBlock(contraptionBlockPos, Blocks.AIR.defaultBlockState(), 3)
// }

// Remove original blocks
if (removeOriginal) {
Expand All @@ -104,9 +112,19 @@ object ShipAssembler {
AssemblyUtil.updateBlock(level,itPos,shipPos,level.getBlockState(shipPos))
}

val spawnWorldPos: Vector3dc = AssemblyUtil.getMiddle(structureCornerMin.toJOMLD(), structureCornerMax.toJOMLD()).add(0.5, 0.5, 0.5)

if (existingShip != null) {
sLevel.server.shipObjectWorld
.teleportShip(newShip as ServerShip, ShipTeleportDataImpl(existingShip.shipToWorld.transformPosition(spawnWorldPos, Vector3d()), existingShip.transform.shipToWorldRotation, existingShip.velocity, existingShip.omega, existingShip.chunkClaimDimension))

sLevel.server.shipObjectWorld
.teleportShip(newShip as ServerShip, ShipTeleportDataImpl(Vector3d(contraptionWorldPos.x.toDouble(),contraptionWorldPos.y.toDouble(),contraptionWorldPos.z.toDouble())))
} else {
sLevel.server.shipObjectWorld
.teleportShip(newShip as ServerShip, ShipTeleportDataImpl(spawnWorldPos))
}
if (shouldDisableSplitting) {
level.shipObjectWorld.loadedShips.getById(newShip.id)?.getAttachment<SplittingDisablerAttachment>()?.enableSplitting()
}

return newShip as ServerShip
}
Expand Down
Loading

0 comments on commit 7c6b8b6

Please sign in to comment.