From 4aacb3177547bfd8132866be6c6bb60b89ee33f6 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Mon, 15 Jun 2026 15:29:43 -0400 Subject: [PATCH 1/5] Properly distribute relay media without voiding --- .../talia/hexal/common/blocks/entity/BlockEntityRelay.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt b/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt index 15bd597d..8c5d5be2 100644 --- a/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt +++ b/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt @@ -419,16 +419,21 @@ class BlockEntityRelay(pos: BlockPos, val state: BlockState) : HexBlockEntity(He fun acceptMedia(other: ILinkable, sentMedia: Long) { var remainingMedia = sentMedia + // distribute incoming media to all other linked objects for (mediaAcceptor in mediaExchangers.shuffled()) { if (other == mediaAcceptor) continue - val toSend = mediaAcceptor.canAcceptMedia(root, computedAverageMedia) + val averageMediaWithoutAcceptor = (computedAverageMedia * numMediaExchangers - mediaAcceptor.currentMediaLevel()) / (numMediaExchangers - 1) + val toSend = mediaAcceptor.canAcceptMedia(root, averageMediaWithoutAcceptor) mediaAcceptor.acceptMedia(root, min(toSend, remainingMedia)) remainingMedia -= min(toSend, remainingMedia) if (remainingMedia <= 0) break } + // if there's any media left over, send it back where it came from + if (remainingMedia > 0) + other.acceptMedia(root, remainingMedia) linkablesAcceptedFromThisTick.add(other) } From cdfdf5becd361729416df46fe4d2d8ec31281ce7 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Mon, 15 Jun 2026 17:21:49 -0400 Subject: [PATCH 2/5] Fix relay transfer permissions --- .../hexal/common/blocks/entity/BlockEntityRelay.kt | 2 ++ .../talia/hexal/common/entities/BaseCastingWisp.kt | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt b/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt index 8c5d5be2..57a29681 100644 --- a/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt +++ b/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt @@ -51,6 +51,8 @@ class BlockEntityRelay(pos: BlockPos, val state: BlockState) : HexBlockEntity(He private val nonRelaysLinkedDirectly: LazyILinkableSet = LazyILinkableSet() private var mediaExchangersLinkedDirectly: LazyILinkableSet = LazyILinkableSet() + fun sameNetwork(other: BlockEntityRelay): Boolean = other.relayNetwork == this.relayNetwork + fun setPigment(pigment: FrozenPigment, level: Level) = relayNetwork.setPigment(pigment, level.gameTime) fun serverTick() { diff --git a/Common/src/main/java/ram/talia/hexal/common/entities/BaseCastingWisp.kt b/Common/src/main/java/ram/talia/hexal/common/entities/BaseCastingWisp.kt index 579b8133..a8c6fdb6 100644 --- a/Common/src/main/java/ram/talia/hexal/common/entities/BaseCastingWisp.kt +++ b/Common/src/main/java/ram/talia/hexal/common/entities/BaseCastingWisp.kt @@ -36,6 +36,7 @@ import ram.talia.hexal.api.casting.wisp.triggers.WispTriggerRegistry import ram.talia.hexal.api.mulBounded import ram.talia.hexal.api.nbt.SerialisedIota import ram.talia.hexal.client.sounds.WispCastingSoundInstance +import ram.talia.hexal.common.blocks.entity.BlockEntityRelay import ram.talia.hexal.common.lib.HexalSounds import ram.talia.hexal.common.network.MsgWispCastSoundS2C import ram.talia.hexal.xplat.IXplatAbstractions @@ -270,8 +271,16 @@ abstract class BaseCastingWisp(entityType: EntityType, worl fun blackListContains(other: ILinkable): Boolean = blackListTransferMedia.contains(other) fun whiteListContains(other: ILinkable): Boolean = whiteListTransferMedia.contains(other) - private fun shouldBlockTransfer(other: ILinkable): Boolean - = blackListTransferMedia.contains(other) || (other.owner() != this.owner() && !whiteListTransferMedia.contains(other)) + private fun shouldBlockTransfer(other: ILinkable): Boolean { + if (other is BlockEntityRelay) { + for (blEntry in blackListTransferMedia) + if (blEntry is BlockEntityRelay && blEntry.sameNetwork(other)) return true + for (wlEntry in whiteListTransferMedia) + if (wlEntry is BlockEntityRelay && wlEntry.sameNetwork(other)) return false + return true + } + return blackListTransferMedia.contains(other) || (other.owner() != this.owner() && !whiteListTransferMedia.contains(other)) + } override fun currentMediaLevel(): Long = media From 2d910d768fcd2da00393f31d86cc536810efee5f Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Mon, 15 Jun 2026 18:02:26 -0400 Subject: [PATCH 3/5] Prevent relay linkable counter from going negative --- .../talia/hexal/common/blocks/entity/BlockEntityRelay.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt b/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt index 57a29681..3d6d5d8e 100644 --- a/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt +++ b/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt @@ -215,14 +215,13 @@ class BlockEntityRelay(pos: BlockPos, val state: BlockState) : HexBlockEntity(He other.setChanged() } else { // remove from list of non-relays linked to network. + // only decrement counts if removal succeeded (it could fail if tick() already handled the removal) nonRelaysLinkedDirectly.remove(other) - relayNetwork.nonRelays.remove(other) - relayNetwork.numNonRelays -= 1 + relayNetwork.nonRelays.remove(other).let { if (it) relayNetwork.numNonRelays -= 1 } setChanged() if (other.currentMediaLevel() != -1L) { mediaExchangersLinkedDirectly.remove(other) - relayNetwork.mediaExchangers.remove(other) - relayNetwork.numMediaExchangers -= 1 + relayNetwork.mediaExchangers.remove(other).let { if (it) relayNetwork.numMediaExchangers -= 1 } } } } From 4b689adcb5ed357de2e451df8860dcc99ece9584 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Mon, 15 Jun 2026 20:19:20 -0400 Subject: [PATCH 4/5] Prevent exception when breaking linked relays --- .../ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt b/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt index 3d6d5d8e..e62bd898 100644 --- a/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt +++ b/Common/src/main/java/ram/talia/hexal/common/blocks/entity/BlockEntityRelay.kt @@ -227,7 +227,9 @@ class BlockEntityRelay(pos: BlockPos, val state: BlockState) : HexBlockEntity(He } fun disconnectAll() { - for (relay in relaysLinkedDirectly) + // kotlin docs claim that MutableSet supports concurrent modification, so the toMutableList shouldn't be needed, + // but from my testing it throws ConcurrentModificationException anyway if that's not there + for (relay in relaysLinkedDirectly.toMutableList()) relay.getRelay(level)?.let { unlink(it) } } From 481e440b9964f085eae0a88dd3235eca85cba696 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Mon, 15 Jun 2026 21:07:22 -0400 Subject: [PATCH 5/5] Update changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f6e96ec..de1dfc48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - The upkeep penalty for holding a truename in a wisp is now (properly) documented. - Mote Nexus and Relay have been added to the Hex Casting creative mode tab. - Increased the cost of Phase Block to prevent short durations being castable for free. -- Updated zh_cn translations, by ChuijkYahus in [#187](https://github.com/FallingColors/Hexal/pull/187), [#199](https://github.com/FallingColors/Hexal/pull/199), and [#206](https://github.com/FallingColors/Hexal/pull/206). +- Updated zh_cn translations, by ChuijkYahus in [#187](https://github.com/FallingColors/Hexal/pull/187), [#199](https://github.com/FallingColors/Hexal/pull/199), [#206](https://github.com/FallingColors/Hexal/pull/206), and [#228](https://github.com/FallingColors/Hexal/pull/228). - Wisps can now consume themselves for free to cleanly self-destruct. - Moved certain lang keys for type iotas from Hexal into MoreIotas, since MoreIotas is what actually implements type iotas. - Phase Block now ensures that the caster has permission to break the target block. @@ -34,6 +34,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - Fixed internal error when an entity-anchored gate can't find its entity, by Dominik-Pawelec in [#204](https://github.com/FallingColors/Hexal/pull/204). - Fixed Bind Storage - Temp permanently unbinding the caster when given a non-nexus block, by pythonmcpi in [#218](https://github.com/FallingColors/Hexal/pull/218). +- Fixed a variety of issues related to transferring media through linked Relays. - Fixed the Trade spell requiring input items in a specific order for two-item trades. - Fixed broken/missing lang keys for `list.double` and `list.vec`. - Fixed the listed cost for Summon Projectile Wisp being incorrect. @@ -44,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - Fixed the Relay block not dropping when broken. - Fixed an error when a playerless caster tries to create a link. - Fixed an error when passing null or an empty mote to Use Item On. +- Fixed an error when breaking a Relay linked to multiple other Relays. - Fixed a variety of broken lang keys in the config menu. - Fixed Trade allowing trades even when not enough input items were present.