aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java2
-rw-r--r--src/main/kotlin/Firmament.kt1
-rw-r--r--src/main/kotlin/util/textutil.kt3
-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
7 files changed, 248 insertions, 3 deletions
diff --git a/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java b/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java
index a9db7f9..07e4549 100644
--- a/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java
+++ b/src/main/java/moe/nea/firmament/init/AutoDiscoveryPlugin.java
@@ -27,6 +27,8 @@ public class AutoDiscoveryPlugin {
return mixins.stream().map(it -> defaultName + "." + it).toList();
}
+ // TODO: remove println
+
private static final List<AutoDiscoveryPlugin> mixinPlugins = new ArrayList<>();
public static List<AutoDiscoveryPlugin> getMixinPlugins() {
diff --git a/src/main/kotlin/Firmament.kt b/src/main/kotlin/Firmament.kt
index b00546a..218d304 100644
--- a/src/main/kotlin/Firmament.kt
+++ b/src/main/kotlin/Firmament.kt
@@ -74,6 +74,7 @@ object Firmament {
prettyPrint = DEBUG
isLenient = true
allowTrailingComma = true
+ allowComments = true
ignoreUnknownKeys = true
encodeDefaults = true
prettyPrintIndent = if (prettyPrint) "\t" else DEFAULT_JSON_INDENT
diff --git a/src/main/kotlin/util/textutil.kt b/src/main/kotlin/util/textutil.kt
index cfda2e9..177b0af 100644
--- a/src/main/kotlin/util/textutil.kt
+++ b/src/main/kotlin/util/textutil.kt
@@ -179,10 +179,11 @@ fun Text.transformEachRecursively(function: (Text) -> Text): Text {
val c = this.content
if (c is TranslatableTextContent) {
return Text.translatableWithFallback(c.key, c.fallback, *c.args.map {
- (if (it is Text) it else Text.literal(it.toString())).transformEachRecursively(function)
+ (it as? Text ?: Text.literal(it.toString())).transformEachRecursively(function)
}.toTypedArray()).also { new ->
new.style = this.style
new.siblings.clear()
+ val new = function(new)
this.siblings.forEach { child ->
new.siblings.add(child.transformEachRecursively(function))
}
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);
+ }
+
+}