Skip to content

Commit a515c26

Browse files
authored
Merge pull request #835 from pylonmc/idra/recipe-rewrite
DIVINIA RATIO COQUINARIA™
2 parents 88ce263 + f1a41d2 commit a515c26

76 files changed

Lines changed: 2545 additions & 866 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

nms/src/main/kotlin/io/github/pylonmc/rebar/nms/NmsAccessorImpl.kt

Lines changed: 124 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,14 @@ import kotlin.math.max
7272
import kotlin.math.min
7373
import com.mojang.datafixers.util.Pair as NmsPair
7474
import net.minecraft.world.entity.EquipmentSlot as NmsEquipmentSlot
75-
75+
import net.minecraft.world.item.ItemStack as NmsItemStack
76+
import net.minecraft.core.component.DataComponentType as NmsDataComponentType
77+
78+
/**
79+
* Documentation is in [NmsAccessor].
80+
*
81+
* @see NmsAccessor
82+
*/
7683
@Suppress("unused")
7784
object NmsAccessorImpl : NmsAccessor {
7885

@@ -337,6 +344,11 @@ object NmsAccessorImpl : NmsAccessor {
337344
}
338345
}
339346

347+
fun getBukkitType(nmsType: NmsDataComponentType<*>): PaperDataComponentType<*, *>? {
348+
val bukkitType = PaperDataComponentType.minecraftToBukkit(nmsType) as? PaperDataComponentType<*, *>
349+
return if (bukkitType !is PaperDataComponentType.Unimplemented<*, *>) bukkitType else null
350+
}
351+
340352
override fun getOverriddenTypes(itemStack: ItemStack): List<DataComponentType> {
341353
val schema = RebarItemSchema.fromStack(itemStack)
342354
val nmsStack = (itemStack as CraftItemStack).handle
@@ -346,10 +358,119 @@ object NmsAccessorImpl : NmsAccessor {
346358
val types = mutableListOf<DataComponentType>()
347359
for (type in nmsTemplate.components.keySet()) {
348360
if (nmsTemplate.get(type) != nmsStack.get(type)) {
349-
types.add(PaperDataComponentType.minecraftToBukkit(type))
361+
types.add(getBukkitType(type) ?: continue)
350362
}
351363
}
364+
return types
365+
}
366+
return nmsStack.componentsPatch.entrySet().mapNotNull { getBukkitType(it.key) }
367+
}
368+
369+
fun <T: Any, NMS: Any> componentMatches(itemStack: NmsItemStack, type: PaperDataComponentType.ValuedImpl<T, NMS>, value: Any?): Boolean {
370+
val nmsType = PaperDataComponentType.bukkitToMinecraft<NMS>(type)
371+
val nmsValue = itemStack.get(nmsType)
372+
if (nmsValue == value) {
373+
return true
374+
} else if (value == null || nmsValue == null) {
375+
return false
352376
}
353-
return nmsStack.componentsPatch.entrySet().map { PaperDataComponentType.minecraftToBukkit(it.key) }
377+
378+
val adaptedValue = type.adapter.fromVanilla(nmsValue)
379+
return adaptedValue == value
380+
}
381+
382+
fun componentMatches(itemStack: NmsItemStack, type: PaperDataComponentType.NonValuedImpl<*, *>, hasValue: Boolean): Boolean {
383+
val nmsType = PaperDataComponentType.bukkitToMinecraft<Unit>(type)
384+
return itemStack.has(nmsType) == hasValue
385+
}
386+
387+
fun <T: Any, NMS: Any> convertNmsValue(type: PaperDataComponentType<T, NMS>, nmsValue: Any): T {
388+
return type.adapter.fromVanilla(nmsValue as NMS)
389+
}
390+
391+
override fun overriddenComponents(itemStack: ItemStack, exact: Boolean): Map<DataComponentType, Any?> {
392+
val nmsComponents = mutableMapOf<NmsDataComponentType<*>, Any?>()
393+
val schema = RebarItemSchema.fromStack(itemStack)
394+
val nmsStack = (itemStack as CraftItemStack).handle
395+
if (schema != null && !exact) {
396+
val template = schema.getOriginalTemplate()
397+
val nmsTemplate = (template as CraftItemStack).handle
398+
for (type in nmsTemplate.components.keySet()) {
399+
val realValue = nmsStack.get(type)
400+
if (nmsTemplate.get(type) != realValue) {
401+
nmsComponents[type] = realValue
402+
}
403+
}
404+
} else {
405+
for (component in nmsStack.componentsPatch.entrySet()) {
406+
nmsComponents[component.key] = component.value.orElse(null)
407+
}
408+
}
409+
410+
val components = mutableMapOf<DataComponentType, Any?>()
411+
for (component in nmsComponents) {
412+
val bukkitType = getBukkitType(component.key) ?: continue
413+
val bukkitValue = component.value?.let { convertNmsValue(bukkitType, it) }
414+
components[bukkitType] = bukkitValue
415+
}
416+
return components
417+
}
418+
419+
override fun hasDefaultComponents(itemStack: ItemStack, components: Set<DataComponentType>): Boolean {
420+
val schema = RebarItemSchema.fromStack(itemStack)
421+
val nmsStack = (itemStack as CraftItemStack).handle
422+
if (schema != null) {
423+
val template = schema.getOriginalTemplate()
424+
val nmsTemplate = (template as CraftItemStack).handle
425+
for (type in components) {
426+
val nmsType = PaperDataComponentType.bukkitToMinecraft<Any>(type)
427+
if (nmsTemplate.get(nmsType) != nmsStack.get(nmsType)) {
428+
return false
429+
}
430+
}
431+
return true
432+
}
433+
return components.none {
434+
val nmsType = PaperDataComponentType.bukkitToMinecraft<Any>(it)
435+
nmsStack.hasNonDefault(nmsType)
436+
}
437+
}
438+
439+
override fun isDefaultComponents(itemStack: ItemStack): Boolean {
440+
val schema = RebarItemSchema.fromStack(itemStack)
441+
val nmsStack = (itemStack as CraftItemStack).handle
442+
if (schema != null) {
443+
val template = schema.getOriginalTemplate()
444+
val nmsTemplate = (template as CraftItemStack).handle
445+
for (type in nmsTemplate.components.keySet()) {
446+
if (nmsTemplate.get(type) != nmsStack.get(type)) {
447+
return false
448+
}
449+
}
450+
return true
451+
}
452+
return nmsStack.componentsPatch.size() == 0
453+
}
454+
455+
override fun componentsMatch(itemStack: ItemStack, components: Map<DataComponentType, Any?>): Boolean {
456+
val nmsStack = (itemStack as CraftItemStack).handle
457+
for (component in components) {
458+
val type = component.key
459+
val value = component.value
460+
val matches = when (type) {
461+
is PaperDataComponentType.NonValuedImpl<*, *> -> componentMatches(nmsStack, type, value != null)
462+
is PaperDataComponentType.ValuedImpl<*, *> -> componentMatches(nmsStack, type, value)
463+
else -> true // should be unreachable
464+
}
465+
if (!matches) {
466+
return false
467+
}
468+
}
469+
return true
470+
}
471+
472+
override fun componentsEqual(itemStack: ItemStack, components: Map<DataComponentType, Any?>): Boolean {
473+
val nmsStack = (itemStack as CraftItemStack).handle
474+
return componentsMatch(itemStack, components) && nmsStack.componentsPatch.size() == components.size
354475
}
355476
}

