Skip to content

Commit

Permalink
fix times power isn't transferring, more robust relation system
Browse files Browse the repository at this point in the history
  • Loading branch information
Gutin1 committed Sep 26, 2024
1 parent 074cf8e commit 56f4501
Show file tree
Hide file tree
Showing 15 changed files with 198 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ object IonChunkCommand : SLCommand() {
sender.information("Targeted node: ${grid.nodes[key]}")
}

@Subcommand("get node look relations")
fun getNodeRelations(sender: Player, network: NetworkType) {
val targeted = sender.getTargetBlock(null, 10)
val ionChunk = targeted.chunk.ion()
val grid = network.get(ionChunk)
val key = toBlockKey(targeted.x, targeted.y, targeted.z)

sender.information("${grid.nodes[key]?.getTransferableNodes()?.joinToString { it.javaClass.simpleName }}")
}

@Subcommand("tick extractor")
fun onTick(sender: Player) {
val targeted = sender.getTargetBlock(null, 10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ object NewTransport : IonServerComponent(runAfterTick = true /* Run after tick t
}

override fun onDisable() {
if (::monitorThread.isInitialized) monitorThread.cancel()
if (::executor.isInitialized) executor.shutdown()
if (::monitorThread.isInitialized) executor.shutdown()
}

fun registerTransportManager(manager: TransportManager) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.horizonsend.ion.server.features.transport.node

import net.horizonsend.ion.server.miscellaneous.utils.coordinates.BlockKey
import org.bukkit.block.BlockFace

/**
Expand All @@ -22,18 +21,6 @@ data class NodeRelationship(
holder.refreshTransferCache()
other.refreshTransferCache()
}

companion object {
fun create(point: BlockKey, holder: TransportNode, other: TransportNode, nodeTwoOffset: BlockFace) {
val holderToOther = holder.isTransferableTo(other)
val otherToHolder = other.isTransferableTo(holder)

holder.relationships[point] = NodeRelationship(holder, other, nodeTwoOffset, holderToOther)
other.relationships[point] = NodeRelationship(other, holder, nodeTwoOffset.oppositeFace, otherToHolder)
holder.refreshTransferCache()
other.refreshTransferCache()
}
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package net.horizonsend.ion.server.features.transport.node

import it.unimi.dsi.fastutil.ints.IntOpenHashSet
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.BlockKey
import org.bukkit.block.BlockFace
import java.util.concurrent.BlockingDeque
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.LinkedBlockingDeque

class RelationHolder(val node: TransportNode) {
private val relationships = ConcurrentHashMap<BlockKey, BlockingDeque<NodeRelationship>>()
private val containsCache = ConcurrentHashMap<BlockKey, IntOpenHashSet>()

/**
* Create a relationship between this node and the provided node
*
* If neither side can transfer, a relation will not be created
**/
fun addRelationship(other: TransportNode, holderPosition: BlockKey, otherPosition: BlockKey, nodeTwoOffset: BlockFace) {
// Do not add duplicates
val existingAt = relationships[holderPosition]
if (existingAt != null && existingAt.any { it.other == other }) return

create(other, holderPosition, otherPosition, nodeTwoOffset)
other.neighborChanged(node)
}

/**
* @param other The node this relation is being created with
* @param holderPosition The position that this node was created from
* @param otherPosition The position that the other node was found at
* @param nodeTwoOffset The direction that the other node was found
**/
private fun create(other: TransportNode, holderPosition: BlockKey, otherPosition: BlockKey, nodeTwoOffset: BlockFace) {
val holderToOther = node.isTransferableTo(other)
val otherToHolder = other.isTransferableTo(node)

// Add relation from this node to the other
add(holderPosition, NodeRelationship(node, other, nodeTwoOffset, holderToOther))
// Add relation from the other to this
other.relationHolder.add(otherPosition, NodeRelationship(other, node, nodeTwoOffset.oppositeFace, otherToHolder))

node.refreshTransferCache()
other.refreshTransferCache()
}

fun add(point: BlockKey, relation: NodeRelationship) {
relationships.getOrPut(point) { LinkedBlockingDeque() }.add(relation)
containsCache.getOrPut(point) { IntOpenHashSet() }.add(relation.other.hashCode())
}

fun remove(point: BlockKey, relation: NodeRelationship) {
relationships[point]?.remove(relation)
containsCache[point]?.remove(relation.other.hashCode())
}

fun removeAll(point: BlockKey): BlockingDeque<NodeRelationship>? {
return relationships.remove(point)
}

fun clear() {
relationships.values.forEach {
for (nodeRelationship in it) {
nodeRelationship.breakUp()
}
}
}

fun removeRelationship(other: TransportNode) {
// Handle duplicate cases
for (key in relationships.keys.filter { containsCache.contains(other.hashCode()) }) {
relationships[key]?.removeAll { it.other == other }
}

// Notify of neighbor change
other.neighborChanged(node)
}

fun getAllOthers(): Set<NodeRelationship> {
val others = ObjectOpenHashSet<NodeRelationship>()

for (key in relationships.keys) {
for (relation in relationships[key]!!) {
others.add(relation)
}
}

return others
}

fun raw() = relationships

fun hasRelationAt(position: BlockKey): Boolean = relationships.containsKey(position)
fun hasRelationAtWith(point: BlockKey, other: TransportNode): Boolean = containsCache[point]?.contains(other.hashCode()) ?: false
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import kotlinx.serialization.SerializationException
import net.horizonsend.ion.server.features.transport.node.manager.NodeManager
import net.horizonsend.ion.server.miscellaneous.registrations.persistence.NamespacedKeys.NODE_TYPE
import net.horizonsend.ion.server.miscellaneous.registrations.persistence.PDCSerializable
import net.horizonsend.ion.server.miscellaneous.utils.ADJACENT_BLOCK_FACES
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.BlockKey
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.Vec3i
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.getRelative
import org.bukkit.block.BlockFace
import org.bukkit.persistence.PersistentDataAdapterContext
import org.bukkit.persistence.PersistentDataContainer
import org.bukkit.persistence.PersistentDataType
import java.util.concurrent.ConcurrentHashMap

/**
* Represents a single node, or step, in transport transportNetwork
Expand All @@ -21,50 +22,19 @@ abstract class TransportNode : PDCSerializable<TransportNode, TransportNode.Comp
override val persistentDataType: Companion get() = Companion
abstract val type: NodeType

/** Stored relationships between nodes **/
val relationships: ConcurrentHashMap<BlockKey, NodeRelationship> = ConcurrentHashMap()
val relationHolder = RelationHolder(this)

/**
* Break all relations between this node and others
**/
fun clearRelations() {
relationships.values.forEach {
it.breakUp()
}
}

/**
* Create a relationship between this node and the provided node
*
* If neither side can transfer, a relation will not be created
**/
fun addRelationship(point: BlockKey, other: TransportNode, offset: BlockFace) {
// Do not add duplicates
val existing = relationships[point]
if (existing?.other == other) return

NodeRelationship.create(point, this, other, offset)
other.neighborChanged(this)
}

fun removeRelationship(other: TransportNode) {
// Handle duplicate cases
val toOther = relationships.filter { it.value.other == other }

toOther.keys.forEach { relationships.remove(it) }
fun clearRelations() = relationHolder.clear()

// Notify of neighbor change
other.neighborChanged(this)
}
fun removeRelationship(other: TransportNode) = relationHolder.removeRelationship(other)

fun removeRelationship(at: BlockKey) {
// Handle duplicate cases
val toOther = relationships[at]
toOther?.breakUp()
fun removeRelationships(at: BlockKey) = relationHolder.removeAll(at)

// Notify of neighbor change
toOther?.other?.neighborChanged(this)
}
fun addRelationship(other: TransportNode, holderPosition: BlockKey, otherPosition: BlockKey, nodeTwoOffset: BlockFace) =
relationHolder.addRelationship(other, holderPosition, otherPosition, nodeTwoOffset)

/**
* Returns whether this node may transport to the provided node
Expand All @@ -85,9 +55,9 @@ abstract class TransportNode : PDCSerializable<TransportNode, TransportNode.Comp
* Gets the distinct nodes this can transfer to
**/
fun getTransferableNodes(): Collection<TransportNode> {
return relationships.mapNotNullTo(mutableSetOf()) { relation ->
return relationHolder.getAllOthers().mapNotNullTo(mutableSetOf()) { relation ->
// The other side of the relation, only if transfer is possible between this node and it. Double check if it is dead as well
relation.value.other.takeIf { other -> relation.value.canTransfer && !other.isDead }
relation.other.takeIf { relation.canTransfer && !it.isDead }
}
}

Expand All @@ -113,10 +83,25 @@ abstract class TransportNode : PDCSerializable<TransportNode, TransportNode.Comp
**/
open fun handlePositionRemoval(position: BlockKey) {}

/**
* The directions in which to try ro build relations
**/
protected open val relationOffsets = ADJACENT_BLOCK_FACES

/**
* Builds relations between this node and transferrable nodes
**/
abstract fun buildRelations(position: BlockKey)
open fun buildRelations(position: BlockKey) {
for (offset in relationOffsets) {
val offsetKey = getRelative(position, offset, 1)
val neighborNode = manager.getNode(offsetKey) ?: continue

if (this == neighborNode) continue

// Add a relationship, if one should be added
addRelationship(neighborNode, position, offsetKey, offset)
}
}

/**
* Notify a node if a neighbor changed
Expand All @@ -136,7 +121,15 @@ abstract class TransportNode : PDCSerializable<TransportNode, TransportNode.Comp
private val relationCache = mutableMapOf<TransportNode, Map<BlockKey, NodeRelationship>>()

fun getRelationshipWith(other: TransportNode): Map<BlockKey, NodeRelationship> {
return relationCache.getOrPut(other) { relationships.filter { it.value.other == other } }
return relationCache.getOrPut(other) {
val cache = mutableMapOf<BlockKey, NodeRelationship>()
for ((key, relations) in relationHolder.raw()) {
if (!relationHolder.hasRelationAtWith(key, other)) continue
cache[key] = relations.firstOrNull { it.other == other } ?: continue
}

cache
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import net.horizonsend.ion.server.miscellaneous.registrations.persistence.Namesp
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.BlockKey
import org.bukkit.NamespacedKey
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Future
import kotlin.math.roundToInt

class PowerNodeManager(holder: NetworkHolder<PowerNodeManager>) : NodeManager(holder) {
Expand All @@ -42,7 +43,7 @@ class PowerNodeManager(holder: NetworkHolder<PowerNodeManager>) : NodeManager(ho
solarPanels.forEach(::tickSolarPanel)
}

fun tickExtractor(extractorNode: PowerExtractorNode) = NewTransport.executor.submit {
fun tickExtractor(extractorNode: PowerExtractorNode): Future<*> = NewTransport.executor.submit {
val powerCheck = extractorNode.getTransferPower()
if (powerCheck == 0) return@submit

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,6 @@ abstract class MultiNode<Self: MultiNode<Self, Z>, Z: MultiNode<Z, Self>> : Tran
new.positions.forEach { new.buildRelations(it) }
}

override fun buildRelations(position: BlockKey) {
for (offset in ADJACENT_BLOCK_FACES) {
val offsetKey = getRelative(position, offset, 1)
val neighborNode = manager.getNode(offsetKey) ?: continue

if (this == neighborNode) continue

addRelationship(position, neighborNode, offset)
}
}

fun rebuildRelations() {
clearRelations()

Expand All @@ -89,7 +78,7 @@ abstract class MultiNode<Self: MultiNode<Self, Z>, Z: MultiNode<Z, Self>> : Tran

// Remove the position from this node
positions.remove(position)
removeRelationship(position)
removeRelationships(position)

if (separateNode(this)) {
positions.clear()
Expand Down Expand Up @@ -125,9 +114,10 @@ abstract class MultiNode<Self: MultiNode<Self, Z>, Z: MultiNode<Z, Self>> : Tran

positions.forEach {
newNode.addPosition(it)
newNode.buildRelations(it)
}

newNode.rebuildRelations()

return newNode
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package net.horizonsend.ion.server.features.transport.node.type

import net.horizonsend.ion.server.features.transport.node.TransportNode
import net.horizonsend.ion.server.miscellaneous.utils.ADJACENT_BLOCK_FACES
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.BlockKey
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.Vec3i
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.getRelative
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.toVec3i
import kotlin.properties.Delegates

Expand All @@ -18,18 +16,6 @@ abstract class SingleNode : TransportNode() {
manager.nodes[position] = this
}

override fun buildRelations(position: BlockKey) {
for (offset in ADJACENT_BLOCK_FACES) {
val offsetKey = getRelative(position, offset, 1)
val neighborNode = manager.getNode(offsetKey) ?: continue

if (this == neighborNode) return

// Add a relationship, if one should be added
addRelationship(position, neighborNode, offset)
}
}

override fun onPlace(position: BlockKey) {
buildRelations(position)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ class FluidInputNode(override val manager: FluidNodeManager) : SingleNode() {
return false
}

override fun buildRelations(position: BlockKey) {
super.buildRelations(position)
}

override fun storeData(persistentDataContainer: PersistentDataContainer) {
persistentDataContainer.set(NamespacedKeys.NODE_COVERED_POSITIONS, PersistentDataType.LONG, position)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import net.horizonsend.ion.server.features.transport.node.NodeType
import net.horizonsend.ion.server.features.transport.node.manager.FluidNodeManager
import net.horizonsend.ion.server.features.transport.node.type.general.JunctionNode
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.BlockKey
import net.horizonsend.ion.server.miscellaneous.utils.coordinates.toVec3i

class FluidJunctionNode(network: FluidNodeManager) : JunctionNode<FluidNodeManager, FluidJunctionNode, FluidJunctionNode>(network) {
override val type: NodeType = NodeType.FLUID_JUNCTION
Expand All @@ -19,7 +20,7 @@ class FluidJunctionNode(network: FluidNodeManager) : JunctionNode<FluidNodeManag
return """
[Gas Junction Node]
${positions.size} positions
Relationships: ${relationships.values.joinToString { it.other.toString() }}
Relationships: ${relationHolder.raw().entries.joinToString { (key, relations) -> "[${toVec3i(key)} = (${relations.joinToString { it.other.toString() }}(]" }}
""".trimIndent()
}
}
Loading

0 comments on commit 56f4501

Please sign in to comment.