Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
366418e
RECIPES VOLUME 1: THE PROPHECY
LordIdra Jun 9, 2026
f092edd
RECIPES VOLUME 2: EMERGENCE
LordIdra Jun 9, 2026
faf3c02
RECIPES VOLUME 3: CONVERSION
JustAHuman-xD Jun 9, 2026
5f31ff0
RECIPES VOLUME 4: TRANSMUTATION
LordIdra Jun 9, 2026
0b7a207
RECIPES VOLUME 5: DOPPELGANGERS
JustAHuman-xD Jun 9, 2026
9c9de3b
RECIPES VOLUME 6: EVOLUTION
LordIdra Jun 9, 2026
a7b8887
Merge branch 'idra/recipe-rewrite' of github.com:pylonmc/rebar into i…
LordIdra Jun 9, 2026
b0faf54
RECIPES VOLUME 7: REPAIR
JustAHuman-xD Jun 9, 2026
58c46a2
RECIPES VOLUME 8: NEW PERSPECTIVES
LordIdra Jun 9, 2026
d955a8a
Merge branch 'idra/recipe-rewrite' of github.com:pylonmc/rebar into i…
LordIdra Jun 9, 2026
506ded6
RECIPES VOLUME 8: REVELATIONS
JustAHuman-xD Jun 9, 2026
9cc2807
RECIPES VOLUME 8.5: COALESCENCE
LordIdra Jun 9, 2026
dc77f67
Merge remote-tracking branch 'origin/idra/recipe-rewrite' into idra/r…
LordIdra Jun 9, 2026
9cdaa9f
RECIPES VOLUME 9: ACCEPTANCE
JustAHuman-xD Jun 9, 2026
c9dadc0
RECIPES VOLUME 9.1: FLEXIBILITY
JustAHuman-xD Jun 9, 2026
197427c
RECIPES VOLUME 10: DEVASTATION
LordIdra Jun 9, 2026
d425f91
RECIPES VOLUME 10.1: THE SHEDDING
JustAHuman-xD Jun 9, 2026
93d9792
RECIPES VOLUME 10.5: WASTELANDS
JustAHuman-xD Jun 10, 2026
a82fb80
Revert "RECIPES VOLUME 10: DEVASTATION"
LordIdra Jun 10, 2026
f332838
RECIPES VOLUME 10.01: INTEMRISSION
LordIdra Jun 10, 2026
5c98bcb
RECIPES VOLUME 11: SERENITY
LordIdra Jun 10, 2026
ab2def0
RECIPES VOLUME 12: ENLIGHTENMENT
JustAHuman-xD Jun 10, 2026
ead6d94
RECIPES VOLUME 13: SERENITY
JustAHuman-xD Jun 10, 2026
6a0744b
docs improvements and stuff
LordIdra Jun 12, 2026
7ad25db
Merge branch 'idra/recipe-rewrite' into idra/docs-improvements-and-stuff
LordIdra Jun 12, 2026
7f6be6c
config adapter improvements
LordIdra Jun 13, 2026
b563fef
PR comments
LordIdra Jun 16, 2026
aea04d3
oh that's why I didn't do it
LordIdra Jun 16, 2026
fea84ce
apistatus internal
LordIdra Jun 16, 2026
414e98d
.of
LordIdra Jun 17, 2026
fbea0e1
fix rebar item javadoc
JustAHuman-xD Jun 17, 2026
9afff70
Merge pull request #841 from pylonmc/idra/docs-improvements-and-stuff
LordIdra Jun 18, 2026
999537b
Merge branch 'master' into idra/recipe-rewrite
JustAHuman-xD Jun 18, 2026
c37a5c0
RECIPES VOLUME 14.01: WAKING
JustAHuman-xD Jun 18, 2026
57c9751
RECIPES VOLUME 14.02: PARALYSIS
JustAHuman-xD Jun 18, 2026
f1a41d2
RECIPES VOLUME 14.03: CURE
JustAHuman-xD Jun 18, 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
127 changes: 124 additions & 3 deletions nms/src/main/kotlin/io/github/pylonmc/rebar/nms/NmsAccessorImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,14 @@ import kotlin.math.max
import kotlin.math.min
import com.mojang.datafixers.util.Pair as NmsPair
import net.minecraft.world.entity.EquipmentSlot as NmsEquipmentSlot

