Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
775088d
feat: extendable & additional multiblock demo
Gebardensprache Jun 15, 2026
8e79f5b
Merge branch 'GregTechLite:main' into og/extendable_multi
Gebardensprache Jun 15, 2026
689319e
clean up some syntax & use mutable list but not collection
MagicSweepy Jun 16, 2026
32bea4c
feat: decoupling logic & new connect logic
Gebardensprache Jun 17, 2026
5e84ceb
fix: move to correct dir & interface rewrite
Gebardensprache Jun 17, 2026
9c29340
l10n for machine name in request addition recipe property
MagicSweepy Jun 17, 2026
4860107
connect interaction between AMB and EMB via data stick
MagicSweepy Jun 17, 2026
c351bce
raw recipe logic
MagicSweepy Jun 17, 2026
e2103b0
try to support multi request additional structures
MagicSweepy Jun 18, 2026
8fa0539
multi value support & port pcb to extendable recipe logic
MagicSweepy Jun 18, 2026
5acaac8
some missing overriden in AMB and EMB
MagicSweepy Jun 18, 2026
1352297
render oriented front overlay for AMB
MagicSweepy Jun 18, 2026
7d70c9b
fix unmodifiable operation for abilities of EMB
MagicSweepy Jun 18, 2026
ba4a34a
reimpl working status and persist it
MagicSweepy Jun 18, 2026
96436be
first-step rework PCB factory & shortcut recipe display text
MagicSweepy Jun 18, 2026
38b56e7
parallel and overclocking mechanism for pcb factory
MagicSweepy Jun 18, 2026
56eadd9
fix: nbt data persistence
Gebardensprache Jun 18, 2026
01df015
recipes for new pcb machines
MagicSweepy Jun 18, 2026
0fa0f0b
clean up deprecated pcb factory tooltips
MagicSweepy Jun 18, 2026
8523146
allow water cooling tower has some speed bonus for pcb factory
MagicSweepy Jun 19, 2026
e4b7f31
feat(gui): additional list, highlight (TODO), additional controller m…
Gebardensprache Jun 19, 2026
9aca93b
clean up highlight controller part & support kotlin operator
MagicSweepy Jul 12, 2026
24661ca
clean up deprecated features and add ui hint for pcb factory
MagicSweepy Jul 12, 2026
ea729f0
some overlay adjust
MagicSweepy Jul 12, 2026
929b0ae
fix mainController npe when hint warning text in additional controller
MagicSweepy Jul 12, 2026
ed06efe
persist mainController pos for additions
MagicSweepy Jul 12, 2026
9898e7d
lazy catch connection to give a hook for sync
MagicSweepy Jul 12, 2026
8a843ec
add display text for additional structures
MagicSweepy Jul 12, 2026
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package gregtechlite.gtlitecore.api.capability.logic

import gregtech.api.capability.impl.MultiblockRecipeLogic
import gregtech.api.recipes.Recipe
import gregtechlite.gtlitecore.api.metatileentity.multiblock.extendable.AdditionalStructureManager
import gregtechlite.gtlitecore.api.metatileentity.multiblock.extendable.RecipeMapExtendableMultiblock
import gregtechlite.gtlitecore.api.recipe.property.RequestAdditionalProperty

