Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ object PylonCore : JavaPlugin(), PylonAddon {
Bukkit.getPluginManager().registerEvents(BlockListener, this)
Bukkit.getPluginManager().registerEvents(PylonCopperBlock, this)
Bukkit.getPluginManager().registerEvents(PylonItemListener, this)
Bukkit.getScheduler().runTaskTimer(this, PylonInventoryTicker(), 0, PylonConfig.inventoryTickerBaseRate)
Bukkit.getScheduler().runTaskTimer(this, PylonInventoryTicker(), 0, PylonConfig.INVENTORY_TICKER_BASE_RATE)
Bukkit.getPluginManager().registerEvents(MultiblockCache, this)
Bukkit.getPluginManager().registerEvents(EntityStorage, this)
Bukkit.getPluginManager().registerEvents(EntityListener, this)
Expand All @@ -130,6 +130,7 @@ object PylonCore : JavaPlugin(), PylonAddon {
Bukkit.getPluginManager().registerEvents(PylonFluidBufferBlock, this)
Bukkit.getPluginManager().registerEvents(PylonFluidTank, this)
Bukkit.getPluginManager().registerEvents(PylonRecipeListener, this)
Bukkit.getPluginManager().registerEvents(PylonDirectionalBlock, this)
Bukkit.getPluginManager().registerEvents(FluidPipePlacementService, this)
Bukkit.getPluginManager().registerEvents(PylonTickingBlock, this)
Bukkit.getPluginManager().registerEvents(PylonGuide, this)
Expand All @@ -145,8 +146,8 @@ object PylonCore : JavaPlugin(), PylonAddon {

PylonGuide.settingsPage.addSetting(PageButton(PlayerSettingsPage.resourcePackSettings))

if (PylonConfig.ArmorTextureConfig.enabled) {
if (!PylonConfig.ArmorTextureConfig.forced) {
if (PylonConfig.ArmorTextureConfig.ENABLED) {
if (!PylonConfig.ArmorTextureConfig.FORCED) {
PlayerSettingsPage.resourcePackSettings.addSetting(TogglePlayerSettingButton(
pylonKey("toggle-armor-textures"),
toggle = { player -> player.hasCustomArmorTextures = !player.hasCustomArmorTextures },
Expand All @@ -156,13 +157,13 @@ object PylonCore : JavaPlugin(), PylonAddon {
packetEvents.eventManager.registerListener(ArmorTextureEngine, PacketListenerPriority.HIGHEST)
}

if (PylonConfig.BlockTextureConfig.enabled) {
if (PylonConfig.BlockTextureConfig.ENABLED) {
PlayerSettingsPage.resourcePackSettings.addSetting(PageButton(PlayerSettingsPage.blockTextureSettings))
Bukkit.getPluginManager().registerEvents(BlockTextureEngine, this)
BlockTextureEngine.updateOccludingCacheJob.start()
}

if (PylonConfig.researchesEnabled) {
if (PylonConfig.RESEARCHES_ENABLED) {
PylonGuide.settingsPage.addSetting(PlayerSettingsPage.researchConfetti)
PylonGuide.settingsPage.addSetting(PlayerSettingsPage.researchSounds)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ internal object BlockListener : Listener {
}
e.printStackTrace()
blockErrMap[block] = blockErrMap[block]?.plus(1) ?: 1
if (blockErrMap[block]!! > PylonConfig.allowedBlockErrors) {
if (blockErrMap[block]!! > PylonConfig.ALLOWED_BLOCK_ERRORS) {
BlockStorage.makePhantom(block)
if (block is PylonTickingBlock) {
PylonTickingBlock.stopTicking(block)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,15 +465,15 @@ object BlockStorage : Listener {
chunkAutosaveTasks[event.chunk.position] = PylonCore.launch(PylonCore.minecraftDispatcher) {

// Wait a random delay before starting, this is to help smooth out lag from saving
delay(Random.nextLong(PylonConfig.blockDataAutosaveIntervalSeconds * 1000))
delay(Random.nextLong(PylonConfig.BLOCK_DATA_AUTOSAVE_INTERVAL_SECONDS * 1000))

while (true) {
lockBlockRead {
val blocksInChunk = blocksByChunk[event.chunk.position]
check(blocksInChunk != null) { "Block autosave task was not cancelled properly" }
save(event.chunk, blocksInChunk)
}
delay(PylonConfig.blockDataAutosaveIntervalSeconds * 1000)
delay(PylonConfig.BLOCK_DATA_AUTOSAVE_INTERVAL_SECONDS * 1000)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ open class PylonBlock internal constructor(val block: Block) {
* can actually see it.
*/
open val blockTextureEntity: BlockTextureEntity? by lazy {
if (!PylonConfig.BlockTextureConfig.enabled || disableBlockTextureEntity) {
if (!PylonConfig.BlockTextureConfig.ENABLED || disableBlockTextureEntity) {
null
} else {
val entity = BlockTextureEntity(this)
Expand Down Expand Up @@ -215,10 +215,7 @@ open class PylonBlock internal constructor(val block: Block) {
open fun getBlockTextureProperties(): MutableMap<String, Pair<String, Int>> {
val properties = mutableMapOf<String, Pair<String, Int>>()
if (this is PylonDirectionalBlock) {
val facing = getFacing()
if (facing != null) {
properties["facing"] = facing.name.lowercase() to IMMEDIATE_FACES.size
}
properties["facing"] = facing.name.lowercase() to IMMEDIATE_FACES.size
}
return properties
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ interface PylonCargoBlock : PylonLogisticBlock, PylonEntityHolderBlock {

var cargoTransferRate: Int
/**
* Note that [cargoTransferRate] will be multiplied by [PylonConfig.cargoTransferRateMultiplier],
* Note that [cargoTransferRate] will be multiplied by [PylonConfig.CARGO_TRANSFER_RATE_MULTIPLIER],
* and the result will be the maximum number of items that can be transferred
* out of this block per cargo tick.
*
Expand Down Expand Up @@ -172,7 +172,7 @@ interface PylonCargoBlock : PylonLogisticBlock, PylonEntityHolderBlock {

val toTransfer = min(
min(targetMaxAmount - targetAmount, sourceAmount),
cargoBlockData.transferRate.toLong() * PylonConfig.cargoTransferRateMultiplier
cargoBlockData.transferRate.toLong() * PylonConfig.CARGO_TRANSFER_RATE_MULTIPLIER
)

if (sourceAmount == toTransfer) {
Expand Down Expand Up @@ -201,7 +201,7 @@ interface PylonCargoBlock : PylonLogisticBlock, PylonEntityHolderBlock {

@JvmStatic
fun cargoItemsTransferredPerSecond(cargoTransferRate: Int)
= (cargoTransferRate * PylonConfig.cargoTransferRateMultiplier).toDouble() / PylonConfig.cargoTickInterval.toDouble()
= (20 * cargoTransferRate * PylonConfig.CARGO_TRANSFER_RATE_MULTIPLIER).toDouble() / PylonConfig.CARGO_TICK_INTERVAL.toDouble()

internal data class CargoBlockData(
var groups: MutableMap<BlockFace, String>,
Expand All @@ -216,7 +216,7 @@ interface PylonCargoBlock : PylonLogisticBlock, PylonEntityHolderBlock {
private fun startTicker(block: PylonCargoBlock) {
cargoTickers[block] = PylonCore.launch(PylonCore.minecraftDispatcher) {
while (true) {
delay(PylonConfig.cargoTickInterval.ticks)
delay(PylonConfig.CARGO_TICK_INTERVAL.ticks)
block.tickCargo()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,61 @@
package io.github.pylonmc.pylon.core.block.base

import io.github.pylonmc.pylon.core.block.PylonBlock
import io.github.pylonmc.pylon.core.datatypes.PylonSerializers
import io.github.pylonmc.pylon.core.event.PylonBlockDeserializeEvent
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 org.bukkit.Keyed
import org.bukkit.block.BlockFace
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.jetbrains.annotations.ApiStatus
import java.util.IdentityHashMap
import kotlin.collections.set

/**
* Represents a block that has a specific facing direction.
*
* Internally only used for rotating [PylonBlock.blockTextureEntity]s.
*/
interface PylonDirectionalBlock {
fun getFacing(): BlockFace?
interface PylonDirectionalBlock : Keyed {

var facing: BlockFace
get() = directionalBlocks[this] ?: error("No direction was set for block $key")
set(value) {
directionalBlocks[this] = value
}

@ApiStatus.Internal
companion object : Listener {
private val directionalBlockKey = pylonKey("directional_block")

private val directionalBlocks = IdentityHashMap<PylonDirectionalBlock, BlockFace>()

@EventHandler
private fun onDeserialize(event: PylonBlockDeserializeEvent) {
val block = event.pylonBlock
if (block is PylonDirectionalBlock) {
directionalBlocks[block] = event.pdc.get(directionalBlockKey, PylonSerializers.BLOCK_FACE)
?: error("Direction not found for ${block.key}")
}
}

@EventHandler
private fun onSerialize(event: PylonBlockSerializeEvent) {
val block = event.pylonBlock
if (block is PylonDirectionalBlock) {
event.pdc.set(directionalBlockKey, PylonSerializers.BLOCK_FACE, directionalBlocks[block]!!)
}
}

@EventHandler
private fun onUnload(event: PylonBlockUnloadEvent) {
val block = event.pylonBlock
if (block is PylonDirectionalBlock) {
directionalBlocks.remove(block)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import io.github.pylonmc.pylon.core.block.context.BlockCreateContext
import io.github.pylonmc.pylon.core.content.fluid.FluidEndpointDisplay
import io.github.pylonmc.pylon.core.fluid.FluidPointType
import io.github.pylonmc.pylon.core.fluid.PylonFluid
import io.github.pylonmc.pylon.core.util.rotateToPlayerFacing
import io.github.pylonmc.pylon.core.util.rotateFaceToReference
import org.bukkit.block.BlockFace
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.MustBeInvokedByOverriders

/**
* A block that interacts with fluids in some way.
Expand All @@ -25,19 +24,11 @@ import org.jetbrains.annotations.ApiStatus
*
* Multiple inputs/outputs are not supported. You can have at most 1 input and 1 output.
*
* PylonFLuidBlocks automatically implement [PylonDirectionalBlock]. If the block has
* an input or output point, the block direction will be towards the output or input
* point's face. Output points take precedence over input points. You can override
* this behaviour by overriding [getFacing].
*
* @see PylonFluidBufferBlock
* @see PylonFluidTank
*/
interface PylonFluidBlock : PylonEntityHolderBlock, PylonDirectionalBlock, PylonBreakHandler {

override fun getFacing(): BlockFace? =
getHeldPylonEntity(FluidEndpointDisplay::class.java, "fluid_point_output")?.face
?: getHeldPylonEntity(FluidEndpointDisplay::class.java, "fluid_point_input")?.face
interface PylonFluidBlock : PylonEntityHolderBlock, PylonBreakHandler {

fun getFluidPointDisplay(type: FluidPointType) =
getHeldPylonEntity(FluidEndpointDisplay::class.java, getFluidPointName(type))
Expand All @@ -58,38 +49,6 @@ interface PylonFluidBlock : PylonEntityHolderBlock, PylonDirectionalBlock, Pylon
*/
fun createFluidPoint(type: FluidPointType, face: BlockFace) = createFluidPoint(type, face, 0.5F)

/**
* Creates a fluid input point. Call in your place constructor. Should be called at most once per block.
*
* @param player If supplied, the point will be rotated to the player's frame of reference, with NORTH
* considered 'forward'
* @param allowVerticalFaces Whether up/down should be considered when rotating to the player's frame
* of reference
*
* @see rotateToPlayerFacing
*/
fun createFluidPoint(type: FluidPointType, face: BlockFace, player: Player?, allowVerticalFaces: Boolean, radius: Float) {
var finalFace = face
if (player != null) {
finalFace = rotateToPlayerFacing(player, face, allowVerticalFaces)
}
createFluidPoint(type, finalFace, radius)
}

/**
* Creates a fluid input point. Call in your place constructor. Should be called at most once per block.
*
* @param player If supplied, the point will be rotated to the player's frame of reference, with NORTH
* considered 'forward'
* @param allowVerticalFaces Whether up/down should be considered when rotating to the player's frame
* of reference
*
* @see rotateToPlayerFacing
*/
fun createFluidPoint(type: FluidPointType, face: BlockFace, player: Player?, allowVerticalFaces: Boolean) {
createFluidPoint(type, face, player, allowVerticalFaces, 0.5F)
}

/**
* Creates a fluid input point. Call in your place constructor. Should be called at most once per block.
*
Expand All @@ -98,11 +57,14 @@ interface PylonFluidBlock : PylonEntityHolderBlock, PylonDirectionalBlock, Pylon
* @param allowVerticalFaces Whether up/down should be considered when rotating to the player's frame
* of reference
*
* @see rotateToPlayerFacing
* @see rotateFaceToReference
*/
fun createFluidPoint(type: FluidPointType, face: BlockFace, context: BlockCreateContext, allowVerticalFaces: Boolean) {
createFluidPoint(type, face, (context as? BlockCreateContext.PlayerPlace)?.player, allowVerticalFaces)
}
fun createFluidPoint(type: FluidPointType, face: BlockFace, context: BlockCreateContext, allowVerticalFaces: Boolean, radius: Float)
= createFluidPoint(
type,
rotateFaceToReference(if (allowVerticalFaces) context.facingVertical else context.facing, face),
radius
)

/**
* Creates a fluid input point. Call in your place constructor. Should be called at most once per block.
Expand All @@ -112,43 +74,43 @@ interface PylonFluidBlock : PylonEntityHolderBlock, PylonDirectionalBlock, Pylon
* @param allowVerticalFaces Whether up/down should be considered when rotating to the player's frame
* of reference
*
* @see rotateToPlayerFacing
* @see rotateFaceToReference
*/
fun createFluidPoint(type: FluidPointType, face: BlockFace, context: BlockCreateContext, allowVerticalFaces: Boolean, radius: Float) {
createFluidPoint(type, face, (context as? BlockCreateContext.PlayerPlace)?.player, allowVerticalFaces, radius)
}
fun createFluidPoint(type: FluidPointType, face: BlockFace, context: BlockCreateContext, allowVerticalFaces: Boolean)
= createFluidPoint(type, face, context, allowVerticalFaces, 0.5F)

@MustBeInvokedByOverriders
override fun onBreak(drops: MutableList<ItemStack>, context: BlockBreakContext) {
val player = (context as? BlockBreakContext.PlayerBreak)?.event?.player
getFluidPointDisplay(FluidPointType.INPUT)?.pipeDisplay?.delete(player, drops)
}

/**
* Returns a map of fluid types - and their corresponding amounts - that can be supplied by
* the block for this fluid tick. deltaSeconds is the time since the last fluid tick.
* the block for this fluid tick.
*
* If you have a machine that can supply up to 100 fluid per second, it should supply
* 100*deltaSeconds of that fluid
* 5 * PylonConfig.fluidTickInterval of that fluid
*
* Any implementation of this method must NEVER call the same method for any other connection
* point, otherwise you risk creating infinite loops.
*
* Called exactly one per fluid tick.
*/
fun getSuppliedFluids(deltaSeconds: Double): Map<PylonFluid, Double> = mapOf()
fun getSuppliedFluids(): Map<PylonFluid, Double> = mapOf()

/**
* Returns the amount of the given fluid that the machine wants to receive next tick.
*
* If you have a machine that consumes 100 water per second, it should request
* 100*deltaSeconds of water, and return 0 for every other fluid.
* If you have a machine that consumes 5 water per tick, it should request
* 5*PylonConfig.fluidTickInterval of water, and return 0 for every other fluid.
*
* Any implementation of this method must NEVER call the same method for any other connection
* point, otherwise you risk creating infinite loops.
*
* Called at most once for any given fluid type per tick.
*/
fun fluidAmountRequested(fluid: PylonFluid, deltaSeconds: Double): Double = 0.0
fun fluidAmountRequested(fluid: PylonFluid): Double = 0.0

/**
* `amount` is always at most `getRequestedFluids().get(fluid)` and will never
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ interface PylonFluidBufferBlock : PylonFluidBlock {
return setFluid(fluid, fluidData(fluid).amount - amount)
}

override fun fluidAmountRequested(fluid: PylonFluid, deltaSeconds: Double): Double
override fun fluidAmountRequested(fluid: PylonFluid): Double
= if (hasFluid(fluid) && fluidData(fluid).input) fluidSpaceRemaining(fluid) else 0.0

override fun getSuppliedFluids(deltaSeconds: Double): Map<PylonFluid, Double>
override fun getSuppliedFluids(): Map<PylonFluid, Double>
= fluidBuffers.filter { it.value.output }.mapValues { it.value.amount }

override fun onFluidAdded(fluid: PylonFluid, amount: Double) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ interface PylonFluidTank : PylonFluidBlock {

fun isAllowedFluid(fluid: PylonFluid): Boolean

override fun fluidAmountRequested(fluid: PylonFluid, deltaSeconds: Double): Double{
override fun fluidAmountRequested(fluid: PylonFluid): Double{
if (!isAllowedFluid(fluid)) {
return 0.0
}
Expand All @@ -137,7 +137,7 @@ interface PylonFluidTank : PylonFluidBlock {
}
}

override fun getSuppliedFluids(deltaSeconds: Double): Map<PylonFluid, Double> {
override fun getSuppliedFluids(): Map<PylonFluid, Double> {
val fluidData = this.fluidData // local variable to save calling fluidData getter multiple times
return if (fluidData.fluid == null) {
emptyMap()
Expand Down
Loading
Loading