Skip to content

Commit

Permalink
Spliterating
Browse files Browse the repository at this point in the history
  • Loading branch information
ThePlasticPotato committed Oct 25, 2024
1 parent d437831 commit 68764a2
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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 @@ -14,10 +15,15 @@ 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 @@ -137,19 +143,167 @@ object BlockStateInfo {
)

if (level is ServerLevel) {
if (!prevBlockState.isAir && newBlockState.isAir){
val blockNeighbors: HashSet<BlockPos> = HashSet()
for (dir in Direction.entries) {
val neighborPos = BlockPos(x, y, z).relative(dir)
val neighborState = level.getBlockState(neighborPos)
if (!neighborState.isAir) {
blockNeighbors.add(neighborPos)
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)
}
}
}
}
}
}
}
}
}
for (neighborPos in blockNeighbors) {
for (otherNeighborPos in blockNeighbors) {
if (neighborPos != otherNeighborPos) {

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)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ object ValkyrienSkiesMod {
lateinit var TEST_FLAP: Block
lateinit var TEST_WING: Block
lateinit var TEST_SPHERE: Block
lateinit var CONNECTION_CHECKER_ITEM: Item
lateinit var SHIP_CREATOR_ITEM: Item
lateinit var SHIP_ASSEMBLER_ITEM: Item
lateinit var SHIP_CREATOR_ITEM_SMALLER: Item
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.valkyrienskies.mod.common.item

import net.minecraft.Util
import net.minecraft.network.chat.TextComponent
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.InteractionResult
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.context.UseOnContext
import net.minecraft.world.level.block.state.BlockState
import org.valkyrienskies.mod.common.dimensionId
import org.valkyrienskies.mod.common.getShipManagingPos
import org.valkyrienskies.mod.common.shipObjectWorld
import java.util.function.DoubleSupplier

class ConnectionCheckerItem(
properties: Properties, private val scale: DoubleSupplier, private val minScaling: DoubleSupplier
) : Item(properties) {

override fun isFoil(stack: ItemStack): Boolean {
return true
}

override fun useOn(ctx: UseOnContext): InteractionResult {
val level = ctx.level as? ServerLevel ?: return super.useOn(ctx)
val blockPos = ctx.clickedPos
val blockState: BlockState = level.getBlockState(blockPos)
val item = ctx.itemInHand

if (item.item !is ConnectionCheckerItem) {
return InteractionResult.FAIL
}

if (!level.isClientSide) {
val parentShip = ctx.level.getShipManagingPos(blockPos)
if (!blockState.isAir) {
// Make a ship
val dimensionId = level.dimensionId

if (parentShip != null) {
if (item.tag != null && item.tag!!.contains("firstPosX")) {
val firstPosX = item.tag!!.getInt("firstPosX")
val firstPosY = item.tag!!.getInt("firstPosY")
val firstPosZ = item.tag!!.getInt("firstPosZ")
val connected = level.shipObjectWorld.isConnectedBySolid(blockPos.x, blockPos.y, blockPos.z, firstPosX, firstPosY, firstPosZ, dimensionId)
ctx.player?.sendMessage(TextComponent("Connected: $connected"), Util.NIL_UUID)
item.tag!!.remove("firstPosX")
item.tag!!.remove("firstPosY")
item.tag!!.remove("firstPosZ")
} else {
item.tag = item.orCreateTag.apply {
putInt("firstPosX", blockPos.x)
putInt("firstPosY", blockPos.y)
putInt("firstPosZ", blockPos.z)
}
ctx.player?.sendMessage(TextComponent("First block selected: (${blockPos.x}, ${blockPos.y}, ${blockPos.z}"), Util.NIL_UUID)
}
}
}
}

return super.useOn(ctx)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"block.valkyrienskies.test_flap": "Debug Flap",
"block.valkyrienskies.test_wing": "Debug Wing",
"item.valkyrienskies.ship_creator": "Ship Creator",
"item.valkyrienskies.connection_checker": "Connection Checker",
"item.valkyrienskies.ship_creator_smaller": "Mini Ship Creator",
"item.valkyrienskies.physics_entity_creator": "Physics Entity Creator",
"argument.valkyrienskies.ship.no_found": "Ship not found",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "minecraft:item/stick"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import org.valkyrienskies.mod.common.entity.ShipMountingEntity
import org.valkyrienskies.mod.common.entity.VSPhysicsEntity
import org.valkyrienskies.mod.common.entity.handling.VSEntityManager
import org.valkyrienskies.mod.common.hooks.VSGameEvents
import org.valkyrienskies.mod.common.item.ConnectionCheckerItem
import org.valkyrienskies.mod.common.item.PhysicsEntityCreatorItem
import org.valkyrienskies.mod.common.item.ShipAssemblerItem
import org.valkyrienskies.mod.common.item.ShipCreatorItem
Expand All @@ -63,6 +64,11 @@ class ValkyrienSkiesModFabric : ModInitializer {
ValkyrienSkiesMod.TEST_FLAP = TestFlapBlock
ValkyrienSkiesMod.TEST_WING = TestWingBlock
ValkyrienSkiesMod.TEST_SPHERE = TestSphereBlock
ValkyrienSkiesMod.CONNECTION_CHECKER_ITEM = ConnectionCheckerItem(
Properties().tab(CreativeModeTab.TAB_MISC),
{ 1.0 },
{ VSGameConfig.SERVER.minScaling }
)
ValkyrienSkiesMod.SHIP_CREATOR_ITEM = ShipCreatorItem(
Properties().tab(CreativeModeTab.TAB_MISC),
{ 1.0 },
Expand Down Expand Up @@ -114,6 +120,10 @@ class ValkyrienSkiesModFabric : ModInitializer {
registerBlockAndItem("test_flap", ValkyrienSkiesMod.TEST_FLAP)
registerBlockAndItem("test_wing", ValkyrienSkiesMod.TEST_WING)
registerBlockAndItem("test_sphere", ValkyrienSkiesMod.TEST_SPHERE)
Registry.register(
Registry.ITEM, ResourceLocation(ValkyrienSkiesMod.MOD_ID, "connection_checker"),
ValkyrienSkiesMod.CONNECTION_CHECKER_ITEM
)
Registry.register(
Registry.ITEM, ResourceLocation(ValkyrienSkiesMod.MOD_ID, "ship_assembler"),
ValkyrienSkiesMod.SHIP_ASSEMBLER_ITEM
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import org.valkyrienskies.mod.common.entity.ShipMountingEntity
import org.valkyrienskies.mod.common.entity.VSPhysicsEntity
import org.valkyrienskies.mod.common.entity.handling.VSEntityManager
import org.valkyrienskies.mod.common.hooks.VSGameEvents
import org.valkyrienskies.mod.common.item.ConnectionCheckerItem
import org.valkyrienskies.mod.common.item.PhysicsEntityCreatorItem
import org.valkyrienskies.mod.common.item.ShipAssemblerItem
import org.valkyrienskies.mod.common.item.ShipCreatorItem
Expand All @@ -62,6 +63,7 @@ class ValkyrienSkiesModForge {
private val TEST_FLAP_REGISTRY: RegistryObject<Block>
private val TEST_WING_REGISTRY: RegistryObject<Block>
private val TEST_SPHERE_REGISTRY: RegistryObject<Block>
private val CONNECTION_CHECKER_ITEM_REGISTRY: RegistryObject<Item>
private val SHIP_CREATOR_ITEM_REGISTRY: RegistryObject<Item>
private val SHIP_CREATOR_SMALLER_ITEM_REGISTRY: RegistryObject<Item>
private val PHYSICS_ENTITY_CREATOR_ITEM_REGISTRY: RegistryObject<Item>
Expand Down Expand Up @@ -119,6 +121,14 @@ class ValkyrienSkiesModForge {
{ 1.0 },
{ VSGameConfig.SERVER.minScaling })
}
CONNECTION_CHECKER_ITEM_REGISTRY =
ITEMS.register("connection_checker") {
ConnectionCheckerItem(
Properties().tab(CreativeModeTab.TAB_MISC),
{ 1.0 },
{ VSGameConfig.SERVER.minScaling }
)
}
SHIP_CREATOR_SMALLER_ITEM_REGISTRY =
ITEMS.register("ship_creator_smaller") {
ShipCreatorItem(
Expand Down Expand Up @@ -206,5 +216,6 @@ class ValkyrienSkiesModForge {
ValkyrienSkiesMod.PHYSICS_ENTITY_TYPE = PHYSICS_ENTITY_TYPE_REGISTRY.get()
ValkyrienSkiesMod.SHIP_ASSEMBLER_ITEM = SHIP_ASSEMBLER_ITEM_REGISTRY.get()
ValkyrienSkiesMod.TEST_HINGE_BLOCK_ENTITY_TYPE = TEST_HINGE_BLOCK_ENTITY_TYPE_REGISTRY.get()
ValkyrienSkiesMod.CONNECTION_CHECKER_ITEM = CONNECTION_CHECKER_ITEM_REGISTRY.get()
}
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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+2e644a6fea
vs_core_version=1.1.0+9d576c0e71
# 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
Expand Down

0 comments on commit 68764a2

Please sign in to comment.