Refactor execution flow (again)
This commit is contained in:
parent
2c2c330db6
commit
a941679197
|
@ -34,8 +34,8 @@ class ManagerBlockEntity: BlockEntity(ASMR.managerEntityType) {
|
|||
it.position = Point(240.0, 0.0)
|
||||
}
|
||||
|
||||
program.startBlock.executionFlow.link(divide)
|
||||
divide.executionFlow.link(print)
|
||||
program.startBlock.link(divide)
|
||||
divide.link(print)
|
||||
}
|
||||
|
||||
fun activate() {
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package net.shadowfacts.asmr.program
|
||||
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
abstract class ExecutableBlock(identifier: Identifier): ProgramBlock(identifier) {
|
||||
|
||||
abstract val executionFlow: ExecutionFlow
|
||||
|
||||
abstract fun execute()
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package net.shadowfacts.asmr.program
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
interface ExecutionFlow {
|
||||
val block: ExecutableBlock
|
||||
|
||||
val next: ExecutableBlock?
|
||||
val prev: ExecutableBlock?
|
||||
}
|
||||
class DirectExecutionFlow(override val block: ExecutableBlock): ExecutionFlow {
|
||||
override var next: ExecutableBlock? = null
|
||||
override var prev: ExecutableBlock? = null
|
||||
|
||||
fun link(next: ExecutableBlock) {
|
||||
this.next = next
|
||||
(next.executionFlow as? DirectExecutionFlow)?.let {
|
||||
it.prev = block
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package net.shadowfacts.asmr.program
|
||||
|
||||
import net.shadowfacts.asmr.program.blocks.StartBlock
|
||||
import net.shadowfacts.asmr.program.execution.ExecutableBlock
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
|
||||
/**
|
||||
|
@ -14,11 +15,11 @@ class Program {
|
|||
val blocks = mutableListOf<ProgramBlock>(startBlock)
|
||||
|
||||
fun execute() {
|
||||
var currentBlock: ExecutableBlock? = startBlock.executionFlow.next
|
||||
var currentBlock: ExecutableBlock? = startBlock.next()
|
||||
while (currentBlock != null) {
|
||||
currentBlock.execute()
|
||||
|
||||
currentBlock = currentBlock.executionFlow.next
|
||||
currentBlock = currentBlock.next()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package net.shadowfacts.asmr.program
|
|||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProgramType<Type> {
|
||||
class ProgramType<Type: Any> {
|
||||
companion object {
|
||||
val INT = ProgramType<Int>()
|
||||
val FLOAT = ProgramType<Float>()
|
||||
|
|
|
@ -3,14 +3,14 @@ package net.shadowfacts.asmr.program.blocks
|
|||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.asmr.ASMR
|
||||
import net.shadowfacts.asmr.program.*
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.asmr.program.execution.SimpleExecutableBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class PrintBlock<Type: Any>(
|
||||
val type: ProgramType<Type>
|
||||
): ExecutableBlock(
|
||||
): SimpleExecutableBlock(
|
||||
Identifier(ASMR.modid, "print")
|
||||
) {
|
||||
|
||||
|
@ -19,8 +19,6 @@ class PrintBlock<Type: Any>(
|
|||
override val inputs: Array<ProgramBlockInput<*>> = arrayOf(input)
|
||||
override val outputs: Array<ProgramBlockOutput<*>> = arrayOf()
|
||||
|
||||
override val executionFlow = DirectExecutionFlow(this)
|
||||
|
||||
override fun execute() {
|
||||
println(input.value)
|
||||
}
|
||||
|
|
|
@ -3,19 +3,18 @@ package net.shadowfacts.asmr.program.blocks
|
|||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.asmr.ASMR
|
||||
import net.shadowfacts.asmr.program.*
|
||||
import net.shadowfacts.asmr.program.execution.SimpleExecutableBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class StartBlock: ExecutableBlock(
|
||||
class StartBlock: SimpleExecutableBlock(
|
||||
Identifier(ASMR.modid, "start")
|
||||
) {
|
||||
|
||||
override val inputs: Array<ProgramBlockInput<*>> = arrayOf()
|
||||
override val outputs: Array<ProgramBlockOutput<*>> = arrayOf()
|
||||
|
||||
override val executionFlow = DirectExecutionFlow(this)
|
||||
|
||||
override fun execute() {
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package net.shadowfacts.asmr.program.blocks.math
|
|||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.asmr.ASMR
|
||||
import net.shadowfacts.asmr.program.*
|
||||
import net.shadowfacts.asmr.program.execution.SimpleExecutableBlock
|
||||
import java.lang.RuntimeException
|
||||
|
||||
/**
|
||||
|
@ -11,7 +12,7 @@ import java.lang.RuntimeException
|
|||
class BinaryOperatorBlock<Type: Any>(
|
||||
val type: ProgramType<Type>,
|
||||
val operation: Operation
|
||||
): ExecutableBlock(
|
||||
): SimpleExecutableBlock(
|
||||
Identifier(ASMR.modid, "binary_operator")
|
||||
) {
|
||||
|
||||
|
@ -29,8 +30,6 @@ class BinaryOperatorBlock<Type: Any>(
|
|||
override val inputs: Array<ProgramBlockInput<*>> = arrayOf(left, right)
|
||||
override val outputs: Array<ProgramBlockOutput<*>> = arrayOf(output)
|
||||
|
||||
override val executionFlow = DirectExecutionFlow(this)
|
||||
|
||||
override fun execute() {
|
||||
if (type == ProgramType.INT) {
|
||||
val left = left.value as Int
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package net.shadowfacts.asmr.program.execution
|
||||
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.asmr.ASMR
|
||||
import net.shadowfacts.asmr.program.ProgramBlock
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
abstract class ExecutableBlock(identifier: Identifier): ProgramBlock(identifier) {
|
||||
|
||||
val incoming = IncomingExecutionFlow(Identifier(ASMR.modid, "incoming"), this)
|
||||
abstract val outgoing: Array<OutgoingExecutionFlow>
|
||||
|
||||
abstract fun execute()
|
||||
|
||||
abstract fun next(): ExecutableBlock?
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package net.shadowfacts.asmr.program.execution
|
||||
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.Language
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class IncomingExecutionFlow(
|
||||
val identifier: Identifier,
|
||||
val block: ExecutableBlock
|
||||
) {
|
||||
|
||||
var source: OutgoingExecutionFlow? = null
|
||||
internal set
|
||||
|
||||
fun link(from: OutgoingExecutionFlow) {
|
||||
from.link(to = this)
|
||||
}
|
||||
|
||||
fun unlink() {
|
||||
source?.unlink()
|
||||
}
|
||||
|
||||
fun translateName(): String {
|
||||
return Language.getInstance().translate("programblock.execution.${identifier.namespace}.${identifier.path}")
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package net.shadowfacts.asmr.program.execution
|
||||
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.Language
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class OutgoingExecutionFlow(
|
||||
val identifier: Identifier,
|
||||
val block: ExecutableBlock
|
||||
) {
|
||||
|
||||
var destination: IncomingExecutionFlow? = null
|
||||
private set
|
||||
|
||||
fun link(to: IncomingExecutionFlow) {
|
||||
destination = to
|
||||
to.source = this
|
||||
}
|
||||
|
||||
fun unlink() {
|
||||
destination?.source = null
|
||||
destination = null
|
||||
}
|
||||
|
||||
fun translateName(): String {
|
||||
return Language.getInstance().translate("programblock.execution.${identifier.namespace}.${identifier.path}")
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package net.shadowfacts.asmr.program.execution
|
||||
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.asmr.ASMR
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
abstract class SimpleExecutableBlock(identifier: Identifier): ExecutableBlock(identifier) {
|
||||
|
||||
val outgoingFlow = OutgoingExecutionFlow(Identifier(ASMR.modid, "outgoing"), this)
|
||||
override val outgoing = arrayOf(outgoingFlow)
|
||||
|
||||
override fun next(): ExecutableBlock? {
|
||||
return outgoingFlow.destination?.block
|
||||
}
|
||||
|
||||
fun link(to: ExecutableBlock) {
|
||||
outgoingFlow.link(to.incoming)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package net.shadowfacts.asmr.ui
|
||||
|
||||
import net.shadowfacts.asmr.program.*
|
||||
import net.shadowfacts.asmr.program.execution.ExecutableBlock
|
||||
import net.shadowfacts.asmr.ui.block.ProgramBlockParamView
|
||||
import net.shadowfacts.asmr.ui.block.ProgramBlockView
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
|
@ -35,13 +36,14 @@ class ProgramCanvasView(val program: Program): View() {
|
|||
|
||||
private fun updateBlockLinks() {
|
||||
for ((startBlock, startView) in blocks) {
|
||||
(startBlock as? ExecutableBlock)?.executionFlow?.next?.let { endBlock ->
|
||||
blocks[endBlock]?.let { endView ->
|
||||
val outgoing = startView.outgoingExeuction!!
|
||||
val incoming = endView.incomingExecution!!
|
||||
|
||||
val start = outgoing.convert(outgoing.bounds.center, to = this)
|
||||
val end = incoming.convert(outgoing.bounds.center, to = this)
|
||||
(startBlock as? ExecutableBlock)?.let { startBlock ->
|
||||
for (outgoing in startBlock.outgoing) {
|
||||
val outgoingView = startView.outgoingViews[outgoing] ?: continue
|
||||
val start = outgoingView.convert(outgoingView.bounds.center, to = this)
|
||||
val incoming = outgoing.destination ?: continue
|
||||
val incomingBlockView = blocks[incoming.block] ?: continue
|
||||
val incomingView = incomingBlockView.incomingView!!
|
||||
val end = incomingView.convert(incomingView.bounds.center, to = this)
|
||||
|
||||
executionFlowStartLinks[startBlock] = start to end
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package net.shadowfacts.asmr.ui.block
|
||||
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.asmr.ASMR
|
||||
import net.shadowfacts.asmr.program.execution.IncomingExecutionFlow
|
||||
import net.shadowfacts.asmr.program.execution.OutgoingExecutionFlow
|
||||
import net.shadowfacts.cacao.util.texture.Texture
|
||||
import net.shadowfacts.cacao.view.TextureView
|
||||
import net.shadowfacts.cacao.view.View
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import java.lang.RuntimeException
|
||||
|
||||
/**
|
||||
* @author shadowfacts
|
||||
*/
|
||||
class ProgramBlockExecutionView(val incoming: IncomingExecutionFlow?, val outgoing: OutgoingExecutionFlow?): View() {
|
||||
|
||||
companion object {
|
||||
val emptyConnection = Texture(Identifier(ASMR.modid, "textures/gui/programmer/program_connections.png"), u = 0, v = 0)
|
||||
val executionConnection = Texture(Identifier(ASMR.modid, "textures/gui/programmer/program_connections.png"), u = 7, v = 0)
|
||||
}
|
||||
|
||||
lateinit var textureView: TextureView
|
||||
|
||||
constructor(incoming: IncomingExecutionFlow?): this(incoming, null)
|
||||
constructor(outgoing: OutgoingExecutionFlow?): this(null, outgoing)
|
||||
|
||||
init {
|
||||
if (incoming == null && outgoing == null) {
|
||||
throw RuntimeException("One of incoming or outgoing must be non-null")
|
||||
}
|
||||
}
|
||||
|
||||
override fun wasAdded() {
|
||||
super.wasAdded()
|
||||
|
||||
textureView = addSubview(TextureView(emptyConnection))
|
||||
updateTexture()
|
||||
|
||||
solver.dsl {
|
||||
textureView.leftAnchor equalTo leftAnchor
|
||||
textureView.rightAnchor equalTo rightAnchor
|
||||
textureView.topAnchor equalTo topAnchor
|
||||
textureView.bottomAnchor equalTo bottomAnchor
|
||||
}
|
||||
}
|
||||
|
||||
fun updateTexture() {
|
||||
val active = if (incoming != null) incoming.source != null else outgoing!!.destination != null
|
||||
textureView.texture = if (active) executionConnection else emptyConnection
|
||||
}
|
||||
|
||||
}
|
|
@ -2,10 +2,11 @@ package net.shadowfacts.asmr.ui.block
|
|||
|
||||
import net.minecraft.util.Identifier
|
||||
import net.shadowfacts.asmr.ASMR
|
||||
import net.shadowfacts.asmr.program.ExecutableBlock
|
||||
import net.shadowfacts.asmr.program.execution.ExecutableBlock
|
||||
import net.shadowfacts.asmr.program.ProgramBlock
|
||||
import net.shadowfacts.asmr.program.ProgramBlockInput
|
||||
import net.shadowfacts.asmr.program.ProgramBlockOutput
|
||||
import net.shadowfacts.asmr.program.execution.OutgoingExecutionFlow
|
||||
import net.shadowfacts.cacao.geometry.Axis
|
||||
import net.shadowfacts.cacao.geometry.Point
|
||||
import net.shadowfacts.cacao.util.Color
|
||||
|
@ -13,7 +14,6 @@ import net.shadowfacts.cacao.util.MouseButton
|
|||
import net.shadowfacts.cacao.util.texture.Texture
|
||||
import net.shadowfacts.cacao.view.Label
|
||||
import net.shadowfacts.cacao.view.StackView
|
||||
import net.shadowfacts.cacao.view.TextureView
|
||||
import net.shadowfacts.cacao.view.View
|
||||
import net.shadowfacts.kiwidsl.dsl
|
||||
import no.birkett.kiwi.Constraint
|
||||
|
@ -30,8 +30,8 @@ class ProgramBlockView(val block: ProgramBlock): StackView(Axis.VERTICAL, Distri
|
|||
val parameterConnection = Texture(Identifier(ASMR.modid, "textures/gui/programmer/program_connections.png"), u = 14, v = 0)
|
||||
}
|
||||
|
||||
var incomingExecution: View? = null
|
||||
var outgoingExeuction: View? = null
|
||||
var incomingView: ProgramBlockExecutionView? = null
|
||||
val outgoingViews = mutableMapOf<OutgoingExecutionFlow, ProgramBlockExecutionView>()
|
||||
|
||||
val inputViews = mutableMapOf<ProgramBlockInput<*>, ProgramBlockParamView>()
|
||||
val outputViews = mutableMapOf<ProgramBlockOutput<*>, ProgramBlockParamView>()
|
||||
|
@ -49,23 +49,33 @@ class ProgramBlockView(val block: ProgramBlock): StackView(Axis.VERTICAL, Distri
|
|||
zIndex = 10.0
|
||||
|
||||
val titleStack = addArrangedSubview(StackView(Axis.HORIZONTAL, Distribution.CENTER))
|
||||
val title = titleStack.addArrangedSubview(Label(block.translateName(), wrappingMode = Label.WrappingMode.NO_WRAP))
|
||||
if (block is ExecutableBlock) {
|
||||
val incomingTexture = if (block.executionFlow.prev == null) emptyConnection else executionConnection
|
||||
incomingExecution = titleStack.addArrangedSubview(TextureView(incomingTexture), index = 0)
|
||||
val outgoingTexture = if (block.executionFlow.next == null) emptyConnection else executionConnection
|
||||
outgoingExeuction = titleStack.addArrangedSubview(TextureView(outgoingTexture))
|
||||
incomingView = titleStack.addArrangedSubview(ProgramBlockExecutionView(block.incoming))
|
||||
}
|
||||
val title = titleStack.addArrangedSubview(Label(block.translateName(), wrappingMode = Label.WrappingMode.NO_WRAP))
|
||||
|
||||
solver.dsl {
|
||||
// we have to constrain the titleStack height, because it's distribution is set to CENTER, so it doesn't do it itself
|
||||
titleStack.heightAnchor equalTo title.heightAnchor
|
||||
|
||||
if (block is ExecutableBlock) {
|
||||
incomingExecution!!.widthAnchor equalTo incomingExecution!!.heightAnchor
|
||||
incomingExecution!!.widthAnchor equalTo 7
|
||||
outgoingExeuction!!.widthAnchor equalTo outgoingExeuction!!.heightAnchor
|
||||
outgoingExeuction!!.widthAnchor equalTo 7
|
||||
incomingView!!.widthAnchor equalTo incomingView!!.heightAnchor
|
||||
incomingView!!.widthAnchor equalTo 7
|
||||
}
|
||||
}
|
||||
|
||||
if (block is ExecutableBlock) {
|
||||
for (outgoing in block.outgoing) {
|
||||
val hStack = addArrangedSubview(StackView(Axis.HORIZONTAL, Distribution.CENTER))
|
||||
val outgoingLabel = hStack.addArrangedSubview(Label(outgoing.translateName(), textAlignment = Label.TextAlignment.RIGHT))
|
||||
val outgoingView = hStack.addArrangedSubview(ProgramBlockExecutionView(outgoing))
|
||||
outgoingViews[outgoing] = outgoingView
|
||||
solver.dsl {
|
||||
hStack.heightAnchor equalTo outgoingLabel.heightAnchor
|
||||
|
||||
outgoingView.widthAnchor equalTo outgoingView.heightAnchor
|
||||
outgoingView.widthAnchor equalTo 7
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,8 +83,6 @@ class ProgramBlockView(val block: ProgramBlock): StackView(Axis.VERTICAL, Distri
|
|||
val hStack = addArrangedSubview(StackView(Axis.HORIZONTAL, Distribution.CENTER))
|
||||
|
||||
block.inputs.getOrNull(i)?.let { input ->
|
||||
// val inputTexture = if (input.source == null) emptyConnection else parameterConnection
|
||||
// val inputView = hStack.addArrangedSubview(TextureView(inputTexture))
|
||||
val inputView = hStack.addArrangedSubview(ProgramBlockParamView(input))
|
||||
inputViews[input] = inputView
|
||||
val inputLabel = hStack.addArrangedSubview(Label(input.translateName()))
|
||||
|
@ -93,8 +101,6 @@ class ProgramBlockView(val block: ProgramBlock): StackView(Axis.VERTICAL, Distri
|
|||
|
||||
block.outputs.getOrNull(i)?.let { output ->
|
||||
val outputLabel = hStack.addArrangedSubview(Label(output.translateName(), textAlignment = Label.TextAlignment.RIGHT))
|
||||
// val outputTexture = if (output.destinations.isEmpty()) emptyConnection else parameterConnection
|
||||
// val outputView = hStack.addArrangedSubview(TextureView(outputTexture))
|
||||
val outputView = hStack.addArrangedSubview(ProgramBlockParamView(output))
|
||||
outputViews[output] = outputView
|
||||
solver.dsl {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
{
|
||||
"programblock.execution.asmr.incoming": "Incoming",
|
||||
"programblock.execution.asmr.outgoing": "Outgoing",
|
||||
"programblock.asmr.start": "Start",
|
||||
"programblock.asmr.constant": "Constant",
|
||||
"programblock.param.asmr.constant.output": "Output",
|
||||
|
|
|
@ -20,7 +20,7 @@ class ProgramTests {
|
|||
it.right.link(from = two.output)
|
||||
}
|
||||
|
||||
program.startBlock.executionFlow.link(multiply)
|
||||
program.startBlock.link(multiply)
|
||||
|
||||
program.execute()
|
||||
|
||||
|
|
Loading…
Reference in New Issue