Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion src/main/kotlin/com/coderjoe/atlas/Atlas.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import com.coderjoe.atlas.power.PowerBlockDialog
import com.coderjoe.atlas.power.PowerBlockFactory
import com.coderjoe.atlas.power.PowerBlockPersistence
import com.coderjoe.atlas.power.PowerBlockRegistry
import com.coderjoe.atlas.transport.TransportBlockDialog
import com.coderjoe.atlas.transport.TransportBlockFactory
import com.coderjoe.atlas.transport.TransportBlockPersistence
import com.coderjoe.atlas.transport.TransportBlockRegistry
import org.bukkit.plugin.java.JavaPlugin
import org.bukkit.scheduler.BukkitTask

Expand All @@ -20,6 +24,8 @@ class Atlas : JavaPlugin() {
private lateinit var powerBlockPersistence: PowerBlockPersistence
private lateinit var fluidBlockRegistry: FluidBlockRegistry
private lateinit var fluidBlockPersistence: FluidBlockPersistence
private lateinit var transportBlockRegistry: TransportBlockRegistry
private lateinit var transportBlockPersistence: TransportBlockPersistence
private var autoSaveTask: BukkitTask? = null

override fun onEnable() {
Expand All @@ -42,9 +48,11 @@ class Atlas : JavaPlugin() {

PowerBlockDialog.init(this)
FluidBlockDialog.init(this)
TransportBlockDialog.init(this)

initPowerSystem()
initFluidSystem()
initTransportSystem()

// Register unified listener
val powerSystem = BlockSystem<com.coderjoe.atlas.power.PowerBlock>(
Expand All @@ -67,15 +75,26 @@ class Atlas : JavaPlugin() {
}
)

val transportSystem = BlockSystem<com.coderjoe.atlas.transport.TransportBlock>(
name = "transport",
registry = transportBlockRegistry,
factory = TransportBlockFactory,
descriptors = transportDescriptors(),
showDialog = { player, block ->
TransportBlockDialog.showTransportDialog(player, block as com.coderjoe.atlas.transport.TransportBlock, transportBlockRegistry)
}
)

server.pluginManager.registerEvents(
AtlasBlockListener(this, listOf(powerSystem, fluidSystem)),
AtlasBlockListener(this, listOf(powerSystem, fluidSystem, transportSystem)),
this
)

// Auto-save every 5 minutes (6000 ticks)
autoSaveTask = server.scheduler.runTaskTimer(this, Runnable {
powerBlockPersistence.save(powerBlockRegistry)
fluidBlockPersistence.save(fluidBlockRegistry)
transportBlockPersistence.save(transportBlockRegistry)
}, 6000L, 6000L)

logger.atlasInfo("Atlas plugin enabled!")
Expand All @@ -92,8 +111,13 @@ class Atlas : JavaPlugin() {
fluidBlockPersistence.save(fluidBlockRegistry)
}

if (::transportBlockPersistence.isInitialized && ::transportBlockRegistry.isInitialized) {
transportBlockPersistence.save(transportBlockRegistry)
}

PowerBlockDialog.cleanup()
FluidBlockDialog.cleanup()
TransportBlockDialog.cleanup()

if (::powerBlockRegistry.isInitialized) {
powerBlockRegistry.stopAll()
Expand All @@ -103,6 +127,10 @@ class Atlas : JavaPlugin() {
fluidBlockRegistry.stopAll()
}

if (::transportBlockRegistry.isInitialized) {
transportBlockRegistry.stopAll()
}

logger.atlasInfo("Atlas plugin has been disabled!")
}

Expand All @@ -124,6 +152,21 @@ class Atlas : JavaPlugin() {
logger.atlasInfo("Fluid system initialized with ${FluidBlockFactory.getRegisteredBlockIds().size} block types")
}

fun initTransportSystem() {
TransportBlockFactory.registerFromDescriptors(transportDescriptors().values)
transportBlockRegistry = TransportBlockRegistry(this)
transportBlockPersistence = TransportBlockPersistence(this)
transportBlockPersistence.load(transportBlockRegistry)

logger.atlasInfo("Transport system initialized with ${TransportBlockFactory.getRegisteredBlockIds().size} block types")
}

private fun transportDescriptors(): Map<String, com.coderjoe.atlas.core.BlockDescriptor> {
return listOf(
com.coderjoe.atlas.transport.block.ConveyorBelt.descriptor
).associateBy { it.baseBlockId }
}

private fun powerDescriptors(): Map<String, com.coderjoe.atlas.core.BlockDescriptor> {
return listOf(
com.coderjoe.atlas.power.block.SmallSolarPanel.descriptor,
Expand Down
23 changes: 23 additions & 0 deletions src/main/kotlin/com/coderjoe/atlas/NexoIntegration.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class NexoIntegration(private val plugin: JavaPlugin) {
fun initialize() {
copyItemConfigurations()
copyTextures()
copyModels()
copyRecipes()
plugin.logger.atlasInfo("Atlas Nexo integration initialized")
}
Expand Down Expand Up @@ -78,6 +79,28 @@ class NexoIntegration(private val plugin: JavaPlugin) {
}
}

private fun copyModels() {
val modelsFolder = File(nexoFolder, "pack/assets/atlas/models/block")
if (!modelsFolder.exists()) {
modelsFolder.mkdirs()
}

val prefix = "nexo/pack/assets/atlas/models/block/"
val modelPaths = discoverResources(prefix, ".json")

for (resourcePath in modelPaths) {
val fileName = resourcePath.substringAfterLast("/")
val modelFile = File(modelsFolder, fileName)
plugin.saveResource(resourcePath, true)
val sourceFile = File(plugin.dataFolder, resourcePath)
if (sourceFile.exists()) {
sourceFile.copyTo(modelFile, overwrite = true)
sourceFile.delete()
plugin.logger.atlasInfo("Copied ${fileName.removeSuffix(".json")} model to Nexo")
}
}
}

private fun copyRecipes() {
val recipesFolder = File(nexoFolder, "recipes/shapeless")
if (!recipesFolder.exists()) {
Expand Down
13 changes: 11 additions & 2 deletions src/main/kotlin/com/coderjoe/atlas/core/AtlasBlockListener.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class AtlasBlockListener(
createAndRegister(system, blockId, location, facing)
}
PlacementType.DIRECTIONAL -> {
val facing = getPlayerFacing(event)
val facing = getDirectionalFacing(event, descriptor)
val variantId = descriptor.directionalVariants[facing] ?: return
val location = event.block.location.clone()
plugin.server.scheduler.runTask(plugin, Runnable {
Expand All @@ -70,7 +70,7 @@ class AtlasBlockListener(
})
}
PlacementType.DIRECTIONAL_OPPOSITE -> {
val facing = getPlayerFacing(event).oppositeFace
val facing = getDirectionalFacing(event, descriptor, opposite = true)
val variantId = descriptor.directionalVariants[facing] ?: blockId
val location = event.block.location.clone()
plugin.server.scheduler.runTask(plugin, Runnable {
Expand Down Expand Up @@ -146,6 +146,15 @@ class AtlasBlockListener(
}

companion object {
fun getDirectionalFacing(event: BlockPlaceEvent, descriptor: BlockDescriptor, opposite: Boolean = false): BlockFace {
val raw = getPlayerFacing(event)
val facing = if (opposite) raw.oppositeFace else raw
if (descriptor.directionalVariants.containsKey(facing)) return facing
// Fall back to the player's horizontal look direction
val fallback = event.player.facing
return if (opposite) fallback.oppositeFace else fallback
}

fun getPlayerFacing(event: BlockPlaceEvent): BlockFace {
val against = event.blockAgainst.location
val placed = event.block.location
Expand Down
20 changes: 20 additions & 0 deletions src/main/kotlin/com/coderjoe/atlas/transport/TransportBlock.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.coderjoe.atlas.transport

import com.coderjoe.atlas.core.AtlasBlock
import com.coderjoe.atlas.core.BlockRegistry
import org.bukkit.Location

abstract class TransportBlock(
location: Location
) : AtlasBlock(location) {

protected abstract fun transportUpdate()

override fun blockUpdate() {
transportUpdate()
}

override fun getRegistry(): BlockRegistry<*> {
return TransportBlockRegistry.instance ?: throw IllegalStateException("TransportBlockRegistry not initialized")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.coderjoe.atlas.transport

import com.coderjoe.atlas.core.AtlasBlockDialog
import com.coderjoe.atlas.core.BlockRegistry
import com.coderjoe.atlas.transport.block.ConveyorBelt
import io.papermc.paper.dialog.Dialog
import io.papermc.paper.registry.data.dialog.ActionButton
import io.papermc.paper.registry.data.dialog.DialogBase
import io.papermc.paper.registry.data.dialog.action.DialogAction
import io.papermc.paper.registry.data.dialog.action.DialogActionCallback
import io.papermc.paper.registry.data.dialog.body.DialogBody
import io.papermc.paper.registry.data.dialog.type.DialogType
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.event.ClickCallback
import net.kyori.adventure.text.format.NamedTextColor
import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin

object TransportBlockDialog {

fun init(plugin: JavaPlugin) {
AtlasBlockDialog.init(plugin)
}

fun showTransportDialog(player: Player, block: TransportBlock, registry: BlockRegistry<*>) {
AtlasBlockDialog.showDialog(player, block, registry) { p, b, onClose ->
sendDialog(p, b as TransportBlock, onClose)
}
}

fun cleanup() {
AtlasBlockDialog.cleanup()
}

private fun sendDialog(player: Player, block: TransportBlock, onClose: (Player) -> Unit) {
val title = Component.text(getBlockDisplayName(block))
val bodyText = getBlockDescription(block)
val body = DialogBody.plainMessage(bodyText)

val closeAction = DialogAction.customClick(
DialogActionCallback { _, audience ->
val p = audience as? Player ?: return@DialogActionCallback
onClose(p)
},
ClickCallback.Options.builder().build()
)

val closeButton = ActionButton.builder(Component.text("Close"))
.action(closeAction)
.build()

val dialog = Dialog.create { factory ->
factory.empty()
.base(
DialogBase.builder(title)
.body(listOf(body))
.canCloseWithEscape(false)
.afterAction(DialogBase.DialogAfterAction.CLOSE)
.build()
)
.type(DialogType.notice(closeButton))
}

player.showDialog(dialog)
}

private fun getBlockDisplayName(block: TransportBlock): String = when (block) {
is ConveyorBelt -> "Conveyor Belt (${block.facing.name.lowercase().replaceFirstChar { it.uppercase() }})"
else -> "Transport Block"
}

private fun getBlockDescription(block: TransportBlock): Component = when (block) {
is ConveyorBelt -> Component.text("Moves items forward 1 block every second")
.color(NamedTextColor.GRAY)
else -> Component.text("Transport block")
.color(NamedTextColor.GRAY)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.coderjoe.atlas.transport

import com.coderjoe.atlas.core.BlockFactory
import org.bukkit.Location
import org.bukkit.block.BlockFace

object TransportBlockFactory : BlockFactory<TransportBlock>() {

fun createTransportBlock(blockId: String, location: Location, facing: BlockFace = BlockFace.SELF): TransportBlock? {
return create(blockId, location, facing)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.coderjoe.atlas.transport

import com.coderjoe.atlas.core.BlockPersistence
import org.bukkit.plugin.java.JavaPlugin

class TransportBlockPersistence(plugin: JavaPlugin) {
private val persistence = BlockPersistence<TransportBlock>(
plugin = plugin,
fileName = "transport_blocks.yml",
yamlKey = "transport_blocks",
factory = TransportBlockFactory,
serialize = { _, _ -> emptyMap() },
restore = { _, _ -> }
)

fun save(registry: TransportBlockRegistry) = persistence.save(registry)
fun load(registry: TransportBlockRegistry) = persistence.load(registry)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.coderjoe.atlas.transport

import com.coderjoe.atlas.core.BlockRegistry
import org.bukkit.Location
import org.bukkit.block.BlockFace
import org.bukkit.plugin.java.JavaPlugin

class TransportBlockRegistry(plugin: JavaPlugin) : BlockRegistry<TransportBlock>(plugin) {

companion object {
var instance: TransportBlockRegistry? = null
private set

fun locationKey(location: Location): String = BlockRegistry.locationKey(location)
}

init {
instance = this
}

fun registerTransportBlock(block: TransportBlock, blockId: String) = register(block, blockId)

fun unregisterTransportBlock(location: Location): TransportBlock? = unregister(location)

fun getTransportBlock(location: Location): TransportBlock? = getBlock(location)

fun getAdjacentTransportBlock(location: Location, face: BlockFace): TransportBlock? = getAdjacentBlock(location, face)

fun getAllTransportBlocksWithIds(): List<Pair<TransportBlock, String>> = getAllBlocksWithIds()
}
Loading
Loading