rebar/src/main/kotlin/io/github/pylonmc/rebar/Rebar.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,16 @@ import io.github.pylonmc.rebar.item.research.Research
3535
import io.github.pylonmc.rebar.logistics.CargoRoutes
3636
import io.github.pylonmc.rebar.metrics.RebarMetrics
3737
import io.github.pylonmc.rebar.recipe.ConfigurableRecipeType
38-
import io.github.pylonmc.rebar.recipe.RebarRecipeListener
39-
import io.github.pylonmc.rebar.recipe.RecipeCompletion
38+
import io.github.pylonmc.rebar.recipe.logic.RebarRecipeListener
39+
import io.github.pylonmc.rebar.recipe.logic.RecipeCompletion
4040
import io.github.pylonmc.rebar.recipe.RecipeType
4141
import io.github.pylonmc.rebar.registry.RebarRegistry
4242
import io.github.pylonmc.rebar.util.delayTicks
4343
import io.github.pylonmc.rebar.item.interfaces.*
4444
import io.github.pylonmc.rebar.nms.NmsAccessor
4545
import io.github.pylonmc.rebar.util.mergeResource
4646
import io.github.pylonmc.rebar.waila.Waila
47-
import io.github.pylonmc.rebar.waila.WailaPlaceholders
47+
import io.github.pylonmc.rebar.integration.WailaPlaceholders
4848
import io.papermc.paper.ServerBuildInfo
4949
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents
5050
import kotlinx.coroutines.CoroutineScope
@@ -371,7 +371,7 @@ object Rebar : JavaPlugin(), RebarAddon {
371371
val start = System.currentTimeMillis()
372372

373373
for (addon in RebarRegistry.ADDONS) {
374-
mergeResource(addon, "researches.yml", "researches/${addon.key.namespace}.yml", false)
374+
mergeResource(addon, Rebar, "researches.yml", "researches/${addon.key.namespace}.yml", false)
375375
}
376376

377377
val researchDir = dataPath.resolve("researches")

rebar/src/main/kotlin/io/github/pylonmc/rebar/block/interfaces/CargoRebarBlock.kt

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,21 @@ import kotlin.collections.iterator
3838
import kotlin.math.min
3939

4040
/**
41-
* Represents a block that can connect to cargo ducts and use them to interface
42-
* with other RebarCargoBlocks.
41+
* If you are looking to allow logistics systems (including cargo) to add/remove items
42+
* from your block, see [LogisticRebarBlock]. This interface is specifically for blocks
43+
* which connect to cargo ducts or directly to other CargoRebarBlocks.
44+
*
45+
* Represents a block that can connect to cargo ducts or directly to other RebarCargoBlocks.
4346
*
4447
* Each face can have one logistic group which cargo ducts (or other RebarCargoBlocks)
4548
* connected to that face are allowed to interface with.
4649
*
47-
* In your place constructor, you will need to call [addCargoLogisticGroup] for all
48-
* the block faces you want to be able to connect cargo ducts to, and also
50+
* In your place constructor, you will need to call [CargoRebarBlock.addCargoLogisticGroup]
51+
* for all the block faces you want to be able to connect cargo ducts to, and also
4952
* `setCargoTransferRate` to set the maximum number of items that can be transferred
5053
* out of this block per cargo tick.
54+
*
55+
* @see LogisticRebarBlock
5156
*/
5257
interface CargoRebarBlock : LogisticRebarBlock, EntityHolderRebarBlock {
5358

@@ -130,6 +135,12 @@ interface CargoRebarBlock : LogisticRebarBlock, EntityHolderRebarBlock {
130135
}
131136
}
132137

138+
/**
139+
* This function will tick each face which has a logistic group by finding the
140+
* block and face which the face connects to (either directly or via cargo ducts)
141+
* and trying to move items from the source faces on this block to their
142+
* corresponding target faces.
143+
*/
133144
@ApiStatus.Internal
134145
fun tickCargo() {
135146
for ((face, group) in cargoBlockData.groups) {
@@ -153,6 +164,11 @@ interface CargoRebarBlock : LogisticRebarBlock, EntityHolderRebarBlock {
153164
}
154165
}
155166

167+
/**
168+
* Attempts to move cargo from [sourceGroup] to [targetGroup]. This assumes that routing
169+
* logic has been performed, we know where items need to be transferred to, and now we
170+
* just need to actually transfer the items.
171+
*/
156172
@ApiStatus.Internal
157173
fun tickCargoFace(sourceGroup: LogisticGroup, targetGroup: LogisticGroup) {
158174
for (sourceSlot in sourceGroup.slots) {

rebar/src/main/kotlin/io/github/pylonmc/rebar/block/interfaces/DirectionalRebarBlock.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import java.util.IdentityHashMap
1616
/**
1717
* Represents a block that has a specific facing direction.
1818
*
19+
* You should set [DirectionalRebarBlock.facing] in your place constructor. The face you set will be persisted over reloads.
20+
*
1921
* Internally only used for rotating [RebarBlock.blockTextureEntity]s.
2022
*/
2123
interface DirectionalRebarBlock : Keyed {

rebar/src/main/kotlin/io/github/pylonmc/rebar/block/interfaces/EntityCulledRebarBlock.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import org.bukkit.Bukkit
66
import org.bukkit.entity.Player
77
import java.util.UUID
88

9+
/**
10+
* TODO docs (JustAHuman)
11+
*/
912
interface EntityCulledRebarBlock : CulledRebarBlock {
1013
/**
1114
* Any entity id's that should be culled when the block is considered culled by the BlockTextureEngine.

rebar/src/main/kotlin/io/github/pylonmc/rebar/block/interfaces/EntityGroupCulledRebarBlock.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import java.util.UUID
1414
* on the display entities (multiple blocks use the same entity), and therefor should
1515
* only cull said entities if all blocks using that entity are culled.
1616
*/
17-
interface EntityGroupCulledRebarBlock : GroupCulledRebarBLock {
17+
interface EntityGroupCulledRebarBlock : GroupCulledRebarBlock {
1818
override val cullingGroups: Iterable<EntityCullingGroup>
1919

2020
override val isCulledAsync: Boolean
@@ -25,7 +25,7 @@ interface EntityGroupCulledRebarBlock : GroupCulledRebarBLock {
2525
return group.entityIds.firstOrNull()?.let { player.isVisibilityInverted(it) } ?: true
2626
}
2727

28-
override fun onGroupVisible(player: Player, group: GroupCulledRebarBLock.CullingGroup) {
28+
override fun onGroupVisible(player: Player, group: GroupCulledRebarBlock.CullingGroup) {
2929
if (group !is EntityCullingGroup) return
3030
for (entityId in group.entityIds) {
3131
if (player.isVisibilityInverted(entityId)) {
@@ -36,7 +36,7 @@ interface EntityGroupCulledRebarBlock : GroupCulledRebarBLock {
3636
}
3737
}
3838

39-
override fun onGroupCulled(player: Player, group: GroupCulledRebarBLock.CullingGroup) {
39+
override fun onGroupCulled(player: Player, group: GroupCulledRebarBlock.CullingGroup) {
4040
if (group !is EntityCullingGroup) return
4141
for (entityId in group.entityIds) {
4242
if (!player.isVisibilityInverted(entityId)) {
@@ -49,7 +49,7 @@ interface EntityGroupCulledRebarBlock : GroupCulledRebarBLock {
4949

5050
class EntityCullingGroup(
5151
id: String,
52-
blocks: MutableSet<GroupCulledRebarBLock> = mutableSetOf(),
52+
blocks: MutableSet<GroupCulledRebarBlock> = mutableSetOf(),
5353
val entityIds: MutableSet<UUID> = mutableSetOf()
54-
) : GroupCulledRebarBLock.CullingGroup(id, blocks)
54+
) : GroupCulledRebarBlock.CullingGroup(id, blocks)
5555
}

rebar/src/main/kotlin/io/github/pylonmc/rebar/block/interfaces/FacadeRebarBlock.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ interface FacadeRebarBlock : InteractRebarBlockHandler {
2020
*/
2121
val block: Block
2222

23-
val facadeDefaultBlockType: Material
24-
2523
@MultiHandler(priorities = [EventPriority.MONITOR])
2624
override fun onInteractedWith(event: PlayerInteractEvent, priority: EventPriority) {
2725
if (!event.action.isRightClick || event.player.isSneaking || event.hand != EquipmentSlot.HAND) {

rebar/src/main/kotlin/io/github/pylonmc/rebar/block/interfaces/FluidBufferRebarBlock.kt

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,20 @@ import kotlin.math.max
1919
*
2020
* In more detail: Usually, fluid machines store fluids in internal 'buffers.'
2121
* For example, the press has an internal buffer used to store plant oil, of
22-
* size 1000mB by default. This is a common enough thing that we created a new
23-
* interface to handle it: RebarFluidBufferBlock. This interface allows your
24-
* block to easily manage fluid buffers.
22+
* size 1000mB by default. This is a common enough thing that we created this
23+
* interface to handle it. This interface allows your block to easily manage
24+
* fluid buffers.
2525
*
26-
* You will need to call `createFluidBuffer` when your block is placed
27-
* and specify the buffer's fluid type, capacity, whether it can take in
28-
* fluids from input points, and whether it can supply fluids to output
29-
* points.
26+
* You will need to call [FluidBufferRebarBlock.createFluidBuffer]
27+
* when your block is placed and specify the buffer's fluid type, capacity,
28+
* whether it can take in fluids from input points, and whether it can supply
29+
* fluids to output points.
3030
*
3131
* You do not need to handle saving buffers or implement any of the
32-
* `RebarFluidBlock` methods for this; this is all done automatically.
32+
* [FluidRebarBlock] methods for this; this is all done automatically.
33+
*
34+
* @see FluidTankRebarBlock
35+
* @see FluidRebarBlock
3336
*/
3437
interface FluidBufferRebarBlock : FluidRebarBlock {
3538
private val fluidBuffers: MutableMap<RebarFluid, FluidBufferData>

rebar/src/main/kotlin/io/github/pylonmc/rebar/block/interfaces/FluidRebarBlock.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import org.bukkit.inventory.ItemStack
1212
import org.jetbrains.annotations.MustBeInvokedByOverriders
1313

1414
/**
15-
* A block that interacts with fluids in some way.
15+
* A block that interacts with the fluid system.
1616
*
1717
* This is a very flexible class which requires you to define exactly how fluid should
1818
* be input and output. You are responsible for keeping track of any state, like how
@@ -25,7 +25,6 @@ import org.jetbrains.annotations.MustBeInvokedByOverriders
2525
*
2626
* Multiple inputs/outputs are not supported. You can have at most 1 input and 1 output.
2727
*
28-
*
2928
* @see FluidBufferRebarBlock
3029
* @see FluidTankRebarBlock
3130
*/

rebar/src/main/kotlin/io/github/pylonmc/rebar/block/interfaces/FluidTankRebarBlock.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ import kotlin.math.max
1818
* time, but can store many types of fluids. `RebarFluidTank` implements this
1919
* pattern.
2020
*
21-
* You must call [setCapacity] for this
22-
* block to work.
21+
* To use this interface, call [FluidTankRebarBlock.setCapacity] in your place
22+
* constructor and implement [isAllowedFluid] to control which fluids can be
23+
* stored in this tank.
2324
*
2425
* As with [FluidBufferRebarBlock], you do not need to handle saving buffers
2526
* or implement any of the [FluidRebarBlock] methods for this; this is all
2627
* done automatically.
2728
*
29+
* @see FluidBufferRebarBlock
30+
* @see FluidRebarBlock
2831
*/
2932
interface FluidTankRebarBlock : FluidRebarBlock {
3033

@@ -61,6 +64,8 @@ interface FluidTankRebarBlock : FluidRebarBlock {
6164
val fluidSpaceRemaining: Double
6265
get() = fluidData.capacity - fluidData.amount
6366

67+
fun isAllowedFluid(fluid: RebarFluid): Boolean
68+
6469
/**
6570
* Sets the type of fluid in the fluid tank.
6671
*/
@@ -135,8 +140,6 @@ interface FluidTankRebarBlock : FluidRebarBlock {
135140
fun removeFluid(amount: Double): Boolean
136141
= setFluid(fluidAmount - amount)
137142

138-
fun isAllowedFluid(fluid: RebarFluid): Boolean
139-
140143
override fun fluidAmountRequested(fluid: RebarFluid): Double{
141144
if (!isAllowedFluid(fluid)) {
142145
return 0.0

0 commit comments

Comments
 (0)