Skip to content

Commit bcbcc99

Browse files
committed
Fix CJK line wrapping (#792) and harden FluidIntersectionMarker WAILA
LineWrapping: properly wrap text that has no spaces (e.g. Chinese/Japanese) or a single word longer than the wrap limit. Previously the word-snap loop walked the break index back to 0, appended an empty substring, and dropped one character per iteration, producing many empty lines and silently losing text. Now it hard-breaks at the wrap limit when no space is found, so it both wraps correctly and always makes progress. Closes #792. FluidIntersectionMarker: resolve the connected pipe defensively via getHeldRebarEntity so a lost intersection/pipe display no longer NPEs the WAILA update tick - getWaila hides the WAILA and getPickItem returns null instead.
1 parent 3a6a406 commit bcbcc99

2 files changed

Lines changed: 43 additions & 13 deletions

File tree

rebar/src/main/kotlin/io/github/pylonmc/rebar/content/fluid/FluidIntersectionMarker.kt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,23 @@ class FluidIntersectionMarker : RebarBlock, EntityHolderRebarBlock, BlockBreakRe
4949
}
5050
}
5151

52-
override fun getWaila(player: Player): WailaDisplay?
53-
= WailaDisplay(defaultWailaTranslationKey.arguments(RebarArgument.of("pipe", this.pipe.stack.effectiveName())))
52+
override fun getWaila(player: Player): WailaDisplay? {
53+
val pipeItem = pipeOrNull() ?: return null
54+
return WailaDisplay(defaultWailaTranslationKey.arguments(RebarArgument.of("pipe", pipeItem.stack.effectiveName())))
55+
}
5456

5557
val pipe: RebarItem
56-
get() {
57-
check(fluidIntersectionDisplay.connectedPipeDisplays.isNotEmpty())
58-
val uuid = fluidIntersectionDisplay.connectedPipeDisplays.iterator().next()
59-
return EntityStorage.getAs<FluidPipeDisplay?>(uuid)!!.pipe
60-
}
58+
get() = pipeOrNull() ?: error("FluidIntersectionMarker has no resolvable pipe display")
59+
60+
private fun pipeOrNull(): RebarItem? {
61+
val display = getHeldRebarEntity(FluidIntersectionDisplay::class.java, "intersection") ?: return null
62+
val uuid = display.connectedPipeDisplays.firstOrNull() ?: return null
63+
return EntityStorage.getAs<FluidPipeDisplay?>(uuid)?.pipe
64+
}
6165

6266
override fun getDropItem(context: BlockBreakContext) = null
6367

64-
override fun getPickItem(player: Player) = pipe.stack
68+
override fun getPickItem(player: Player) = pipeOrNull()?.stack
6569

6670
companion object {
6771
@JvmField

rebar/src/main/kotlin/io/github/pylonmc/rebar/i18n/LineWrapping.kt

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,44 @@ private fun wrapLine(
9090
// which are handled clientside) but this is fine, it can't be perfect.
9191
var content = component.content()
9292
while (currentLineLength + content.length > RebarConfig.TRANSLATION_WRAP_LIMIT) {
93+
// How many more characters fit on the current line
94+
val remaining = RebarConfig.TRANSLATION_WRAP_LIMIT - currentLineLength
9395

94-
// Make sure we snap to the end of a word (i.e. don't cut words in half)
95-
var endIndex = RebarConfig.TRANSLATION_WRAP_LIMIT - currentLineLength
96-
while (endIndex != 0 && content[endIndex] != ' ') {
96+
// Current line is already full — flush it and restart on a fresh line
97+
if (remaining <= 0) {
98+
lines.add(currentLine)
99+
currentLine = DEFAULT_COMPONENT
100+
currentLineLength = 0
101+
continue
102+
}
103+
104+
// Try to snap to the end of a word so we don't cut words in half.
105+
// (content.length > remaining here, so content[endIndex] is always in bounds.)
106+
var endIndex = remaining
107+
while (endIndex > 0 && content[endIndex] != ' ') {
97108
endIndex -= 1
98109
}
99110

100-
currentLine = currentLine.append(Component.text(content.substring(0, endIndex)).style(style))
111+
// The amount of text to put on this line, and whether to skip a delimiter space.
112+
val cut: Int
113+
val skipDelimiter: Boolean
114+
if (endIndex == 0) {
115+
// No space within the limit: either a single word longer than the wrap
116+
// limit, or a language without spaces (e.g. Chinese/Japanese). Hard-break
117+
// at the limit so we keep making progress instead of looping forever and
118+
// silently dropping characters.
119+
cut = remaining
120+
skipDelimiter = false
121+
} else {
122+
cut = endIndex
123+
skipDelimiter = true
124+
}
125+
126+
currentLine = currentLine.append(Component.text(content.substring(0, cut)).style(style))
101127
lines.add(currentLine)
102128
currentLine = DEFAULT_COMPONENT
103129
currentLineLength = 0
104-
content = if (endIndex+1 == content.length) "" else content.substring(endIndex+1)
130+
content = content.substring(if (skipDelimiter) cut + 1 else cut)
105131
}
106132
currentLine = currentLine.append(Component.text(content).style(style))
107133
currentLineLength += content.length

0 commit comments

Comments
 (0)