import net.minecraft.world.item.ItemStack as NmsItemStack
import net.minecraft.core.component.DataComponentType as NmsDataComponentType

/**
* Documentation is in [NmsAccessor].
*
* @see NmsAccessor
*/
@Suppress("unused")
object NmsAccessorImpl : NmsAccessor {

Expand Down Expand Up @@ -341,6 +348,11 @@ object NmsAccessorImpl : NmsAccessor {
}
}

fun getBukkitType(nmsType: NmsDataComponentType<*>): PaperDataComponentType<*, *>? {
val bukkitType = PaperDataComponentType.minecraftToBukkit(nmsType) as? PaperDataComponentType<*, *>
return if (bukkitType !is PaperDataComponentType.Unimplemented<*, *>) bukkitType else null
}

override fun getOverriddenTypes(itemStack: ItemStack): List<DataComponentType> {
val schema = RebarItemSchema.fromStack(itemStack)
val nmsStack = (itemStack as CraftItemStack).handle
Expand All @@ -350,10 +362,119 @@ object NmsAccessorImpl : NmsAccessor {
val types = mutableListOf<DataComponentType>()
for (type in nmsTemplate.components.keySet()) {
if (nmsTemplate.get(type) != nmsStack.get(type)) {
types.add(PaperDataComponentType.minecraftToBukkit(type))
types.add(getBukkitType(type) ?: continue)
}
}
return types
}
return nmsStack.componentsPatch.entrySet().mapNotNull { getBukkitType(it.key) }
}

fun <T: Any, NMS: Any> componentMatches(itemStack: NmsItemStack, type: PaperDataComponentType.ValuedImpl<T, NMS>, value: Any?): Boolean {
val nmsType = PaperDataComponentType.bukkitToMinecraft<NMS>(type)
val nmsValue = itemStack.get(nmsType)
if (nmsValue == value) {
return true
} else if (value == null || nmsValue == null) {
return false
}
return nmsStack.componentsPatch.entrySet().map { PaperDataComponentType.minecraftToBukkit(it.key) }

val adaptedValue = type.adapter.fromVanilla(nmsValue)
return adaptedValue == value
}

fun componentMatches(itemStack: NmsItemStack, type: PaperDataComponentType.NonValuedImpl<*, *>, hasValue: Boolean): Boolean {
val nmsType = PaperDataComponentType.bukkitToMinecraft<Unit>(type)
return itemStack.has(nmsType) == hasValue
}

fun <T: Any, NMS: Any> convertNmsValue(type: PaperDataComponentType<T, NMS>, nmsValue: Any): T {
return type.adapter.fromVanilla(nmsValue as NMS)
}

override fun overriddenComponents(itemStack: ItemStack, exact: Boolean): Map<DataComponentType, Any?> {
val nmsComponents = mutableMapOf<NmsDataComponentType<*>, Any?>()
val schema = RebarItemSchema.fromStack(itemStack)
val nmsStack = (itemStack as CraftItemStack).handle
if (schema != null && !exact) {
val template = schema.getOriginalTemplate()
val nmsTemplate = (template as CraftItemStack).handle
for (type in nmsTemplate.components.keySet()) {
val realValue = nmsStack.get(type)
if (nmsTemplate.get(type) != realValue) {
nmsComponents[type] = realValue
}
}
} else {
for (component in nmsStack.componentsPatch.entrySet()) {
nmsComponents[component.key] = component.value.orElse(null)
}
}

val components = mutableMapOf<DataComponentType, Any?>()
for (component in nmsComponents) {
val bukkitType = getBukkitType(component.key) ?: continue
val bukkitValue = component.value?.let { convertNmsValue(bukkitType, it) }
components[bukkitType] = bukkitValue
}
return components
}