open class ExtendableMultiblockRecipeLogic<T: RecipeMapExtendableMultiblock<T>>(controller: RecipeMapExtendableMultiblock<T>,
protected val manager: AdditionalStructureManager<T>)
: MultiblockRecipeLogic(controller)
{
override fun checkRecipe(recipe: Recipe): Boolean
= super.checkRecipe(recipe) && checkAdditionalRequirement(recipe)

override fun canProgressRecipe(): Boolean
= super.canProgressRecipe() && (previousRecipe?.let { checkAdditionalRequirement(it) } ?: true)

private fun checkAdditionalRequirement(recipe: Recipe): Boolean
{
if (!recipe.hasProperty(RequestAdditionalProperty)) return true
val requirement = recipe.getProperty(RequestAdditionalProperty, null) ?: return false
return requirement.additionalStructures.all { manager.get(it).isNotEmpty() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
@file:Suppress("UNCHECKED_CAST")
package gregtechlite.gtlitecore.api.metatileentity.multiblock.extendable

import codechicken.lib.render.CCRenderState
import codechicken.lib.render.pipeline.IVertexOperation
import codechicken.lib.vec.Matrix4
import gregtech.api.capability.GregtechDataCodes.WORKING_ENABLED
import gregtech.api.capability.IControllable
import gregtech.api.capability.IDataStickIntractable
import gregtech.api.metatileentity.multiblock.MultiblockWithDisplayBase
import gregtech.api.metatileentity.multiblock.ui.MultiblockUIBuilder
import gregtech.api.util.GTUtility
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.network.PacketBuffer
import net.minecraft.util.ResourceLocation
import net.minecraft.util.math.BlockPos
import net.minecraft.util.text.TextComponentTranslation

abstract class AdditionalMultiblockBase<T : ExtendableMultiblock<T>>(metaTileEntityId: ResourceLocation)
: MultiblockWithDisplayBase(metaTileEntityId), IControllable, IDataStickIntractable
{
@JvmField
protected var mainController: ExtendableMultiblock<T>? = null

@JvmField
protected var isWorkingEnabled: Boolean = false

private var snapshotControllerPos: BlockPos? = null

override fun hasMaintenanceMechanics() = false

override fun isWorkingEnabled() = isStructureFormed && isConnected()

override fun setWorkingEnabled(workingStatus: Boolean)
{
isWorkingEnabled = workingStatus
markDirty()
if (world != null && !world.isRemote)
{
writeCustomData(WORKING_ENABLED) { it.writeBoolean(isWorkingEnabled) }
}
}

protected fun isConnected(): Boolean
{
if (mainController != null) return mainController!!.isWorkingEnabled()
val pendingPos = snapshotControllerPos ?: return false
val mte = GTUtility.getMetaTileEntity(world, pendingPos)
if (mte is ExtendableMultiblock<*>)
{
connect(mte as ExtendableMultiblock<T>)
return mainController?.isWorkingEnabled() ?: false
}
return false
}

fun connect(controller: ExtendableMultiblock<T>?)
{
mainController?.removeAdditional(pos)
mainController = controller
mainController?.addAdditional(this)
snapshotControllerPos = null
}

override fun writeToNBT(data: NBTTagCompound): NBTTagCompound
{
super.writeToNBT(data)
data.setBoolean("isWorkingEnabled", isWorkingEnabled)
mainController?.let { controller ->
val mainPos = NBTTagCompound()
mainPos.setInteger("X", controller.controllerPos.x)
mainPos.setInteger("Y", controller.controllerPos.y)
mainPos.setInteger("Z", controller.controllerPos.z)
data.setTag("MainControllerPos", mainPos)
}
return data
}

override fun readFromNBT(data: NBTTagCompound)
{
super.readFromNBT(data)
setWorkingEnabled(data.getBoolean("isWorkingEnabled"))
if (data.hasKey("MainControllerPos"))
{
val mainPos = data.getCompoundTag("MainControllerPos")
val pos = BlockPos(mainPos.getInteger("X"), mainPos.getInteger("Y"), mainPos.getInteger("Z"))
val mte = GTUtility.getMetaTileEntity(world, pos)
if (mte is ExtendableMultiblock<*>)
{
connect(mte as ExtendableMultiblock<T>)
}
else
{
snapshotControllerPos = pos
}
}
}

override fun writeInitialSyncData(buf: PacketBuffer)
{
super.writeInitialSyncData(buf)
buf.writeBoolean(isWorkingEnabled)
}

override fun receiveInitialSyncData(buf: PacketBuffer)
{
super.receiveInitialSyncData(buf)
setWorkingEnabled(buf.readBoolean())
}

override fun receiveCustomData(dataId: Int, buf: PacketBuffer)
{
super.receiveCustomData(dataId, buf)
if (dataId == WORKING_ENABLED)
{
isWorkingEnabled = buf.readBoolean()
scheduleRenderUpdate()
}
}

override fun configureDisplayText(builder: MultiblockUIBuilder)
{
builder.setWorkingStatus(isWorkingEnabled, isConnected())
.addWorkingStatusLine()
}

override fun configureWarningText(builder: MultiblockUIBuilder)
{
val controller = mainController ?: return
if (controller.isStructureFormed)
{
controller.maintenanceProblem.let { builder.addMaintenanceProblemLines(it, true) }
}
}

override fun onDataStickLeftClick(player: EntityPlayer, stack: ItemStack)
{
val tag = stack.tagCompound ?: NBTTagCompound()
tag.setTag("AdditionalPos", NBTTagCompound().apply {
setInteger("X", pos.x)
setInteger("Y", pos.y)
setInteger("Z", pos.z)
})
stack.tagCompound = tag
stack.setTranslatableName("gtlitecore.machine.additional_structure.data_stick.name")
player.sendStatusMessage(TextComponentTranslation("gtlitecore.machine.additional_structure.pos_saved",
pos.x, pos.y, pos.z), true)
}

override fun onDataStickRightClick(player: EntityPlayer, stack: ItemStack): Boolean = false

override fun renderMetaTileEntity(renderState: CCRenderState,
translation: Matrix4,
pipeline: Array<out IVertexOperation>)
{
super.renderMetaTileEntity(renderState, translation, pipeline)
frontOverlay.renderOrientedState(renderState, translation, pipeline, frontFacing, isActive, isWorkingEnabled)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package gregtechlite.gtlitecore.api.metatileentity.multiblock.extendable

import gregtech.api.metatileentity.MetaTileEntity
import gregtech.api.metatileentity.multiblock.MultiblockAbility
import gregtech.api.util.GTUtility
import gregtechlite.gtlitecore.api.collection.openArrayListOf
import gregtechlite.gtlitecore.api.collection.openHashMapOf
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.nbt.NBTTagList
import net.minecraft.util.ResourceLocation
import net.minecraft.util.math.BlockPos

open class AdditionalStructureManager<T: ExtendableMultiblock<T>>(protected val base: ExtendableMultiblock<T>)
{
protected val structures = openHashMapOf<BlockPos, AdditionalMultiblockBase<T>>()
private val snapshotConnections = openArrayListOf<BlockPos>()

fun add(additionalMultiblockBase: AdditionalMultiblockBase<T>)
{
structures[additionalMultiblockBase.pos] = additionalMultiblockBase
snapshotConnections.remove(additionalMultiblockBase.pos)
}

fun addSnapshotConnection(pos: BlockPos)
{
if (pos !in structures.keys && pos !in snapshotConnections)
snapshotConnections.add(pos)
}

operator fun get(metaTileEntityId: ResourceLocation): MutableList<AdditionalMultiblockBase<T>>
{
tryInsertSnapshotConnections()
return structures.values.filter { it.metaTileEntityId.equals(metaTileEntityId) }.toMutableList()
}

operator fun get(pos: BlockPos): AdditionalMultiblockBase<T>?
{
tryInsertSnapshotConnections()
return structures[pos]
}

fun remove(pos: BlockPos)
{
structures.remove(pos)
snapshotConnections.remove(pos)
}

fun <A> getAbilities(ability: MultiblockAbility<A>): MutableList<A>
{
tryInsertSnapshotConnections()
val abilities = arrayListOf<A>()
structures.values.forEach { it.getAbilities<A>(ability).also { ability -> abilities.addAll(ability) } }
return abilities
}

private fun tryInsertSnapshotConnections()
{
if (snapshotConnections.isEmpty()) return
val world = (base as? MetaTileEntity)?.world ?: return
val snapshot = snapshotConnections.toList()
for (pos in snapshot)
{
val mte = GTUtility.getMetaTileEntity(world, pos)
if (mte is AdditionalMultiblockBase<*>)
{
@Suppress("UNCHECKED_CAST")
(mte as AdditionalMultiblockBase<T>).connect(base)
}
}
}

fun serialize(): NBTTagCompound
{
val nbt = NBTTagCompound()
val list = NBTTagList()
val allPoses = linkedSetOf<BlockPos>()
allPoses.addAll(structures.keys)
allPoses.addAll(snapshotConnections)
allPoses.forEach {
val pos = NBTTagCompound().apply {
setInteger("X", it.x)
setInteger("Y", it.y)
setInteger("Z", it.z)
}
list.appendTag(pos)
}
nbt.setTag("BlockPoses", list)
return nbt
}

fun deserialize(nbt: NBTTagCompound): List<BlockPos>
= nbt.getTagList("BlockPoses", 10).filterIsInstance<NBTTagCompound>()
.map { BlockPos(it.getInteger("X"), it.getInteger("Y"), it.getInteger("Z")) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package gregtechlite.gtlitecore.api.metatileentity.multiblock.extendable

import gregtech.api.capability.IMultiblockController
import net.minecraft.util.math.BlockPos

interface ExtendableMultiblock<T: ExtendableMultiblock<T>>: IMultiblockController
{
var additionalStructureManager: AdditionalStructureManager<T>

val maintenanceProblem: Byte

val controllerPos: BlockPos

fun isWorkingEnabled(): Boolean

fun addAdditional(additionalMultiblockBase: AdditionalMultiblockBase<T>)
{
additionalStructureManager.add(additionalMultiblockBase)
}

fun removeAdditional(pos: BlockPos)
{
additionalStructureManager.remove(pos)
}
}
Loading