Skip to content

Commit e7250ff

Browse files
committed
handling for blocks that place with a unique item and blocks that transform type after placement. Potted blocks and bamboo for example.
1 parent 81998b6 commit e7250ff

File tree

11 files changed

+156
-64
lines changed

11 files changed

+156
-64
lines changed

src/main/kotlin/com/lambda/interaction/construction/processing/ProcessorRegistry.kt

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,20 @@
1818
package com.lambda.interaction.construction.processing
1919

2020
import com.lambda.core.Loadable
21+
import com.lambda.interaction.construction.processing.ProcessorRegistry.IntermediaryInfo.Companion.intermediaryInfo
2122
import com.lambda.interaction.construction.verify.TargetState
23+
import com.lambda.util.BlockUtils
24+
import com.lambda.util.BlockUtils.item
2225
import com.lambda.util.reflections.getInstances
26+
import net.minecraft.block.Block
2327
import net.minecraft.block.BlockState
28+
import net.minecraft.block.Blocks
29+
import net.minecraft.block.FlowerPotBlock
30+
import net.minecraft.item.Item
31+
import net.minecraft.item.Items
2432
import net.minecraft.state.property.Properties
2533
import net.minecraft.util.math.BlockPos
34+
import net.minecraft.util.math.Direction
2635
import java.util.*
2736

2837
object ProcessorRegistry : Loadable {
@@ -108,6 +117,22 @@ object ProcessorRegistry : Loadable {
108117
Properties.DISTANCE_1_7
109118
)
110119

120+
/**
121+
* Map of blocks that get placed as a different [Block] type, to then be updated afterward. Bamboo and potted flowers are
122+
* two examples.
123+
*
124+
* @see IntermediaryInfo
125+
*/
126+
val intermediaryBlockMap = buildMap<Block, IntermediaryInfo> {
127+
this[Blocks.BAMBOO] = intermediaryInfo(IntermediaryProcess(Blocks.BAMBOO_SAPLING, item = Items.BAMBOO))
128+
BlockUtils.pottedBlocks.forEach {
129+
this[it] = intermediaryInfo(
130+
IntermediaryProcess(Blocks.FLOWER_POT, item = Items.FLOWER_POT),
131+
IntermediaryProcess(Blocks.FLOWER_POT, it, (it as FlowerPotBlock).content.item)
132+
)
133+
}
134+
}
135+
111136
override fun load() = "Loaded ${processors.size} pre processors"
112137

113138
/**
@@ -134,4 +159,40 @@ object ProcessorRegistry : Loadable {
134159
}
135160
processorCache.getOrPut(blockState, get)
136161
}
162+
163+
/**
164+
* Contains the starting initial block placement and any subsequent intermediary processes to transform the placement
165+
* into the final block.
166+
*
167+
* @see IntermediaryProcess
168+
*/
169+
data class IntermediaryInfo private constructor(
170+
val startBlock: IntermediaryProcess,
171+
val intermediaryProcesses: List<IntermediaryProcess> = emptyList(),
172+
) {
173+
fun getIntermediaryProcess(state: BlockState) = intermediaryProcesses.firstOrNull { it.block === state.block }
174+
fun isIntermediaryBlock(state: BlockState) = intermediaryProcesses.any {
175+
it.block === state.block || it.targetBlock === state.block
176+
} || startBlock.targetBlock === state.block
177+
178+
companion object {
179+
fun intermediaryInfo(
180+
startingBlock: IntermediaryProcess,
181+
vararg intermediaryProcesses: IntermediaryProcess
182+
) = IntermediaryInfo(startingBlock, intermediaryProcesses.toList())
183+
}
184+
}
185+
186+
/**
187+
* Holds the required information for placing a [Block] with more than one placement to achieve its target.
188+
*
189+
* The use of [Block] instead of [BlockState] here is intentional as we would only have to alter the [Properties]s
190+
* if the placement was the correct [BlockState]. This is only used when one [Block] needs to transform into another.
191+
*/
192+
data class IntermediaryProcess(
193+
val block: Block,
194+
val targetBlock: Block = block,
195+
val item: Item,
196+
val sides: Set<Direction> = Direction.entries.toSet()
197+
)
137198
}

src/main/kotlin/com/lambda/interaction/construction/processing/preprocessors/OmitPreProcessor.kt

Lines changed: 0 additions & 39 deletions
This file was deleted.