override fun hasDefaultComponents(itemStack: ItemStack, components: Set<DataComponentType>): Boolean {
val schema = RebarItemSchema.fromStack(itemStack)
val nmsStack = (itemStack as CraftItemStack).handle
if (schema != null) {
val template = schema.getOriginalTemplate()
val nmsTemplate = (template as CraftItemStack).handle
for (type in components) {
val nmsType = PaperDataComponentType.bukkitToMinecraft<Any>(type)
if (nmsTemplate.get(nmsType) != nmsStack.get(nmsType)) {
return false
}
}
return true
}
return components.none {
val nmsType = PaperDataComponentType.bukkitToMinecraft<Any>(it)
nmsStack.hasNonDefault(nmsType)
}
}

override fun isDefaultComponents(itemStack: ItemStack): Boolean {
val schema = RebarItemSchema.fromStack(itemStack)
val nmsStack = (itemStack as CraftItemStack).handle
if (schema != null) {
val template = schema.getOriginalTemplate()
val nmsTemplate = (template as CraftItemStack).handle
for (type in nmsTemplate.components.keySet()) {
if (nmsTemplate.get(type) != nmsStack.get(type)) {
return false
}
}
return true
}
return nmsStack.componentsPatch.size() == 0
}

override fun componentsMatch(itemStack: ItemStack, components: Map<DataComponentType, Any?>): Boolean {
val nmsStack = (itemStack as CraftItemStack).handle
for (component in components) {
val type = component.key
val value = component.value
val matches = when (type) {
is PaperDataComponentType.NonValuedImpl<*, *> -> componentMatches(nmsStack, type, value != null)
is PaperDataComponentType.ValuedImpl<*, *> -> componentMatches(nmsStack, type, value)
else -> true // should be unreachable
}
if (!matches) {
return false
}
}
return true
}

