diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c6123f6..6845779c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Gradle uses: gradle/gradle-build-action@v2.4.0 with: - gradle-version: 8.1.1 + gradle-version: 8.4 - name: Build TASmod with Gradle run: gradle build - name: Upload Test Report diff --git a/.github/workflows/buildandupload.yml b/.github/workflows/buildandupload.yml index caa5db1c..f163ffee 100644 --- a/.github/workflows/buildandupload.yml +++ b/.github/workflows/buildandupload.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Gradle uses: gradle/gradle-build-action@v2.4.0 with: - gradle-version: 8.1.1 + gradle-version: 8.4 - name: Build TASmod with Gradle run: gradle build - name: Upload artifact diff --git a/.gitignore b/.gitignore index b4e87106..17113bf0 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,9 @@ out # gradle build .gradle +gradle +gradlew +gradlew.bat # other eclipse diff --git a/build.gradle b/build.gradle index 82b8f0cb..aa03ed92 100644 --- a/build.gradle +++ b/build.gradle @@ -43,8 +43,7 @@ configurations { // dependencies dependencies { // tasmod dependencies - embed group: 'com.dselent', name: 'bigarraylist', version: '1.0' - + embed group: 'com.dselent', name: 'bigarraylist', version: '1.1' compileOnly group: 'com.minecrafttas', name: 'killtherng', version: '2.0' downloadMod group: 'com.minecrafttas', name: 'killtherng-full', version: '2.0' // for downloadKTRNG task diff --git a/gradle.properties b/gradle.properties index 5ee6b3ce..69e32196 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,4 +16,4 @@ mod_email=scribble@minecrafttas.com # TASmod properties group=com.minecrafttas artifact=TASmod-1.12.2 -version=Beta1-SNAPHOT +version=Beta1-SNAPSHOT diff --git a/src/main/java/com/minecrafttas/mctcommon/LanguageManager.java b/src/main/java/com/minecrafttas/mctcommon/LanguageManager.java new file mode 100644 index 00000000..7dd7852e --- /dev/null +++ b/src/main/java/com/minecrafttas/mctcommon/LanguageManager.java @@ -0,0 +1,115 @@ +package com.minecrafttas.common; + +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import com.google.gson.Gson; +import net.minecraft.client.resources.IResource; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.util.ResourceLocation; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.regex.Pattern; + +public class LanguageManager { + + private static Set modids = new HashSet<>(); + private static final Splitter SPLITTER = Splitter.on('=').limit(2); + private static final Pattern PATTERN = Pattern.compile("%(\\d+\\$)?[\\d\\.]*[df]"); + + public static void onResourceManagerReload(Map original, IResourceManager iResourceManager, List languageList) { + for (String language : languageList) { // Go through all loaded languages + language = language.toLowerCase(); // Set everything to lowercase which prevents headaches in 1.10.2 and below + for (String modid : modids) { // Iterate through all registered modids + HashMap newTranslations = new HashMap<>(); + if (iResourceManager.getResourceDomains().contains(modid)) { + try { + newTranslations = getFromResourcePack(iResourceManager, modid, language); // Load .json translations from resource pack + } catch (IOException var9) { + } + } + if (newTranslations.isEmpty()) { + try { + newTranslations = loadLang(getFromResources(modid, language, "lang")); // Load .lang files from resources + } catch (IOException e) { + throw new RuntimeException(e); + } + } + if (newTranslations.isEmpty()) { + newTranslations = loadJson(getFromResources(modid, language, "json")); // Load .json translations from resources + } + /** + * Making this put if absent here creates the following hirarchy: + * Resourcepack .lang beats + * Resourcepack .json beats + * Resources .lang beats + * Resources .json + * + * Lang is preferred over json and resourcepacks are preferred over json + */ + newTranslations.forEach(original::putIfAbsent); + } + } + } + + private static InputStream getFromResources(String resourceDomain, String language, String fileending) { + return LanguageManager.class.getResourceAsStream(String.format("/assets/%s/lang/%s.%s", resourceDomain, language, fileending)); + } + + private static HashMap getFromResourcePack(IResourceManager iResourceManager, String resourceDomain, String language) throws IOException { + String languageFile = String.format("lang/%s.json", language); + HashMap out = new HashMap<>(); + Collection allResources = iResourceManager.getAllResources(new ResourceLocation(resourceDomain, languageFile)); + for (IResource iResource : allResources) { + InputStream inputStream = iResource.getInputStream(); + out.putAll(loadJson(inputStream)); + } + return out; + } + + /** + * Registers your mod to be processed by the language manager
+ * This will allow you to add .json and/or .lang files to assets/modid/lang
+ * with en_us.lang/en_us.json (lowercase!) + * + * @param modid The modid of your mod + */ + public static void registerMod(String modid) { + modids.add(modid); + } + + private static HashMap loadJson(InputStream inputStream) { + if (inputStream == null) { + return new HashMap(); + } + Gson gson = new Gson(); + HashMap template = new HashMap<>(); + HashMap out = (HashMap) gson.fromJson(new InputStreamReader(inputStream), template.getClass()); + out.forEach((key, value) -> { + value = PATTERN.matcher(value).replaceAll("%$1s"); + }); + return out; + } + + private static HashMap loadLang(InputStream inputStream) throws IOException { + HashMap out = new HashMap<>(); + if (inputStream == null) { + return out; + } + for (String string : IOUtils.readLines(inputStream, StandardCharsets.UTF_8)) { + if (!string.isEmpty() && string.charAt(0) != '#') { + String[] key_value_pair = Iterables.toArray(SPLITTER.split(string), String.class); + if (key_value_pair != null && key_value_pair.length == 2) { + String key = key_value_pair[0]; + String value = PATTERN.matcher(key_value_pair[1]).replaceAll("%$1s"); + out.put(key, value); + } + } + } + return out; + } +} diff --git a/src/main/java/com/minecrafttas/mctcommon/mixin/MixinLocale.java b/src/main/java/com/minecrafttas/mctcommon/mixin/MixinLocale.java new file mode 100644 index 00000000..ce4054f6 --- /dev/null +++ b/src/main/java/com/minecrafttas/mctcommon/mixin/MixinLocale.java @@ -0,0 +1,24 @@ +package com.minecrafttas.common.mixin; + +import com.minecrafttas.common.LanguageManager; +import net.minecraft.client.resources.IResourceManager; +import net.minecraft.client.resources.Locale; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; +import java.util.Map; + +@Mixin(Locale.class) +public class MixinLocale { + + @Shadow + private Map properties; + @Inject(method="loadLocaleDataFiles", at = @At("RETURN")) + private void inject_loadLocalDataFiles(IResourceManager iResourceManager, List list, CallbackInfo ci){ + LanguageManager.onResourceManagerReload(properties, iResourceManager, list); + } +} diff --git a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java index b88e912f..4eecf42f 100644 --- a/src/main/java/com/minecrafttas/tasmod/TASmodClient.java +++ b/src/main/java/com/minecrafttas/tasmod/TASmodClient.java @@ -1,15 +1,6 @@ package com.minecrafttas.tasmod; -import static com.minecrafttas.tasmod.TASmod.LOGGER; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.apache.logging.log4j.Level; -import org.lwjgl.input.Keyboard; - +import com.minecrafttas.common.LanguageManager; import com.minecrafttas.mctcommon.Configuration; import com.minecrafttas.mctcommon.Configuration.ConfigOptions; import com.minecrafttas.mctcommon.KeybindManager; @@ -37,7 +28,6 @@ import com.minecrafttas.tasmod.util.ShieldDownloader; import com.minecrafttas.tasmod.virtual.VirtualInput; import com.minecrafttas.tasmod.virtual.VirtualKeybindings; - import net.fabricmc.api.ClientModInitializer; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; @@ -47,6 +37,15 @@ import net.minecraft.client.multiplayer.ServerData; import net.minecraft.client.settings.KeyBinding; import net.minecraft.server.MinecraftServer; +import org.apache.logging.log4j.Level; +import org.lwjgl.input.Keyboard; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static com.minecrafttas.tasmod.TASmod.LOGGER; public class TASmodClient implements ClientModInitializer, EventClientInit, EventPlayerJoinedClientSide, EventOpenGui{ @@ -111,6 +110,8 @@ public void onInitializeClient() { } config = new Configuration("TASmod configuration", new File(configDir, "tasmod.cfg")); + LanguageManager.registerMod("tasmod"); + // Execute /restartandplay. Load the file to start from the config. If it exists load the playback file on start. String fileOnStart = config.get(ConfigOptions.FileToOpen); if (fileOnStart.isEmpty()) { diff --git a/src/main/java/com/minecrafttas/tasmod/commands/CommandTickrate.java b/src/main/java/com/minecrafttas/tasmod/commands/CommandTickrate.java index e004798e..584e6a81 100644 --- a/src/main/java/com/minecrafttas/tasmod/commands/CommandTickrate.java +++ b/src/main/java/com/minecrafttas/tasmod/commands/CommandTickrate.java @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableList; import com.minecrafttas.tasmod.TASmod; +import net.minecraft.client.resources.I18n; import net.minecraft.command.CommandBase; import net.minecraft.command.CommandException; import net.minecraft.command.ICommandSender; @@ -29,7 +30,7 @@ public List getAliases() { @Override public String getUsage(ICommandSender sender) { - return "/tickrate "; + return I18n.format("tickratechanger.tasmod.command.usage"); // "/tickrate " } @Override @@ -40,7 +41,7 @@ public int getRequiredPermissionLevel() { @Override public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { if (args.length == 0) { - sender.sendMessage(new TextComponentString("Current tickrate: " + TASmod.tickratechanger.ticksPerSecond)); + sender.sendMessage(new TextComponentString( I18n.format("tickratechanger.tasmod.command.show", TASmod.tickratechanger.ticksPerSecond))); //"Current tickrate: " return; } float tickrate; diff --git a/src/main/resources/assets/tasmod/lang/en_us.json b/src/main/resources/assets/tasmod/lang/en_us.json new file mode 100644 index 00000000..42434be2 --- /dev/null +++ b/src/main/resources/assets/tasmod/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "tickratechanger.tasmod.command.show": "Current tickrate: %s", + "tickratechanger.tasmod.command.usage": "/tickrate " +} \ No newline at end of file diff --git a/src/main/resources/mctcommon.mixin.json b/src/main/resources/mctcommon.mixin.json index ac54bb22..f070f007 100644 --- a/src/main/resources/mctcommon.mixin.json +++ b/src/main/resources/mctcommon.mixin.json @@ -13,6 +13,7 @@ "MixinMinecraft", "MixinNetHandlerPlayClient", "MixinWorldClient", - "MixinEntityRenderer" + "MixinEntityRenderer", + "MixinLocale" ] } \ No newline at end of file