diff --git a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/PylonCore.kt b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/PylonCore.kt index 7ff082fb9..462db80ef 100644 --- a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/PylonCore.kt +++ b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/PylonCore.kt @@ -117,7 +117,6 @@ object PylonCore : JavaPlugin(), PylonAddon { Bukkit.getPluginManager().registerEvents(BlockListener, this) Bukkit.getPluginManager().registerEvents(PylonItemListener, this) Bukkit.getScheduler().runTaskTimer(this, PylonInventoryTicker(), 0, PylonConfig.inventoryTickerBaseRate) - Bukkit.getPluginManager().registerEvents(TickManager, this) Bukkit.getPluginManager().registerEvents(MultiblockCache, this) Bukkit.getPluginManager().registerEvents(EntityStorage, this) Bukkit.getPluginManager().registerEvents(EntityListener, this) @@ -125,6 +124,7 @@ object PylonCore : JavaPlugin(), PylonAddon { Bukkit.getPluginManager().registerEvents(PylonGuiBlock, this) Bukkit.getPluginManager().registerEvents(PylonEntityHolderBlock, this) Bukkit.getPluginManager().registerEvents(PylonSimpleMultiblock, this) + Bukkit.getPluginManager().registerEvents(PylonProcessor, this) Bukkit.getPluginManager().registerEvents(PylonRecipeProcessor, this) Bukkit.getPluginManager().registerEvents(PylonFluidBufferBlock, this) Bukkit.getPluginManager().registerEvents(PylonFluidTank, this) diff --git a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/BlockListener.kt b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/BlockListener.kt index ed5bd1c69..95a08bb89 100644 --- a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/BlockListener.kt +++ b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/BlockListener.kt @@ -845,7 +845,9 @@ internal object BlockListener : Listener { blockErrMap[block] = blockErrMap[block]?.plus(1) ?: 1 if (blockErrMap[block]!! > PylonConfig.allowedBlockErrors) { BlockStorage.makePhantom(block) - TickManager.stopTicking(block) + if (block is PylonTickingBlock) { + PylonTickingBlock.stopTicking(block) + } } } } \ No newline at end of file diff --git a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/TickManager.kt b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/TickManager.kt deleted file mode 100644 index 559545bac..000000000 --- a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/TickManager.kt +++ /dev/null @@ -1,85 +0,0 @@ -package io.github.pylonmc.pylon.core.block - -import com.github.shynixn.mccoroutine.bukkit.asyncDispatcher -import com.github.shynixn.mccoroutine.bukkit.launch -import com.github.shynixn.mccoroutine.bukkit.minecraftDispatcher -import com.github.shynixn.mccoroutine.bukkit.ticks -import io.github.pylonmc.pylon.core.PylonCore -import io.github.pylonmc.pylon.core.block.BlockListener.logEventHandleErr -import io.github.pylonmc.pylon.core.block.base.PylonTickingBlock -import io.github.pylonmc.pylon.core.event.PylonBlockBreakEvent -import io.github.pylonmc.pylon.core.event.PylonBlockLoadEvent -import io.github.pylonmc.pylon.core.event.PylonBlockPlaceEvent -import io.github.pylonmc.pylon.core.event.PylonBlockUnloadEvent -import kotlinx.coroutines.Job -import kotlinx.coroutines.delay -import org.bukkit.event.EventHandler -import org.bukkit.event.EventPriority -import org.bukkit.event.Listener -import org.jetbrains.annotations.ApiStatus -import java.util.concurrent.ConcurrentHashMap - -@ApiStatus.Internal -object TickManager : Listener { - - private val tickingBlocks: MutableMap = ConcurrentHashMap() - - /** - * Returns true if the block is still ticking, or false if the block does - * not exist, is not a ticking block, or has errored and been unloaded. - */ - @JvmStatic - @ApiStatus.Internal - fun isTicking(block: PylonBlock): Boolean { - return tickingBlocks[block]?.isActive == true - } - - @JvmSynthetic - internal fun stopTicking(block: PylonBlock) { - tickingBlocks.remove(block)?.cancel() - } - - @EventHandler(priority = EventPriority.MONITOR) - private fun onPylonBlockPlace(e: PylonBlockPlaceEvent) { - startTicker(e.pylonBlock) - } - - @EventHandler(priority = EventPriority.MONITOR) - private fun onPylonBlockBreak(e: PylonBlockBreakEvent) { - val pylonBlock = e.pylonBlock - tickingBlocks.remove(pylonBlock)?.cancel() - } - - @EventHandler(priority = EventPriority.MONITOR) - private fun onPylonBlockLoad(e: PylonBlockLoadEvent) { - startTicker(e.pylonBlock) - } - - @EventHandler(priority = EventPriority.MONITOR) - private fun onPylonBlockUnload(e: PylonBlockUnloadEvent) { - tickingBlocks.remove(e.pylonBlock)?.cancel() - } - - private fun startTicker(pylonBlock: PylonBlock) { - if (pylonBlock is PylonTickingBlock) { - val dispatcher = - if (pylonBlock.isAsync) PylonCore.asyncDispatcher else PylonCore.minecraftDispatcher - val tickDelay = pylonBlock.tickInterval - tickingBlocks[pylonBlock] = PylonCore.launch(dispatcher) { - var lastTickNanos = System.nanoTime() - while (true) { - delay(tickDelay.ticks) - try { - val dt = (System.nanoTime() - lastTickNanos) / 1.0e9 - lastTickNanos = System.nanoTime() - pylonBlock.tick(dt) - } catch (e: Exception) { - PylonCore.launch(PylonCore.minecraftDispatcher) { - logEventHandleErr(null, e, pylonBlock) - } - } - } - } - } - } -} \ No newline at end of file diff --git a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonProcessor.kt b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonProcessor.kt new file mode 100644 index 000000000..52c392ce3 --- /dev/null +++ b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonProcessor.kt @@ -0,0 +1,148 @@ +package io.github.pylonmc.pylon.core.block.base + +import io.github.pylonmc.pylon.core.datatypes.PylonSerializers +import io.github.pylonmc.pylon.core.event.PylonBlockDeserializeEvent +import io.github.pylonmc.pylon.core.event.PylonBlockLoadEvent +import io.github.pylonmc.pylon.core.event.PylonBlockSerializeEvent +import io.github.pylonmc.pylon.core.event.PylonBlockUnloadEvent +import io.github.pylonmc.pylon.core.util.gui.ProgressItem +import io.github.pylonmc.pylon.core.util.pylonKey +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.jetbrains.annotations.ApiStatus +import java.util.IdentityHashMap + +/** + * An interface that tracks progress of some kind of process, such as processing a + * recipe, burning a piece of fuel, enchanting an item, etc + * + * This interface overrides [PylonTickingBlock.tick], meaning the rate at which the + * block progresses is determined by [PylonTickingBlock.setTickInterval]. + */ +interface PylonProcessor { + + @ApiStatus.Internal + data class ProcessorData( + var processTimeTicks: Int?, + var processTicksRemaining: Int?, + var progressItem: ProgressItem?, + ) + private val processorData: ProcessorData + get() = processorBlocks.getOrPut(this) { ProcessorData(null, null, null)} + + val processTimeTicks: Int? + @ApiStatus.NonExtendable + get() = processorData.processTimeTicks + + val processTicksRemaining: Int? + @ApiStatus.NonExtendable + get() = processorData.processTicksRemaining + + val isProcessing: Boolean + @ApiStatus.NonExtendable + get() = processTimeTicks != null + + /** + * Set the progress item that should be updated as the process progresses. Optional. + * + * Does not persist; you must call this whenever the block is initialised (e.g. + * in [io.github.pylonmc.pylon.core.block.PylonBlock.postInitialise]) + */ + fun setProgressItem(item: ProgressItem) { + processorData.progressItem = item + } + + /** + * Starts a new process with duration [ticks], with [ticks] being the number of server + * ticks the process will take. + */ + fun startProcess(ticks: Int) { + processorData.processTimeTicks = ticks + processorData.processTicksRemaining = ticks + processorData.progressItem?.setTotalTimeTicks(ticks) + processorData.progressItem?.setRemainingTimeTicks(ticks) + } + + fun stopProcess() { + val data = processorData + data.processTimeTicks = null + data.processTicksRemaining = null + data.progressItem?.totalTime = null + } + + fun finishProcess() { + check(isProcessing) { + "Cannot finish process because there is no process ongoing" + } + onProcessFinished() + stopProcess() + } + + fun onProcessFinished() {} + + @ApiStatus.Internal + fun progressProcess(ticks: Int) { + val data = processorData + if (data.processTimeTicks == null) { + return + } + + data.processTicksRemaining = data.processTicksRemaining!! - ticks + data.progressItem?.setRemainingTimeTicks(data.processTicksRemaining!!) + if (data.processTicksRemaining!! <= 0) { + finishProcess() + } + } + + @ApiStatus.Internal + companion object : Listener { + + private val processorKey = pylonKey("processor_data") + + private val processorBlocks = IdentityHashMap() + + @EventHandler + private fun onDeserialize(event: PylonBlockDeserializeEvent) { + val block = event.pylonBlock + if (block !is PylonProcessor) { + return + } + + val data = event.pdc.get(processorKey, PylonSerializers.PROCESSOR_DATA) + ?: error("Processor data not found for ${block.key}") + processorBlocks[block] = data + } + + @EventHandler + private fun onLoad(event: PylonBlockLoadEvent) { + // This separate listener is needed because when [PylonBlockDeserializeEvent] fires, then the + // block may not have been fully initialised yet (e.g. postInitialise may not have been called) + // which means progressItem may not have been set yet + val block = event.pylonBlock + if (block is PylonProcessor) { + val data = processorBlocks[block]!! + data.progressItem?.setTotalTimeTicks(data.processTimeTicks) + data.processTicksRemaining?.let { data.progressItem?.setRemainingTimeTicks(it) } + } + } + + @EventHandler + private fun onSerialize(event: PylonBlockSerializeEvent) { + val block = event.pylonBlock + if (block is PylonProcessor) { + val data = processorBlocks[block] ?: error { + "No recipe processor data found for ${block.key}" + } + event.pdc.set(processorKey, PylonSerializers.PROCESSOR_DATA, data) + } + } + + @EventHandler + private fun onUnload(event: PylonBlockUnloadEvent) { + val block = event.pylonBlock + if (block is PylonProcessor) { + processorBlocks.remove(block) + } + } + } +} \ No newline at end of file diff --git a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonRecipeProcessor.kt b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonRecipeProcessor.kt index c7fb0b0d6..1b6c2df7e 100644 --- a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonRecipeProcessor.kt +++ b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonRecipeProcessor.kt @@ -1,5 +1,6 @@ package io.github.pylonmc.pylon.core.block.base +import com.google.common.base.Preconditions import io.github.pylonmc.pylon.core.datatypes.PylonSerializers import io.github.pylonmc.pylon.core.event.PylonBlockDeserializeEvent import io.github.pylonmc.pylon.core.event.PylonBlockLoadEvent @@ -17,33 +18,36 @@ import java.util.IdentityHashMap /** * An interface that stores and progresses a recipe. * - * This does not actually handle the recipe inputs and outputs. Instead, it simply - * tracks a recipe that is being processed and how much time is left on it, ticking - * automatically. - * - * This interface overrides [PylonTickingBlock.tick], meaning the rate at which the - * recipe ticks is determined by [PylonTickingBlock.setTickInterval]. + * @see PylonProcessor */ -interface PylonRecipeProcessor : PylonTickingBlock { +interface PylonRecipeProcessor { + @ApiStatus.Internal data class RecipeProcessorData( var recipeType: RecipeType<*>?, var currentRecipe: PylonRecipe?, - var totalRecipeTicks: Int?, + var recipeTimeTicks: Int?, var recipeTicksRemaining: Int?, var progressItem: ProgressItem?, ) private val recipeProcessorData: RecipeProcessorData + @ApiStatus.NonExtendable get() = recipeProcessorBlocks.getOrPut(this) { RecipeProcessorData(null, null, null, null, null)} val currentRecipe: T? + @ApiStatus.NonExtendable // cast should always be safe due to type restriction when starting recipe get() = recipeProcessorData.currentRecipe as T? val recipeTicksRemaining: Int? + @ApiStatus.NonExtendable get() = recipeProcessorData.recipeTicksRemaining + val isProcessingRecipe: Boolean + @ApiStatus.NonExtendable + get() = currentRecipe != null + /** * Set the progress item that should be updated as the recipe progresses. Optional. * @@ -71,37 +75,43 @@ interface PylonRecipeProcessor : PylonTickingBlock { */ fun startRecipe(recipe: T, ticks: Int) { recipeProcessorData.currentRecipe = recipe - recipeProcessorData.totalRecipeTicks = ticks + recipeProcessorData.recipeTimeTicks = ticks recipeProcessorData.recipeTicksRemaining = ticks recipeProcessorData.progressItem?.setTotalTimeTicks(ticks) recipeProcessorData.progressItem?.setRemainingTimeTicks(ticks) } + fun stopRecipe() { + val data = recipeProcessorData + data.currentRecipe = null + data.recipeTimeTicks = null + data.recipeTicksRemaining = null + data.progressItem?.totalTime = null + } + + fun finishRecipe() { + check(isProcessingRecipe) { + "Cannot finish recipe because there is no recipe being processed" + } + @Suppress("UNCHECKED_CAST") // cast should always be safe due to type restriction when starting recipe + onRecipeFinished(recipeProcessorData.currentRecipe as T) + stopRecipe() + } + fun onRecipeFinished(recipe: T) - override fun tick(deltaSeconds: Double) { + fun progressRecipe(ticks: Int) { val data = recipeProcessorData - if (data.currentRecipe != null && data.recipeTicksRemaining != null) { + data.recipeTicksRemaining = data.recipeTicksRemaining!! - ticks data.progressItem?.setRemainingTimeTicks(data.recipeTicksRemaining!!) - - // tick recipe - if (data.recipeTicksRemaining!! > 0) { - data.recipeTicksRemaining = data.recipeTicksRemaining!! - tickInterval - return + if (data.recipeTicksRemaining!! <= 0) { + finishRecipe() } - - // finish recipe - onRecipeFinished(data.currentRecipe as T) - data.currentRecipe = null - data.totalRecipeTicks = null - data.recipeTicksRemaining = null - data.progressItem?.totalTime = null - // cast should always be safe due to type restriction when starting recipe - return } } + @ApiStatus.Internal companion object : Listener { private val recipeProcessorKey = pylonKey("recipe_processor_data") @@ -126,7 +136,7 @@ interface PylonRecipeProcessor : PylonTickingBlock { val block = event.pylonBlock if (block is PylonRecipeProcessor<*>) { val data = recipeProcessorBlocks[block]!! - data.progressItem?.setTotalTimeTicks(data.totalRecipeTicks) + data.progressItem?.setTotalTimeTicks(data.recipeTimeTicks) data.recipeTicksRemaining?.let { data.progressItem?.setRemainingTimeTicks(it) } } } @@ -135,7 +145,11 @@ interface PylonRecipeProcessor : PylonTickingBlock { private fun onSerialize(event: PylonBlockSerializeEvent) { val block = event.pylonBlock if (block is PylonRecipeProcessor<*>) { - event.pdc.set(recipeProcessorKey, PylonSerializers.RECIPE_PROCESSOR_DATA, recipeProcessorBlocks[block]!!) + val data = recipeProcessorBlocks[block] ?: error { + "No recipe processor data found for ${block.key}" + } + event.pdc.set(recipeProcessorKey, PylonSerializers.RECIPE_PROCESSOR_DATA, data) + check(data.recipeType != null) { "No recipe type set for ${event.pylonBlock.key}; did you forget to call setRecipeType in your place constructor?" } } } diff --git a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonTickingBlock.kt b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonTickingBlock.kt index 498b82d21..073bc2741 100644 --- a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonTickingBlock.kt +++ b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/block/base/PylonTickingBlock.kt @@ -1,13 +1,25 @@ package io.github.pylonmc.pylon.core.block.base +import com.github.shynixn.mccoroutine.bukkit.asyncDispatcher +import com.github.shynixn.mccoroutine.bukkit.launch +import com.github.shynixn.mccoroutine.bukkit.minecraftDispatcher +import com.github.shynixn.mccoroutine.bukkit.ticks +import io.github.pylonmc.pylon.core.PylonCore +import io.github.pylonmc.pylon.core.block.BlockListener.logEventHandleErr +import io.github.pylonmc.pylon.core.block.PylonBlock import io.github.pylonmc.pylon.core.config.PylonConfig import io.github.pylonmc.pylon.core.datatypes.PylonSerializers import io.github.pylonmc.pylon.core.event.PylonBlockBreakEvent import io.github.pylonmc.pylon.core.event.PylonBlockDeserializeEvent +import io.github.pylonmc.pylon.core.event.PylonBlockLoadEvent +import io.github.pylonmc.pylon.core.event.PylonBlockPlaceEvent import io.github.pylonmc.pylon.core.event.PylonBlockSerializeEvent import io.github.pylonmc.pylon.core.event.PylonBlockUnloadEvent import io.github.pylonmc.pylon.core.util.pylonKey +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import org.bukkit.event.EventHandler +import org.bukkit.event.EventPriority import org.bukkit.event.Listener import org.jetbrains.annotations.ApiStatus import java.util.IdentityHashMap @@ -20,7 +32,8 @@ interface PylonTickingBlock { private val tickingData: TickingBlockData get() = tickingBlocks.getOrPut(this) { TickingBlockData( PylonConfig.defaultTickInterval, - false + false, + null )} /** @@ -67,6 +80,7 @@ interface PylonTickingBlock { internal data class TickingBlockData( var tickInterval: Int, var isAsync: Boolean, + var job: Job?, ) private val tickingBlockKey = pylonKey("ticking_block_data") @@ -94,7 +108,7 @@ interface PylonTickingBlock { private fun onUnload(event: PylonBlockUnloadEvent) { val block = event.pylonBlock if (block is PylonTickingBlock) { - tickingBlocks.remove(block) + tickingBlocks.remove(block)?.job?.cancel() } } @@ -102,7 +116,57 @@ interface PylonTickingBlock { private fun onBreak(event: PylonBlockBreakEvent) { val block = event.pylonBlock if (block is PylonTickingBlock) { - tickingBlocks.remove(block) + tickingBlocks.remove(block)?.job?.cancel() + } + } + + @EventHandler + private fun onPylonBlockPlace(event: PylonBlockPlaceEvent) { + val block = event.pylonBlock + if (block is PylonTickingBlock) { + startTicker(block) + } + } + + @EventHandler + private fun onPylonBlockLoad(event: PylonBlockLoadEvent) { + val block = event.pylonBlock + if (block is PylonTickingBlock) { + startTicker(block) + } + } + + /** + * Returns true if the block is still ticking, or false if the block does + * not exist, is not a ticking block, or has errored and been unloaded. + */ + @JvmStatic + @ApiStatus.Internal + fun isTicking(block: PylonBlock?): Boolean { + return block is PylonTickingBlock && tickingBlocks[block]?.job?.isActive == true + } + + @JvmSynthetic + internal fun stopTicking(block: PylonTickingBlock) { + tickingBlocks[block]?.job?.cancel() + } + + private fun startTicker(tickingBlock: PylonTickingBlock) { + val dispatcher = if (tickingBlock.isAsync) PylonCore.asyncDispatcher else PylonCore.minecraftDispatcher + tickingBlocks[tickingBlock]?.job = PylonCore.launch(dispatcher) { + var lastTickNanos = System.nanoTime() + while (true) { + delay(tickingBlock.tickInterval.ticks) + try { + val dt = (System.nanoTime() - lastTickNanos) / 1.0e9 + lastTickNanos = System.nanoTime() + tickingBlock.tick(dt) + } catch (e: Exception) { + PylonCore.launch(PylonCore.minecraftDispatcher) { + logEventHandleErr(null, e, tickingBlock as PylonBlock) + } + } + } } } } diff --git a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/content/debug/DebugWaxedWeatheredCutCopperStairs.kt b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/content/debug/DebugWaxedWeatheredCutCopperStairs.kt index 54eceea47..66eb83282 100644 --- a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/content/debug/DebugWaxedWeatheredCutCopperStairs.kt +++ b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/content/debug/DebugWaxedWeatheredCutCopperStairs.kt @@ -2,7 +2,6 @@ package io.github.pylonmc.pylon.core.content.debug import io.github.pylonmc.pylon.core.block.BlockStorage import io.github.pylonmc.pylon.core.block.PylonBlock -import io.github.pylonmc.pylon.core.block.TickManager import io.github.pylonmc.pylon.core.block.base.PylonTickingBlock import io.github.pylonmc.pylon.core.datatypes.PylonSerializers import io.github.pylonmc.pylon.core.entity.EntityStorage @@ -72,7 +71,7 @@ internal class DebugWaxedWeatheredCutCopperStairs(stack: ItemStack) ) player.sendDebug( when (pylonBlock) { - is PylonTickingBlock -> if (TickManager.isTicking(pylonBlock)) { + is PylonTickingBlock -> if (PylonTickingBlock.isTicking(pylonBlock)) { "ticking.ticking" } else { "ticking.error" diff --git a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/ProcessorDataPersistentDataType.kt b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/ProcessorDataPersistentDataType.kt new file mode 100644 index 000000000..121c65ad5 --- /dev/null +++ b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/ProcessorDataPersistentDataType.kt @@ -0,0 +1,35 @@ +package io.github.pylonmc.pylon.core.datatypes + +import io.github.pylonmc.pylon.core.block.base.PylonProcessor +import io.github.pylonmc.pylon.core.block.base.PylonRecipeProcessor +import io.github.pylonmc.pylon.core.registry.PylonRegistry +import io.github.pylonmc.pylon.core.util.pylonKey +import io.github.pylonmc.pylon.core.util.setNullable +import org.bukkit.persistence.PersistentDataAdapterContext +import org.bukkit.persistence.PersistentDataContainer +import org.bukkit.persistence.PersistentDataType + +internal object ProcessorDataPersistentDataType : PersistentDataType { + + private val PROCESS_TIME_TICKS_KEY = pylonKey("total_process_ticks") + private val PROCESS_TICKS_REMAINING_KEY = pylonKey("process_ticks_remaining") + + override fun getPrimitiveType(): Class = PersistentDataContainer::class.java + + override fun getComplexType(): Class = PylonProcessor.ProcessorData::class.java + + override fun fromPrimitive(primitive: PersistentDataContainer, context: PersistentDataAdapterContext): PylonProcessor.ProcessorData { + return PylonProcessor.ProcessorData( + primitive.get(PROCESS_TIME_TICKS_KEY, PylonSerializers.INTEGER), + primitive.get(PROCESS_TICKS_REMAINING_KEY, PylonSerializers.INTEGER), + null + ) + } + + override fun toPrimitive(complex: PylonProcessor.ProcessorData, context: PersistentDataAdapterContext): PersistentDataContainer { + val pdc = context.newPersistentDataContainer() + pdc.setNullable(PROCESS_TIME_TICKS_KEY, PylonSerializers.INTEGER, complex.processTimeTicks) + pdc.setNullable(PROCESS_TICKS_REMAINING_KEY, PylonSerializers.INTEGER, complex.processTicksRemaining) + return pdc + } +} diff --git a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/PylonSerializers.kt b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/PylonSerializers.kt index 3b50a8a1f..c3a209bf9 100644 --- a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/PylonSerializers.kt +++ b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/PylonSerializers.kt @@ -117,6 +117,9 @@ object PylonSerializers { @JvmSynthetic internal val FLUID_TANK_DATA = FluidTankDataPersistentDataType + @JvmSynthetic + internal val PROCESSOR_DATA = ProcessorDataPersistentDataType + @JvmSynthetic internal val RECIPE_PROCESSOR_DATA = RecipeProcessorDataPersistentDataType diff --git a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/RecipeProcessorDataPersistentDataType.kt b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/RecipeProcessorDataPersistentDataType.kt index 3ffb2ba4e..e7281ab8b 100644 --- a/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/RecipeProcessorDataPersistentDataType.kt +++ b/pylon-core/src/main/kotlin/io/github/pylonmc/pylon/core/datatypes/RecipeProcessorDataPersistentDataType.kt @@ -8,11 +8,11 @@ import org.bukkit.persistence.PersistentDataAdapterContext import org.bukkit.persistence.PersistentDataContainer import org.bukkit.persistence.PersistentDataType -object RecipeProcessorDataPersistentDataType : PersistentDataType { +internal object RecipeProcessorDataPersistentDataType : PersistentDataType { private val RECIPE_TYPE_KEY = pylonKey("recipe_type") private val CURRENT_RECIPE_KEY = pylonKey("current_recipe") - private val TOTAL_RECIPE_TICKS_KEY = pylonKey("total_recipe_ticks") + private val RECIPE_TIME_TICKS_KEY = pylonKey("recipe_time_ticks") private val RECIPE_TICKS_REMAINING_KEY = pylonKey("recipe_ticks_remaining") private val RECIPE_TYPE_TYPE = PylonSerializers.KEYED.keyedTypeFrom { key -> PylonRegistry.RECIPE_TYPES.getOrThrow(key) } @@ -27,7 +27,7 @@ object RecipeProcessorDataPersistentDataType : PersistentDataType { BlockStorage.placeBlock(test.location(), TickingErrorBlock.KEY); - test.succeedWhen(() -> !TickManager.isTicking(BlockStorage.get(test.location()))); + test.succeedWhen(() -> !PylonTickingBlock.isTicking(BlockStorage.get(test.location().getBlock()))); }) .build()); }