Skip to content

Commit 42f22f9

Browse files
committed
Improve splicing table media refill logic (fix #40, fix #41, fix #44, fix #45)
1 parent 021f78f commit 42f22f9

File tree

5 files changed

+59
-17
lines changed

5 files changed

+59
-17
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
1010

1111
- Added keyboard shortcuts to the Splicing Table, configurable in HexDebug's client config menu.
1212
- The Splicing Table now works with Media Purification from [Hexpose](https://miyucomics.github.io/hexpose) (requires at least build [2e90cf5b](https://github.com/miyucomics/hexpose/commit/2e90cf5babb7677a26ca211bd66ac2777e5518cd), or any version after 1.0.0).
13+
- Added a tag (`hexdebug:splicing_table/media_blacklist`) to prevent an item from being used to refill the Splicing Table's media buffer.
1314

1415
### Fixed
1516

1617
- Fixed an issue where newly placed splicing tables would default to having the first iota selected.
18+
- Fixed several bugs/exploits related to the Splicing Table's media buffer ([#40](https://github.com/object-Object/HexDebug/pull/40), [#41](https://github.com/object-Object/HexDebug/pull/41), [#44](https://github.com/object-Object/HexDebug/pull/44), [#45](https://github.com/object-Object/HexDebug/pull/45)).
1719

1820
## `0.4.0+1.20.1` - 2025-09-21
1921

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package gay.object.hexdebug.api;
2+
3+
import gay.object.hexdebug.HexDebug;
4+
import net.minecraft.core.registries.Registries;
5+
import net.minecraft.tags.TagKey;
6+
import net.minecraft.world.item.Item;
7+
8+
@SuppressWarnings("SameParameterValue")
9+
public final class HexDebugTags {
10+
public static final class Items {
11+
public static final TagKey<Item> SPLICING_TABLE_MEDIA_BLACKLIST = create("splicing_table/media_blacklist");
12+
13+
private static TagKey<Item> create(String name) {
14+
return TagKey.create(Registries.ITEM, HexDebug.id(name));
15+
}
16+
}
17+
}

Common/src/main/kotlin/gay/object/hexdebug/blocks/splicing/SplicingTableBlockEntity.kt

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import at.petrak.hexcasting.api.utils.extractMedia
1818
import at.petrak.hexcasting.api.utils.getInt
1919
import at.petrak.hexcasting.api.utils.getList
2020
import at.petrak.hexcasting.xplat.IXplatAbstractions
21+
import gay.`object`.hexdebug.api.HexDebugTags
2122
import gay.`object`.hexdebug.blocks.base.BaseContainer
2223
import gay.`object`.hexdebug.blocks.base.ContainerDataDelegate
2324
import gay.`object`.hexdebug.blocks.base.ContainerDataLongDelegate
@@ -58,12 +59,16 @@ class SplicingTableBlockEntity(pos: BlockPos, state: BlockState) :
5859

5960
var listStack by SplicingTableItemSlot.LIST.delegate
6061
var clipboardStack by SplicingTableItemSlot.CLIPBOARD.delegate
61-
var mediaStack by SplicingTableItemSlot.MEDIA.delegate
62-
private set
62+
private var mediaStack by SplicingTableItemSlot.MEDIA.delegate
6363
private var staffStack by SplicingTableItemSlot.STAFF.delegate
6464

6565
private val listHolder get() = IXplatAbstractions.INSTANCE.findDataHolder(listStack)
6666
val clipboardHolder get() = IXplatAbstractions.INSTANCE.findDataHolder(clipboardStack)
67+
val mediaHolder get() =
68+
mediaStack
69+
.takeIf { !it.`is`(HexDebugTags.Items.SPLICING_TABLE_MEDIA_BLACKLIST) }
70+
?.let { HexAPI.instance().findMediaHolder(it) }
71+
?.takeIf { it.canProvide() }
6772

6873
private val containerData = SimpleContainerData(SplicingTableDataSlot.size)
6974

@@ -89,6 +94,7 @@ class SplicingTableBlockEntity(pos: BlockPos, state: BlockState) :
8994
private set
9095

9196
private var castingCooldown = 0
97+
private var isCurrentlyCasting = false
9298

9399
val analogOutputSignal get() = if (!listStack.isEmpty) 15 else 0
94100

@@ -346,7 +352,16 @@ class SplicingTableBlockEntity(pos: BlockPos, state: BlockState) :
346352
val env = SplicingTableCastEnv(player, this)
347353
val vm = CastingVM.empty(env)
348354

349-
val clientView = vm.queueExecuteAndWrapIotas(instrs, level)
355+
// prevent refilling while casting
356+
isCurrentlyCasting = true
357+
val clientView = try {
358+
vm.queueExecuteAndWrapIotas(instrs, level)
359+
} finally {
360+
isCurrentlyCasting = false
361+
}
362+
363+
refillMedia()
364+
sync()
350365

351366
if (clientView.resolutionType.success) {
352367
ParticleSpray(blockPos.center, Vec3(0.0, 1.5, 0.0), 0.4, Math.PI / 3, 30)
@@ -413,17 +428,29 @@ class SplicingTableBlockEntity(pos: BlockPos, state: BlockState) :
413428
refillMedia()
414429
}
415430

416-
fun refillMedia() {
417-
val mediaHolder = HexAPI.instance().findMediaHolder(mediaStack) ?: return
418-
while (media < maxMedia) {
419-
val cost = maxMedia - media
431+
private fun refillMedia() {
432+
if (isCurrentlyCasting) return
433+
val mediaHolder = mediaHolder ?: return
434+
435+
// for static media items (eg. dust), extract media from one item at a time
436+
// this is necessary to avoid wasting media while still getting as much as possible out of the stack
437+
val unitCost = HexAPI.instance()
438+
.findMediaHolder(mediaStack.copyWithCount(1))
439+
?.withdrawMedia(-1, true)
440+
?: media
441+
442+
// extract media at most once for each item in the stack
443+
// prevents big looping in case someone thinks they're funny
444+
for (i in 0 until mediaStack.count) {
445+
val cost = min(maxMedia - media, unitCost)
446+
if (cost <= 0) return
420447

421448
// avoid wasting media if the item is too large
422-
if (extractMedia(mediaStack, cost = cost, simulate = true) !in 1..cost) return
449+
if (extractMedia(mediaHolder, cost = cost, simulate = true) !in 1..cost) return
423450

424-
// avoid an infinite loop - stop looping as soon as we stop adding media
451+
// stop looping as soon as we stop adding media
425452
val extracted = extractMedia(mediaHolder, cost = cost)
426-
if (extracted < 1) return
453+
if (extracted <= 1) return // the Inexhaustible Phial thinks it's funny.
427454

428455
media += extracted
429456
}

Common/src/main/kotlin/gay/object/hexdebug/casting/eval/SplicingTableCastEnv.kt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ class SplicingTableCastEnv(
3535

3636
override fun postCast(image: CastingImage) {
3737
super.postCast(image)
38-
table.sync() // TODO: is this necessary?
3938
sound.sound?.let {
4039
world.playSound(null, blockPos, it, SoundSource.PLAYERS, 1f, 1f)
4140
}
@@ -57,15 +56,11 @@ class SplicingTableCastEnv(
5756

5857
// then, pull straight from the item in the media slot
5958
if (costLeft > 0) {
60-
HexAPI.instance().findMediaHolder(table.mediaStack)?.let {
59+
table.mediaHolder?.let {
6160
costLeft -= extractMedia(it, cost = costLeft, simulate = simulate)
6261
}
6362
}
6463

65-
if (!simulate) {
66-
table.refillMedia()
67-
}
68-
6964
return costLeft
7065
}
7166

Common/src/main/kotlin/gay/object/hexdebug/gui/splicing/SplicingTableMenu.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gay.`object`.hexdebug.gui.splicing
22

33
import at.petrak.hexcasting.api.mod.HexTags
44
import at.petrak.hexcasting.api.utils.isMediaItem
5+
import gay.`object`.hexdebug.api.HexDebugTags
56
import gay.`object`.hexdebug.blocks.base.ContainerDataDelegate
67
import gay.`object`.hexdebug.blocks.base.ContainerDataLongDelegate
78
import gay.`object`.hexdebug.blocks.base.ContainerDataSelectionDelegate
@@ -80,7 +81,7 @@ class SplicingTableMenu(
8081
mayPlace = ::isIotaHolder
8182
}
8283
mediaSlot = addTableSlot(SplicingTableItemSlot.MEDIA, 205, 169) {
83-
mayPlace = ::isMediaItem
84+
mayPlace = { isMediaItem(it) && !it.`is`(HexDebugTags.Items.SPLICING_TABLE_MEDIA_BLACKLIST) }
8485
}
8586
staffSlot = addTableSlot(SplicingTableItemSlot.STAFF, -20, 169) {
8687
maxStackSize = 1

0 commit comments

Comments
 (0)