src/main/kotlin/com/lambda/interaction/construction/simulation/BuildSimulator.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,7 @@ object BuildSimulator : Sim<PostSimResult>() {
5656
structure.forEach { (pos, targetState) ->
5757
launch {
5858
sim(pos, blockState(pos), targetState, pov, concurrentSet) {
59-
if (targetState is TargetState.State &&
60-
targetState.matches(state, pos, preProcessing.ignore)
61-
) {
59+
if (targetState is TargetState.State && matchesTarget(complete = false)) {
6260
simPostProcessing()
6361
return@sim
6462
}

src/main/kotlin/com/lambda/interaction/construction/simulation/ISimInfo.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.lambda.context.Automated
2121
import com.lambda.context.AutomatedSafeContext
2222
import com.lambda.interaction.construction.processing.PreProcessingInfo
2323
import com.lambda.interaction.construction.processing.ProcessorRegistry.getProcessingInfo
24+
import com.lambda.interaction.construction.processing.ProcessorRegistry.intermediaryBlockMap
2425
import com.lambda.interaction.construction.result.BuildResult
2526
import com.lambda.interaction.construction.simulation.checks.BasicChecker.hasBasicRequirements
2627
import com.lambda.interaction.construction.verify.TargetState
@@ -42,6 +43,17 @@ interface ISimInfo : Automated {
4243
val concurrentResults: MutableSet<BuildResult>
4344
val dependencyStack: Stack<Sim<*>>
4445

46+
fun AutomatedSafeContext.matchesTarget(state: BlockState = this@ISimInfo.state, complete: Boolean = true): Boolean {
47+
if (targetState.matches(state, pos, if (!complete) preProcessing.ignore else emptySet())) return true
48+
else if (complete) return false
49+
50+
intermediaryBlockMap[targetState.getState(pos, state).block]?.let { intermediaryInfo ->
51+
return intermediaryInfo.isIntermediaryBlock(state)
52+
}
53+
54+
return false
55+
}
56+
4557
companion object {
4658
/**
4759
* Creates a [SimInfo], checks its basic requirements, and runs the [simBuilder] block.

src/main/kotlin/com/lambda/interaction/construction/simulation/checks/BreakSim.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class BreakSim private constructor(simInfo: ISimInfo)
9090
return
9191
}
9292

93-
if (targetState.getState(pos).isAir && !state.fluidState.isEmpty && state.isReplaceable) {
93+
if (targetState.getState(pos, state).isAir && !state.fluidState.isEmpty && state.isReplaceable) {
9494
result(BreakResult.Submerge(pos, state))
9595
sim(pos, state, TargetState.Solid(emptySet())) { simPlacement() }
9696
return

src/main/kotlin/com/lambda/interaction/construction/simulation/checks/PlaceSim.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,11 @@ class PlaceSim private constructor(simInfo: ISimInfo)
123123

124124
val validHits = scanShape(pov, shape, pos, setOf(side), preProcessing) ?: return
125125

126-
selectHitPos(validHits, fakePlayer, targetState.getStack(pos).blockItem, supervisorScope)
126+
selectHitPos(validHits, fakePlayer, targetState.getStack(this@PlaceSim.pos, state).blockItem, supervisorScope)
127127
}
128128

129129
private fun AutomatedSafeContext.getSwapStack(): ItemStack? {
130-
val optimalStack = targetState.getStack(pos)
130+
val optimalStack = targetState.getStack(pos, state)
131131
val stackSelection = optimalStack.item.select()
132132
val containerSelection = selectContainer { ofAnyType(MaterialContainer.Rank.Hotbar) }
133133
val container = stackSelection.containerWithMaterial(containerSelection).firstOrNull() ?: run {
@@ -244,7 +244,7 @@ class PlaceSim private constructor(simInfo: ISimInfo)
244244
return PlaceTest(state, PlaceTestResult.BlockedByEntity)
245245
}
246246

247-
return if (!targetState.matches(resultState, pos, preProcessing.ignore)) {
247+
return if (!matchesTarget(resultState, false)) {
248248
result(PlaceResult.NoIntegrity(pos, resultState, context, (targetState as? TargetState.State)?.blockState))
249249
PlaceTest(resultState, PlaceTestResult.NoIntegrity)
250250
} else PlaceTest(resultState, PlaceTestResult.Success)

src/main/kotlin/com/lambda/interaction/construction/simulation/checks/PostProcessingSim.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.lambda.interaction.construction.simulation.checks
1919

2020
import com.lambda.context.AutomatedSafeContext
2121
import com.lambda.interaction.construction.context.InteractContext
22+
import com.lambda.interaction.construction.processing.ProcessorRegistry.intermediaryBlockMap
2223
import com.lambda.interaction.construction.result.BuildResult
2324
import com.lambda.interaction.construction.result.results.GenericResult
2425
import com.lambda.interaction.construction.result.results.InteractResult
@@ -65,6 +66,17 @@ class PostProcessingSim private constructor(simInfo: ISimInfo)
6566
private suspend fun AutomatedSafeContext.simPostProcessing() {
6667
val targetState = (targetState as? TargetState.State) ?: return
6768

69+
intermediaryBlockMap[targetState.getState(pos, state).block]?.let { intermediaryInfo ->
70+
intermediaryInfo.getIntermediaryProcess(state)?.let { intermediaryBlock ->
71+
simInteraction(
72+
intermediaryBlock.targetBlock.defaultState,
73+
intermediaryBlock.sides,
74+
intermediaryBlock.item
75+
)
76+
}
77+
return
78+
}
79+
6880
val mismatchedProperties = state.properties.filter { state.get(it) != targetState.blockState.get(it) }
6981
mismatchedProperties.forEach { property ->
7082
when (property) {

src/main/kotlin/com/lambda/interaction/construction/verify/StateMatcher.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ interface StateMatcher {
3333
): Boolean
3434

3535
context(automatedSafeContext: AutomatedSafeContext)
36-
fun getStack(pos: BlockPos): ItemStack
36+
fun getStack(pos: BlockPos, state: BlockState): ItemStack
3737
context(automatedSafeContext: AutomatedSafeContext)
38-
fun getState(pos: BlockPos): BlockState
38+
fun getState(pos: BlockPos, state: BlockState): BlockState
3939
fun isEmpty(): Boolean
4040
}

src/main/kotlin/com/lambda/interaction/construction/verify/TargetState.kt

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.lambda.interaction.construction.verify
1919

2020
import com.lambda.context.AutomatedSafeContext
2121
import com.lambda.context.SafeContext
22+
import com.lambda.interaction.construction.processing.ProcessorRegistry.intermediaryBlockMap
2223
import com.lambda.interaction.material.container.ContainerManager.findDisposable
2324
import com.lambda.util.BlockUtils.blockState
2425
import com.lambda.util.BlockUtils.emptyState
@@ -51,10 +52,10 @@ sealed class TargetState(val type: Type) : StateMatcher {
5152
) = state.isEmpty
5253

5354
context(_: AutomatedSafeContext)
54-
override fun getStack(pos: BlockPos): ItemStack = ItemStack.EMPTY
55+
override fun getStack(pos: BlockPos, state: BlockState): ItemStack = ItemStack.EMPTY
5556

5657
context(automatedSafeContext: AutomatedSafeContext)
57-
override fun getState(pos: BlockPos) = automatedSafeContext.blockState(pos).emptyState
58+
override fun getState(pos: BlockPos, state: BlockState) = automatedSafeContext.blockState(pos).emptyState
5859

5960
override fun isEmpty() = true
6061
}
@@ -70,10 +71,10 @@ sealed class TargetState(val type: Type) : StateMatcher {
7071
) = state.isAir
7172

7273
context(_: AutomatedSafeContext)
73-
override fun getStack(pos: BlockPos): ItemStack = ItemStack.EMPTY
74+
override fun getStack(pos: BlockPos, state: BlockState): ItemStack = ItemStack.EMPTY
7475

7576
context(_: AutomatedSafeContext)
76-
override fun getState(pos: BlockPos): BlockState = Blocks.AIR.defaultState
77+
override fun getState(pos: BlockPos, state: BlockState): BlockState = Blocks.AIR.defaultState
7778

7879
override fun isEmpty() = true
7980
}
@@ -89,15 +90,15 @@ sealed class TargetState(val type: Type) : StateMatcher {
8990
) = with(safeContext) { state.isSolidBlock(world, pos) && state.block !in replace }
9091

9192
context(automatedSafeContext: AutomatedSafeContext)
92-
override fun getStack(pos: BlockPos) =
93+
override fun getStack(pos: BlockPos, state: BlockState) =
9394
with(automatedSafeContext) {
9495
findDisposable()?.stacks?.firstOrNull {
9596
it.item.block in inventoryConfig.disposables && it.item.block !in replace
9697
} ?: ItemStack(Items.NETHERRACK)
9798
}
9899

99100
context(_: AutomatedSafeContext)
100-
override fun getState(pos: BlockPos): BlockState = getStack(pos).item.block.defaultState
101+
override fun getState(pos: BlockPos, state: BlockState): BlockState = getStack(pos, state).item.block.defaultState
101102

102103
override fun isEmpty() = false
103104
}
@@ -116,15 +117,15 @@ sealed class TargetState(val type: Type) : StateMatcher {
116117
}
117118

118119
context(automatedSafeContext: AutomatedSafeContext)
119-
override fun getStack(pos: BlockPos) =
120+
override fun getStack(pos: BlockPos, state: BlockState) =
120121
with(automatedSafeContext) {
121122
findDisposable()?.stacks?.firstOrNull {
122123
it.item.block in inventoryConfig.disposables
123124
} ?: ItemStack(Items.NETHERRACK)
124125
}
125126

126127
context(_: AutomatedSafeContext)
127-
override fun getState(pos: BlockPos): BlockState = getStack(pos).item.block.defaultState
128+
override fun getState(pos: BlockPos, state: BlockState): BlockState = getStack(pos, state).item.block.defaultState
128129

129130
override fun isEmpty() = false
130131
}
@@ -141,11 +142,12 @@ sealed class TargetState(val type: Type) : StateMatcher {
141142
state.matches(blockState, ignoredProperties)
142143

143144
context(automatedSafeContext: AutomatedSafeContext)
144-
override fun getStack(pos: BlockPos): ItemStack =
145-
blockState.block.getPickStack(automatedSafeContext.world, pos, blockState, true)
145+
override fun getStack(pos: BlockPos, state: BlockState): ItemStack =
146+
intermediaryBlockMap[blockState.block]?.startBlock?.item?.defaultStack
147+
?: blockState.block.getPickStack(automatedSafeContext.world, pos, blockState, true)
146148

147149
context(_: AutomatedSafeContext)
148-
override fun getState(pos: BlockPos): BlockState = blockState
150+
override fun getState(pos: BlockPos, state: BlockState): BlockState = blockState
149151

150152
override fun isEmpty() = blockState.isEmpty
151153
}
@@ -161,11 +163,11 @@ sealed class TargetState(val type: Type) : StateMatcher {
161163
) = state.block == block
162164

163165
context(automatedSafeContext: AutomatedSafeContext)
164-
override fun getStack(pos: BlockPos): ItemStack =
166+
override fun getStack(pos: BlockPos, state: BlockState): ItemStack =
165167
block.getPickStack(automatedSafeContext.world, pos, block.defaultState, true)
166168

167169
context(_: AutomatedSafeContext)
168-
override fun getState(pos: BlockPos): BlockState = block.defaultState
170+
override fun getState(pos: BlockPos, state: BlockState): BlockState = block.defaultState
169171

170172
override fun isEmpty() = block.defaultState.isEmpty
171173
}
@@ -184,11 +186,11 @@ sealed class TargetState(val type: Type) : StateMatcher {
184186
) = state.block == block
185187

186188
context(automatedSafeContext: AutomatedSafeContext)
187-
override fun getStack(pos: BlockPos): ItemStack =
188-
itemStack
189+
override fun getStack(pos: BlockPos, state: BlockState): ItemStack =
190+
intermediaryBlockMap[getState(pos, state).block]?.startBlock?.item?.defaultStack ?: itemStack
189191

190192
context(_: AutomatedSafeContext)
191-
override fun getState(pos: BlockPos): BlockState = block.defaultState
193+
override fun getState(pos: BlockPos, state: BlockState): BlockState = block.defaultState
192194

193195
override fun isEmpty() = false
194196
}

src/main/kotlin/com/lambda/module/modules/debug/StateInfo.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ object StateInfo : Module(
4141
.associateBy { it.get(null) as Property<*> }
4242

4343
init {
44+
onEnable {
45+
val crosshair = mc.crosshairTarget ?: return@onEnable
46+
if (crosshair !is BlockHitResult) return@onEnable
47+
info(blockState(crosshair.blockPos).betterToString())
48+
}
49+
4450
listen<KeyboardEvent.Press> { event ->
4551
if (!event.isPressed ||
4652
!event.satisfies(printBind)) return@listen

0 commit comments

Comments
 (0)