override fun componentsEqual(itemStack: ItemStack, components: Map<DataComponentType, Any?>): Boolean {
val nmsStack = (itemStack as CraftItemStack).handle
return componentsMatch(itemStack, components) && nmsStack.componentsPatch.size() == components.size
}
}
8 changes: 4 additions & 4 deletions rebar/src/main/kotlin/io/github/pylonmc/rebar/Rebar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ import io.github.pylonmc.rebar.item.research.Research
import io.github.pylonmc.rebar.logistics.CargoRoutes
import io.github.pylonmc.rebar.metrics.RebarMetrics
import io.github.pylonmc.rebar.recipe.ConfigurableRecipeType
import io.github.pylonmc.rebar.recipe.RebarRecipeListener
import io.github.pylonmc.rebar.recipe.RecipeCompletion
import io.github.pylonmc.rebar.recipe.logic.RebarRecipeListener
import io.github.pylonmc.rebar.recipe.logic.RecipeCompletion
import io.github.pylonmc.rebar.recipe.RecipeType
import io.github.pylonmc.rebar.registry.RebarRegistry
import io.github.pylonmc.rebar.util.delayTicks
import io.github.pylonmc.rebar.item.interfaces.*
import io.github.pylonmc.rebar.nms.NmsAccessor
import io.github.pylonmc.rebar.util.mergeResource
import io.github.pylonmc.rebar.waila.Waila
import io.github.pylonmc.rebar.waila.WailaPlaceholders
import io.github.pylonmc.rebar.integration.WailaPlaceholders
import io.papermc.paper.ServerBuildInfo
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -370,7 +370,7 @@ object Rebar : JavaPlugin(), RebarAddon {
val start = System.currentTimeMillis()

for (addon in RebarRegistry.ADDONS) {
mergeResource(addon, "researches.yml", "researches/${addon.key.namespace}.yml", false)
mergeResource(addon, Rebar, "researches.yml", "researches/${addon.key.namespace}.yml", false)
}

val researchDir = dataPath.resolve("researches")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,21 @@ import kotlin.collections.iterator
import kotlin.math.min

/**
* Represents a block that can connect to cargo ducts and use them to interface
* with other RebarCargoBlocks.
* If you are looking to allow logistics systems (including cargo) to add/remove items
* from your block, see [LogisticRebarBlock]. This interface is specifically for blocks
* which connect to cargo ducts or directly to other CargoRebarBlocks.
*
* Represents a block that can connect to cargo ducts or directly to other RebarCargoBlocks.
*
* Each face can have one logistic group which cargo ducts (or other RebarCargoBlocks)
* connected to that face are allowed to interface with.
*
* In your place constructor, you will need to call [addCargoLogisticGroup] for all
* the block faces you want to be able to connect cargo ducts to, and also
* In your place constructor, you will need to call [CargoRebarBlock.addCargoLogisticGroup]
* for all the block faces you want to be able to connect cargo ducts to, and also
* `setCargoTransferRate` to set the maximum number of items that can be transferred
* out of this block per cargo tick.
*
* @see LogisticRebarBlock
*/
interface CargoRebarBlock : LogisticRebarBlock, EntityHolderRebarBlock {

Expand Down Expand Up @@ -130,6 +135,12 @@ interface CargoRebarBlock : LogisticRebarBlock, EntityHolderRebarBlock {
}
}

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

/**
* Attempts to move cargo from [sourceGroup] to [targetGroup]. This assumes that routing
* logic has been performed, we know where items need to be transferred to, and now we
* just need to actually transfer the items.
*/
@ApiStatus.Internal
fun tickCargoFace(sourceGroup: LogisticGroup, targetGroup: LogisticGroup) {
for (sourceSlot in sourceGroup.slots) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import java.util.IdentityHashMap
/**
* Represents a block that has a specific facing direction.
*
* You should set [DirectionalRebarBlock.facing] in your place constructor. The face you set will be persisted over reloads.
*
* Internally only used for rotating [RebarBlock.blockTextureEntity]s.
*/
interface DirectionalRebarBlock : Keyed {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import org.bukkit.Bukkit
import org.bukkit.entity.Player
import java.util.UUID

/**
* TODO docs (JustAHuman)
*/
interface EntityCulledRebarBlock : CulledRebarBlock {
/**
* Any entity id's that should be culled when the block is considered culled by the BlockTextureEngine.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import java.util.UUID
* on the display entities (multiple blocks use the same entity), and therefor should
* only cull said entities if all blocks using that entity are culled.
*/
interface EntityGroupCulledRebarBlock : GroupCulledRebarBLock {
interface EntityGroupCulledRebarBlock : GroupCulledRebarBlock {
override val cullingGroups: Iterable<EntityCullingGroup>

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

override fun onGroupVisible(player: Player, group: GroupCulledRebarBLock.CullingGroup) {
override fun onGroupVisible(player: Player, group: GroupCulledRebarBlock.CullingGroup) {
if (group !is EntityCullingGroup) return
for (entityId in group.entityIds) {
if (player.isVisibilityInverted(entityId)) {
Expand All @@ -36,7 +36,7 @@ interface EntityGroupCulledRebarBlock : GroupCulledRebarBLock {
}
}

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

class EntityCullingGroup(
id: String,
blocks: MutableSet<GroupCulledRebarBLock> = mutableSetOf(),
blocks: MutableSet<GroupCulledRebarBlock> = mutableSetOf(),
val entityIds: MutableSet<UUID> = mutableSetOf()
) : GroupCulledRebarBLock.CullingGroup(id, blocks)
) : GroupCulledRebarBlock.CullingGroup(id, blocks)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ interface FacadeRebarBlock : InteractRebarBlockHandler {
*/
val block: Block

val facadeDefaultBlockType: Material

@MultiHandler(priorities = [EventPriority.MONITOR])
override fun onInteractedWith(event: PlayerInteractEvent, priority: EventPriority) {
if (!event.action.isRightClick || event.player.isSneaking || event.hand != EquipmentSlot.HAND) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@ import kotlin.math.max
*
* In more detail: Usually, fluid machines store fluids in internal 'buffers.'
* For example, the press has an internal buffer used to store plant oil, of
* size 1000mB by default. This is a common enough thing that we created a new
* interface to handle it: RebarFluidBufferBlock. This interface allows your
* block to easily manage fluid buffers.
* size 1000mB by default. This is a common enough thing that we created this
* interface to handle it. This interface allows your block to easily manage
* fluid buffers.
*
* You will need to call `createFluidBuffer` when your block is placed
* and specify the buffer's fluid type, capacity, whether it can take in
* fluids from input points, and whether it can supply fluids to output
* points.
* You will need to call [FluidBufferRebarBlock.createFluidBuffer]
* when your block is placed and specify the buffer's fluid type, capacity,
* whether it can take in fluids from input points, and whether it can supply
* fluids to output points.
*
* You do not need to handle saving buffers or implement any of the
* `RebarFluidBlock` methods for this; this is all done automatically.
* [FluidRebarBlock] methods for this; this is all done automatically.
*
* @see FluidTankRebarBlock
* @see FluidRebarBlock
*/
interface FluidBufferRebarBlock : FluidRebarBlock {
private val fluidBuffers: MutableMap<RebarFluid, FluidBufferData>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import org.bukkit.inventory.ItemStack
import org.jetbrains.annotations.MustBeInvokedByOverriders

/**
* A block that interacts with fluids in some way.
* A block that interacts with the fluid system.
*
* This is a very flexible class which requires you to define exactly how fluid should
* be input and output. You are responsible for keeping track of any state, like how
Expand All @@ -25,7 +25,6 @@ import org.jetbrains.annotations.MustBeInvokedByOverriders
*
* Multiple inputs/outputs are not supported. You can have at most 1 input and 1 output.
*
*
* @see FluidBufferRebarBlock
* @see FluidTankRebarBlock
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ import kotlin.math.max
* time, but can store many types of fluids. `RebarFluidTank` implements this
* pattern.
*
* You must call [setCapacity] for this
* block to work.
* To use this interface, call [FluidTankRebarBlock.setCapacity] in your place
* constructor and implement [isAllowedFluid] to control which fluids can be
* stored in this tank.
*
* As with [FluidBufferRebarBlock], you do not need to handle saving buffers
* or implement any of the [FluidRebarBlock] methods for this; this is all
* done automatically.
*
* @see FluidBufferRebarBlock
* @see FluidRebarBlock
*/
interface FluidTankRebarBlock : FluidRebarBlock {

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

fun isAllowedFluid(fluid: RebarFluid): Boolean

/**
* Sets the type of fluid in the fluid tank.
*/
Expand Down Expand Up @@ -135,8 +140,6 @@ interface FluidTankRebarBlock : FluidRebarBlock {
fun removeFluid(amount: Double): Boolean
= setFluid(fluidAmount - amount)

fun isAllowedFluid(fluid: RebarFluid): Boolean

override fun fluidAmountRequested(fluid: RebarFluid): Double{
if (!isAllowedFluid(fluid)) {
return 0.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ interface GhostBlockHolderRebarBlock : EntityHolderRebarBlock {
}

override fun getWaila(player: Player): WailaDisplay? {
return WailaDisplay(Component.translatable(entity.block.placementMaterial.let { it.itemTranslationKey ?: it.blockTranslationKey } ?: return null))
return WailaDisplay.of(Component.translatable(entity.block.placementMaterial.let { it.itemTranslationKey ?: it.blockTranslationKey } ?: return null))
}

override fun getPickItem(player: Player): ItemStack? {
Expand Down Expand Up @@ -286,7 +286,7 @@ interface GhostBlockHolderRebarBlock : EntityHolderRebarBlock {
}

override fun getWaila(player: Player): WailaDisplay {
return WailaDisplay(entity.itemStack.effectiveName())
return WailaDisplay.of(entity.itemStack.effectiveName())
}

override fun getPickItem(player: Player): ItemStack? {
Expand Down
Loading
Loading