aboutsummaryrefslogtreecommitdiff
path: root/src/texturePacks/java/moe
diff options
context:
space:
mode:
Diffstat (limited to 'src/texturePacks/java/moe')
-rw-r--r--src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomTextReplacements.kt56
-rw-r--r--src/texturePacks/java/moe/nea/firmament/features/texturepack/StringMatcher.kt47
-rw-r--r--src/texturePacks/java/moe/nea/firmament/features/texturepack/TreeishTextReplacer.kt87
-rw-r--r--src/texturePacks/java/moe/nea/firmament/mixins/custommodels/ReplaceTextsInDrawContext.java55
4 files changed, 243 insertions, 2 deletions
diff --git a/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomTextReplacements.kt b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomTextReplacements.kt
new file mode 100644
index 0000000..8f7fc06
--- /dev/null
+++ b/src/texturePacks/java/moe/nea/firmament/features/texturepack/CustomTextReplacements.kt
@@ -0,0 +1,56 @@
+package moe.nea.firmament.features.texturepack
+
+import net.minecraft.resource.ResourceManager
+import net.minecraft.resource.SinglePreparationResourceReloader
+import net.minecraft.text.Text
+import net.minecraft.util.profiler.Profiler
+import moe.nea.firmament.Firmament
+import moe.nea.firmament.annotations.Subscribe
+import moe.nea.firmament.events.FinalizeResourceManagerEvent
+import moe.nea.firmament.util.ErrorUtil.intoCatch
+
+object CustomTextReplacements : SinglePreparationResourceReloader<List<TreeishTextReplacer>>() {
+
+ override fun prepare(
+ manager: ResourceManager,
+ profiler: Profiler
+ ): List<TreeishTextReplacer> {
+ return manager.findResources("overrides/texts") { it.namespace == "firmskyblock" && it.path.endsWith(".json") }
+ .mapNotNull {
+ Firmament.tryDecodeJsonFromStream<TreeishTextReplacer>(it.value.inputStream)
+ .intoCatch("Failed to load text override from ${it.key}").orNull()
+ }
+ }
+
+ var textReplacers: List<TreeishTextReplacer> = listOf()
+
+ override fun apply(
+ prepared: List<TreeishTextReplacer>,
+ manager: ResourceManager,
+ profiler: Profiler
+ ) {
+ this.textReplacers = prepared
+ }
+
+ @JvmStatic
+ fun replaceTexts(texts: List<Text>): List<Text> {
+ return texts.map { replaceText(it) }
+ }
+
+ @JvmStatic
+ fun replaceText(text: Text): Text {
+ // TODO: add a config option for this
+ val rawText = text.string
+ var text = text
+ for (replacer in textReplacers) {
+ if (!replacer.match.matches(rawText)) continue
+ text = replacer.replaceText(text)
+ }
+ return text
+ }
+
+ @Subscribe
+ fun onReloadStart(event: FinalizeResourceManagerEvent) {
+ event.resourceManager.registerReloader(this)
+ }
+}
diff --git a/src/texturePacks/java/moe/nea/firmament/features/texturepack/StringMatcher.kt b/src/texturePacks/java/moe/nea/firmament/features/texturepack/StringMatcher.kt
index 7de84d2..863ca3b 100644
--- a/src/texturePacks/java/moe/nea/firmament/features/texturepack/StringMatcher.kt
+++ b/src/texturePacks/java/moe/nea/firmament/features/texturepack/StringMatcher.kt
@@ -23,6 +23,10 @@ interface StringMatcher {
return matches(text.string)
}
+ val asRegex: java.util.regex.Pattern
+
+ fun matchWithGroups(string: String): MatchNamedGroupCollection?
+
fun matches(nbt: NbtString): Boolean {
val string = nbt.value
val jsonStart = string.indexOf('{')
@@ -36,20 +40,59 @@ interface StringMatcher {
}
class Equals(input: String, val stripColorCodes: Boolean) : StringMatcher {
+ override val asRegex by lazy(LazyThreadSafetyMode.PUBLICATION) { input.toPattern(java.util.regex.Pattern.LITERAL) }
private val expected = if (stripColorCodes) input.removeColorCodes() else input
override fun matches(string: String): Boolean {
return expected == (if (stripColorCodes) string.removeColorCodes() else string)
}
+ override fun matchWithGroups(string: String): MatchNamedGroupCollection? {
+ if (matches(string))
+ return object : MatchNamedGroupCollection {
+ override fun get(name: String): MatchGroup? {
+ return null
+ }
+
+ override fun get(index: Int): MatchGroup? {
+ return null
+ }
+
+ override val size: Int
+ get() = 0
+
+ override fun isEmpty(): Boolean {
+ return true
+ }
+
+ override fun contains(element: MatchGroup?): Boolean {
+ return false
+ }
+
+ override fun iterator(): Iterator<MatchGroup?> {
+ return emptyList<MatchGroup>().iterator()
+ }
+
+ override fun containsAll(elements: Collection<MatchGroup?>): Boolean {
+ return elements.isEmpty()
+ }
+ }
+ return null
+ }
+
override fun toString(): String {
return "Equals($expected, stripColorCodes = $stripColorCodes)"
}
}
class Pattern(val patternWithColorCodes: String, val stripColorCodes: Boolean) : StringMatcher {
- private val regex: Predicate<String> = patternWithColorCodes.toPattern().asMatchPredicate()
+ private val pattern = patternWithColorCodes.toRegex()
+ override val asRegex = pattern.toPattern()
override fun matches(string: String): Boolean {
- return regex.test(if (stripColorCodes) string.removeColorCodes() else string)
+ return pattern.matches(if (stripColorCodes) string.removeColorCodes() else string)
+ }
+
+ override fun matchWithGroups(string: String): MatchNamedGroupCollection? {
+ return pattern.matchEntire(if (stripColorCodes) string.removeColorCodes() else string)?.groups as MatchNamedGroupCollection?
}
override fun toString(): String {
diff --git a/src/texturePacks/java/moe/nea/firmament/features/texturepack/TreeishTextReplacer.kt b/src/texturePacks/java/moe/nea/firmament/features/texturepack/TreeishTextReplacer.kt
new file mode 100644
index 0000000..0a59451
--- /dev/null
+++ b/src/texturePacks/java/moe/nea/firmament/features/texturepack/TreeishTextReplacer.kt
@@ -0,0 +1,87 @@
+package moe.nea.firmament.features.texturepack
+
+import java.lang.StringBuilder
+import java.util.regex.Matcher
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import kotlinx.serialization.json.JsonElement
+import net.minecraft.text.Text
+import net.minecraft.text.TextCodecs
+import moe.nea.firmament.util.directLiteralStringContent
+import moe.nea.firmament.util.json.KJsonOps
+import moe.nea.firmament.util.transformEachRecursively
+
+@Serializable
+data class TreeishTextReplacer(
+ val match: StringMatcher,
+ val replacements: List<SubPartReplacement>
+) {
+ @Serializable
+ data class SubPartReplacement(
+ val match: StringMatcher,
+ val replace: @Serializable(TextSerializer::class) Text,
+ )
+
+ object TextSerializer : KSerializer<Text> {
+ override val descriptor: SerialDescriptor
+ get() = JsonElement.serializer().descriptor
+
+ override fun serialize(encoder: Encoder, value: Text) {
+ encoder.encodeSerializableValue(
+ JsonElement.serializer(),
+ TextCodecs.CODEC.encodeStart(KJsonOps.INSTANCE, value).orThrow
+ )
+ }
+
+ override fun deserialize(decoder: Decoder): Text {
+ return TextCodecs.CODEC.decode(KJsonOps.INSTANCE, decoder.decodeSerializableValue(JsonElement.serializer()))
+ .orThrow.first
+ }
+ }
+
+ companion object {
+ val pattern = "(?!<\\$([$]{2})*)[$]\\{(?<name>[^}])\\}".toPattern()
+ fun injectMatchResults(text: Text, matches: Matcher): Text {
+ return text.transformEachRecursively { it ->
+ val content = it.directLiteralStringContent ?: return@transformEachRecursively it
+ val matcher = pattern.matcher(content)
+ val builder = StringBuilder()
+ while (matcher.find()) {
+ matcher.appendReplacement(builder, matches.group(matcher.group("name")).toString())
+ }
+ matcher.appendTail(builder)
+ Text.literal(builder.toString()).setStyle(it.style)
+ }
+ }
+ }
+
+ fun match(text: Text): Boolean {
+ return match.matches(text)
+ }
+
+ fun replaceText(text: Text): Text {
+ return text.transformEachRecursively { part ->
+ var part: Text = part
+ for (replacement in replacements) {
+ val rawPartText = part.string
+ val matcher = replacement.match.asRegex.matcher(rawPartText)
+ if (!matcher.find()) continue
+ val p = Text.literal("")
+ p.setStyle(part.style)
+ var lastAppendPosition = 0
+ do {
+ p.append(rawPartText.substring(lastAppendPosition, matcher.start()))
+ lastAppendPosition = matcher.end()
+ p.append(injectMatchResults(replacement.replace, matcher))
+ } while (matcher.find())
+ p.append(rawPartText.substring(lastAppendPosition))
+ part = p
+ }
+ part
+ }
+ }
+
+}
diff --git a/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/ReplaceTextsInDrawContext.java b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/ReplaceTextsInDrawContext.java
new file mode 100644
index 0000000..faf15cc
--- /dev/null
+++ b/src/texturePacks/java/moe/nea/firmament/mixins/custommodels/ReplaceTextsInDrawContext.java
@@ -0,0 +1,55 @@
+package moe.nea.firmament.mixins.custommodels;
+
+import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
+import moe.nea.firmament.features.texturepack.CustomTextReplacements;
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.text.StringVisitable;
+import net.minecraft.text.Text;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.ModifyVariable;
+
+import java.util.stream.Stream;
+
+@Mixin(DrawContext.class)
+public class ReplaceTextsInDrawContext {
+ // I HATE THIS SO MUCH WHY CANT I JUST OPERATE ON ORDEREDTEXTS!!!
+ // JUNE I WILL RIP ALL OF THIS OUT AND MAKE YOU REWRITE EVERYTHING
+ // TODO: be in a mood to rewrite this
+
+ @ModifyVariable(method = "drawText(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;IIIZ)V", at = @At("HEAD"), argsOnly = true)
+ private Text replaceTextInDrawText(Text text) {
+ return CustomTextReplacements.replaceText(text);
+ }
+
+ @ModifyVariable(method = "drawCenteredTextWithShadow(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/text/Text;III)V", at = @At("HEAD"), argsOnly = true)
+ private Text replaceTextInDrawCenteredTextWithShadow(Text text) {
+ return CustomTextReplacements.replaceText(text);
+ }
+
+ @ModifyVariable(method = "drawWrappedText", at = @At("HEAD"), argsOnly = true)
+ private StringVisitable replaceTextInDrawWrappedText(StringVisitable stringVisitable) {
+ return stringVisitable instanceof Text text ? CustomTextReplacements.replaceText(text) : stringVisitable;
+ }
+
+ @ModifyExpressionValue(method = "drawTooltip(Lnet/minecraft/client/font/TextRenderer;Ljava/util/List;IILnet/minecraft/util/Identifier;)V", at = @At(value = "INVOKE", target = "Ljava/util/List;stream()Ljava/util/stream/Stream;"))
+ private Stream<Text> replaceTextInDrawTooltipListText(Stream<Text> original) {
+ return original.map(CustomTextReplacements::replaceText);
+ }
+
+ @ModifyExpressionValue(method = "drawTooltip(Lnet/minecraft/client/font/TextRenderer;Ljava/util/List;Ljava/util/Optional;IILnet/minecraft/util/Identifier;)V", at = @At(value = "INVOKE", target = "Ljava/util/List;stream()Ljava/util/stream/Stream;"))
+ private Stream<Text> replaceTextInDrawTooltipListTextWithOptional(Stream<Text> original) {
+ return original.map(CustomTextReplacements::replaceText);
+ }
+
+ @ModifyVariable(method = "drawTooltip(Lnet/minecraft/text/Text;II)V", at = @At("HEAD"), argsOnly = true)
+ private Text replaceTextInDrawTooltipSingle(Text text) {
+ return CustomTextReplacements.replaceText(text);
+ }
+
+ @ModifyExpressionValue(method = "drawHoverEvent", at = @At(value = "INVOKE", target = "Lnet/minecraft/text/HoverEvent$ShowText;value()Lnet/minecraft/text/Text;"))
+ private Text replaceShowTextInHover(Text text) {
+ return CustomTextReplacements.replaceText(text);
+ }
+
+}