Rewrote splitLines using Test-Driven Development, words should no longer get lost

This commit is contained in:
Ceikry
2022-08-16 13:37:00 +00:00
committed by Ryan
parent 7690aad9fb
commit 21d334a989
3 changed files with 60 additions and 43 deletions
@@ -353,7 +353,7 @@ public abstract class DialoguePlugin implements Plugin<Player> {
* @param msg the message for the NPC to say * @param msg the message for the NPC to say
*/ */
public Component npcl(FacialExpression expr, String msg){ public Component npcl(FacialExpression expr, String msg){
return npc(expr, splitLines(msg)); return npc(expr, splitLines(msg, 54));
} }
/** /**
@@ -362,7 +362,7 @@ public abstract class DialoguePlugin implements Plugin<Player> {
* @param msg the message for the player to say * @param msg the message for the player to say
*/ */
public Component playerl(FacialExpression expr, String msg){ public Component playerl(FacialExpression expr, String msg){
return player(expr, splitLines(msg)); return player(expr, splitLines(msg, 54));
} }
public void showTopics(Topic<?>... topics) { public void showTopics(Topic<?>... topics) {
+31 -35
View File
@@ -1,50 +1,46 @@
package api package api
import rs09.game.system.SystemLogger
import java.util.* import java.util.*
import kotlin.system.exitProcess import kotlin.math.ceil
//Number of chars per line. Line is split at the nearest whole word that doesn't exceed this length. This should remain constant once a perfect value is found
const val LINE_SIZE = 52.0
/** /**
* Automatically split a single continuous string into multiple comma-separated lines. * Automatically split a single continuous string into multiple comma-separated lines.
* Should this not work out for any reason, you should fallback to standard npc and player methods for dialogue. * Should this not work out for any reason, you should fallback to standard npc and player methods for dialogue.
*/ */
fun splitLines(message: String): Array<String>{ fun splitLines(message: String, perLineLimit: Int = 54) : Array<String> {
val chars = message.split("").toTypedArray().size.toDouble() val lines = Array(ceil(message.length / perLineLimit.toFloat()).toInt()) {""}
val words = message.split(" ").toTypedArray()
val lines = Math.ceil(chars / LINE_SIZE).toInt()
if(lines > 4){ //short circuit when possible because it's cheaper.
SystemLogger.logErr("INVALID NUM LINES. NUM CHARS: $chars") if (lines.size == 1) {
lines[0] = message
return lines
} }
val messages = ArrayList<String>() val tokenQueue = LinkedList(message.split(" "))
var index = 0 var index = 0
for (msg in 0 until lines) {
var length = 0
val line = StringBuilder() val line = StringBuilder()
while (length <= LINE_SIZE && !(index == words.size)) { var accumulator = 0
var currentWord = ""
try { fun pushLine() {
currentWord = words[index] + if (length + words[index].length + 1 <= LINE_SIZE) " " else "" if (line.isEmpty()) return
} catch (e: Exception){ lines[index++] = line.toString()
SystemLogger.logWarn("INDEX: $index WORDSIZE: ${words.size}") line.clear()
for(word in words.indices){ accumulator = 0
SystemLogger.logErr("Word $word: ${words[word]}")
}
exitProcess(0)
}
length += currentWord.length
if (length <= LINE_SIZE) {
line.append(currentWord)
++index
}
}
messages.add(line.toString())
} }
return messages.toTypedArray() while (!tokenQueue.isEmpty()) {
val shouldSpace = line.isNotEmpty()
accumulator += tokenQueue.peek().length
if (shouldSpace) accumulator += 1
if (accumulator > perLineLimit) {
pushLine()
continue
}
if (shouldSpace) line.append(" ")
line.append(tokenQueue.pop())
}
pushLine()
return lines
} }
+27 -6
View File
@@ -1,18 +1,14 @@
import api.IfaceSettingsBuilder import api.IfaceSettingsBuilder
import core.game.node.entity.player.Player import api.splitLines
import core.game.node.entity.player.info.PlayerDetails
import core.game.node.entity.skill.slayer.Master import core.game.node.entity.skill.slayer.Master
import core.game.node.entity.skill.slayer.Tasks import core.game.node.entity.skill.slayer.Tasks
import org.json.simple.JSONObject import org.json.simple.JSONObject
import org.json.simple.parser.JSONParser import org.json.simple.parser.JSONParser
import org.junit.Assert
import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import rs09.game.node.entity.skill.slayer.SlayerFlags
import rs09.game.node.entity.skill.slayer.SlayerManager import rs09.game.node.entity.skill.slayer.SlayerManager
import rs09.game.system.SystemLogger
object APITests { class APITests {
val testPlayer = TestUtils.getMockPlayer("test") val testPlayer = TestUtils.getMockPlayer("test")
val testPlayer2 = TestUtils.getMockPlayer("test2") val testPlayer2 = TestUtils.getMockPlayer("test2")
@@ -142,4 +138,29 @@ object APITests {
Assertions.assertNotEquals(0, manager.flags.getPoints()) Assertions.assertNotEquals(0, manager.flags.getPoints())
Assertions.assertEquals(true, manager.flags.isHelmUnlocked()) Assertions.assertEquals(true, manager.flags.isHelmUnlocked())
} }
@Test fun lineSplitShouldSplitAtLimitAndPreserveAllWords() {
var testCase = "The monks are running a ship from Port Sarim to Entrana, I hear too. Now leave me alone yer elephant!"
var expectedLine1 = "The monks are running a ship from Port Sarim to"
var expectedLine2 = "Entrana, I hear too. Now leave me alone yer elephant!"
var lines = splitLines(testCase, 54)
Assertions.assertEquals(expectedLine1, lines.getOrNull(0) ?: "")
Assertions.assertEquals(expectedLine2, lines.getOrNull(1) ?: "")
Assertions.assertEquals(2, lines.size)
testCase = "Dramenwood staffs are crafted from branches of the Dramen tree, so they are. I hear there's a Dramen tree over on the island of Entrana in a cave."
expectedLine1 = "Dramenwood staffs are crafted from branches of the"
expectedLine2 = "Dramen tree, so they are. I hear there's a Dramen tree"
var expectedLine3 = "over on the island of Entrana in a cave."
lines = splitLines(testCase, 54)
Assertions.assertEquals(expectedLine1, lines.getOrNull(0) ?: "")
Assertions.assertEquals(expectedLine2, lines.getOrNull(1) ?: "")
Assertions.assertEquals(expectedLine3, lines.getOrNull(2) ?: "")
Assertions.assertEquals(3, lines.size)
testCase = "This should be one line."
lines = splitLines(testCase)
Assertions.assertEquals(testCase, lines[0])
Assertions.assertEquals(1, lines.size)
}
} }