From 3b8f9260ac62f6ea60c14af771afc811dfcf55d1 Mon Sep 17 00:00:00 2001 From: Luke100000 Date: Tue, 13 Feb 2024 10:39:06 +0100 Subject: [PATCH] made tts language detection automatic --- changelog.md | 4 + common/src/main/java/net/mca/Config.java | 1 - .../main/java/net/mca/client/LanguageMap.java | 124 ++++++++++++++++++ .../net/mca/client/OnlineSpeechManager.java | 3 +- .../java/net/mca/client/SpeechManager.java | 19 ++- .../java/net/mca/server/command/Command.java | 21 +-- .../main/resources/assets/mca/lang/en_us.json | 1 + 7 files changed, 147 insertions(+), 26 deletions(-) create mode 100644 common/src/main/java/net/mca/client/LanguageMap.java diff --git a/changelog.md b/changelog.md index 77a32e4a56..93e617249b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,7 @@ +# 7.5.14 + +* TTS language is now detected automatically + # 7.5.13 * Updated chatAI to v2 diff --git a/common/src/main/java/net/mca/Config.java b/common/src/main/java/net/mca/Config.java index 66a6e6d77f..c6b94cab07 100644 --- a/common/src/main/java/net/mca/Config.java +++ b/common/src/main/java/net/mca/Config.java @@ -113,7 +113,6 @@ public static Config getInstance() { // TTS public boolean enableOnlineTTS = false; public String villagerTTSServer = "http://api.rk.conczin.net/"; - public String onlineTTSLanguage = "en"; //village behavior public float guardSpawnFraction = 0.175f; diff --git a/common/src/main/java/net/mca/client/LanguageMap.java b/common/src/main/java/net/mca/client/LanguageMap.java new file mode 100644 index 0000000000..2a27861b53 --- /dev/null +++ b/common/src/main/java/net/mca/client/LanguageMap.java @@ -0,0 +1,124 @@ +package net.mca.client; + +import java.util.HashMap; +import java.util.Map; + +public class LanguageMap { + public static final Map LANGUAGE_MAP = new HashMap<>(); + + static { + LANGUAGE_MAP.put("af_za", ""); + LANGUAGE_MAP.put("ar_sa", "ar"); + LANGUAGE_MAP.put("ast_es", "es"); + LANGUAGE_MAP.put("az_az", ""); + LANGUAGE_MAP.put("be_by", "ru"); + LANGUAGE_MAP.put("bg_bg", ""); + LANGUAGE_MAP.put("br_fr", "fr"); + LANGUAGE_MAP.put("brb", "nl"); + LANGUAGE_MAP.put("bs_BA", ""); + LANGUAGE_MAP.put("ca_es", ""); + LANGUAGE_MAP.put("cs_cz", "cs"); + LANGUAGE_MAP.put("cy_gb", ""); + LANGUAGE_MAP.put("da_dk", ""); + LANGUAGE_MAP.put("de_at", "de"); + LANGUAGE_MAP.put("de_ch", "de"); + LANGUAGE_MAP.put("de_de", "de"); + LANGUAGE_MAP.put("el_gr", ""); + LANGUAGE_MAP.put("en_au", "en"); + LANGUAGE_MAP.put("en_ca", "en"); + LANGUAGE_MAP.put("en_za", "en"); + LANGUAGE_MAP.put("en_gb", "en"); + LANGUAGE_MAP.put("en_nz", "en"); + LANGUAGE_MAP.put("en_7s", "en"); + LANGUAGE_MAP.put("en_ud", "en"); + LANGUAGE_MAP.put("en_us", "en"); + LANGUAGE_MAP.put("eo_uy", ""); + LANGUAGE_MAP.put("es_ar", "es"); + LANGUAGE_MAP.put("es_es", "es"); + LANGUAGE_MAP.put("es_cl", "es"); + LANGUAGE_MAP.put("es_mx", "es"); + LANGUAGE_MAP.put("es_uy", "es"); + LANGUAGE_MAP.put("es_ve", "es"); + LANGUAGE_MAP.put("et_ee", ""); + LANGUAGE_MAP.put("eu_es", ""); + LANGUAGE_MAP.put("fa_ir", ""); + LANGUAGE_MAP.put("fi_fi", ""); + LANGUAGE_MAP.put("fil_ph", ""); + LANGUAGE_MAP.put("fo_fo", ""); + LANGUAGE_MAP.put("fr_ca", "fr"); + LANGUAGE_MAP.put("fr_fr", "fr"); + LANGUAGE_MAP.put("fy_nl", ""); + LANGUAGE_MAP.put("ga_ie", ""); + LANGUAGE_MAP.put("gd_gb", ""); + LANGUAGE_MAP.put("gl_es", ""); + LANGUAGE_MAP.put("gv_im", ""); + LANGUAGE_MAP.put("haw", ""); + LANGUAGE_MAP.put("he_il", ""); + LANGUAGE_MAP.put("hi_in", "hi"); + LANGUAGE_MAP.put("hr_hr", ""); + LANGUAGE_MAP.put("hu_hu", "hu"); + LANGUAGE_MAP.put("hy_am", ""); + LANGUAGE_MAP.put("id_id", ""); + LANGUAGE_MAP.put("isv", ""); + LANGUAGE_MAP.put("ig_ng", ""); + LANGUAGE_MAP.put("io_en", ""); + LANGUAGE_MAP.put("is_is", ""); + LANGUAGE_MAP.put("it_it", "it"); + LANGUAGE_MAP.put("ja_jp", "ja"); + LANGUAGE_MAP.put("jbo", ""); + LANGUAGE_MAP.put("ka_ge", ""); + LANGUAGE_MAP.put("ko_kr", "ko"); + LANGUAGE_MAP.put("ksh_de", "de"); // Kölsch/Ripuarian - mapping to German + LANGUAGE_MAP.put("kw_gb", ""); + LANGUAGE_MAP.put("la_va", ""); + LANGUAGE_MAP.put("lb_lu", ""); + LANGUAGE_MAP.put("li_li", ""); + LANGUAGE_MAP.put("lol_aa", ""); + LANGUAGE_MAP.put("lt_lt", ""); + LANGUAGE_MAP.put("lv_lv", ""); + LANGUAGE_MAP.put("mi_nz", ""); + LANGUAGE_MAP.put("mk_mk", ""); + LANGUAGE_MAP.put("mn_mn", ""); + LANGUAGE_MAP.put("moh_us", ""); + LANGUAGE_MAP.put("ms_my", ""); + LANGUAGE_MAP.put("mt_mt", ""); + LANGUAGE_MAP.put("nds_de", "de"); // Low German - mapping to German + LANGUAGE_MAP.put("nl_be", "nl"); + LANGUAGE_MAP.put("nl_nl", "nl"); + LANGUAGE_MAP.put("nn_no", ""); + LANGUAGE_MAP.put("no_no", ""); + LANGUAGE_MAP.put("nb_no", ""); + LANGUAGE_MAP.put("nuk", ""); + LANGUAGE_MAP.put("oc_fr", ""); + LANGUAGE_MAP.put("oj_ca", ""); + LANGUAGE_MAP.put("ovd_se", ""); + LANGUAGE_MAP.put("pl_pl", "pl"); + LANGUAGE_MAP.put("pt_br", "pt"); + LANGUAGE_MAP.put("pt_pt", "pt"); + LANGUAGE_MAP.put("qya_aa", ""); + LANGUAGE_MAP.put("ro_ro", ""); + LANGUAGE_MAP.put("ru_ru", "ru"); + LANGUAGE_MAP.put("sme", ""); + LANGUAGE_MAP.put("sk_sk", ""); + LANGUAGE_MAP.put("sl_si", ""); + LANGUAGE_MAP.put("so_so", ""); + LANGUAGE_MAP.put("sq_al", ""); + LANGUAGE_MAP.put("sr_sp", ""); + LANGUAGE_MAP.put("sv_se", ""); + LANGUAGE_MAP.put("swg", ""); + LANGUAGE_MAP.put("sxu", "de"); // Upper Saxon German - mapping to German + LANGUAGE_MAP.put("szl", ""); + LANGUAGE_MAP.put("ta_IN", ""); + LANGUAGE_MAP.put("th_th", ""); + LANGUAGE_MAP.put("tlh_aa", ""); + LANGUAGE_MAP.put("tr_tr", "tr"); + LANGUAGE_MAP.put("tt_ru", ""); + LANGUAGE_MAP.put("tzl_tzl", ""); + LANGUAGE_MAP.put("uk_ua", ""); + LANGUAGE_MAP.put("vi_vn", ""); + LANGUAGE_MAP.put("vmf_de", "de"); // Franconian - mapping to German + LANGUAGE_MAP.put("yo_ng", ""); + LANGUAGE_MAP.put("zh_cn", "zh-cn"); + LANGUAGE_MAP.put("zh_tw", ""); + } +} \ No newline at end of file diff --git a/common/src/main/java/net/mca/client/OnlineSpeechManager.java b/common/src/main/java/net/mca/client/OnlineSpeechManager.java index c605d37895..902a0bf1c7 100644 --- a/common/src/main/java/net/mca/client/OnlineSpeechManager.java +++ b/common/src/main/java/net/mca/client/OnlineSpeechManager.java @@ -61,9 +61,8 @@ public String getHash(String text) { return toHex(MESSAGEDIGEST.digest()).toLowerCase(Locale.ROOT); } - public void play(String voice, float pitch, String text, Entity entity) { + public void play(String language, String voice, float pitch, String text, Entity entity) { String hash = getHash(text); - String language = Config.getInstance().onlineTTSLanguage; CompletableFuture.runAsync(() -> { if (downloadAudio(language, voice, text, hash)) { play(language, voice, pitch, entity, hash); diff --git a/common/src/main/java/net/mca/client/SpeechManager.java b/common/src/main/java/net/mca/client/SpeechManager.java index 97fc7c9d3b..8792abd8d5 100644 --- a/common/src/main/java/net/mca/client/SpeechManager.java +++ b/common/src/main/java/net/mca/client/SpeechManager.java @@ -10,8 +10,11 @@ import net.minecraft.entity.Entity; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; +import net.minecraft.text.ClickEvent; +import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.text.TextContent; +import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; import net.minecraft.util.Language; import net.minecraft.util.math.random.Random; @@ -71,10 +74,18 @@ private void speak(String phrase, UUID sender) { String gender = villager.getGenetics().getGender().binary().getDataName(); if (Config.getInstance().enableOnlineTTS) { - String content = Language.getInstance().get(phrase); - int tone = Math.min(TOTAL_VOICES - 1, (int) Math.floor(gene * TOTAL_VOICES)); - String voice = gender + "_" + tone; - OnlineSpeechManager.INSTANCE.play(voice, pitch, content, villager); + String gameLang = client.options.language; + if (LanguageMap.LANGUAGE_MAP.containsKey(gameLang) && !LanguageMap.LANGUAGE_MAP.get(gameLang).isEmpty()) { + String content = Language.getInstance().get(phrase); + int tone = Math.min(TOTAL_VOICES - 1, (int) Math.floor(gene * TOTAL_VOICES)); + String voice = gender + "_" + tone; + OnlineSpeechManager.INSTANCE.play(LanguageMap.LANGUAGE_MAP.get(gameLang), voice, pitch, content, villager); + } else { + MutableText styled = (Text.translatable("command.tts_unsupported_language")).styled(s -> s + .withColor(Formatting.RED) + .withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://github.com/Luke100000/minecraft-comes-alive/wiki/TTS"))); + client.inGameHud.getChatHud().addMessage(styled); + } } else { int tone = Math.min(9, (int) Math.floor(gene * 10.0f)); Identifier sound = new Identifier("mca_voices", phrase.toLowerCase(Locale.ROOT) + "/" + gender + "_" + tone); diff --git a/common/src/main/java/net/mca/server/command/Command.java b/common/src/main/java/net/mca/server/command/Command.java index b747e24dc3..9e8e3fecd6 100644 --- a/common/src/main/java/net/mca/server/command/Command.java +++ b/common/src/main/java/net/mca/server/command/Command.java @@ -30,7 +30,6 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; -import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -60,10 +59,7 @@ public static void register(CommandDispatcher dispatcher) { .then(register("tts") .requires(p -> p.getServer().isSingleplayer()) .then(CommandManager.literal("enable").then(CommandManager.argument("enabled", BoolArgumentType.bool()).executes(Command::ttsEnable))) - .then(CommandManager.literal("language").then(CommandManager.argument("language", StringArgumentType.string()).executes(Command::ttsLanguage))) - .then(CommandManager.literal("scan").requires(p -> p.getPlayer() != null && p.getPlayer().getEntityName().contains("Player")).executes(Command::ttsScan)) - ) - ); + .then(CommandManager.literal("scan").then(CommandManager.argument("language", StringArgumentType.string()).requires(p -> p.getPlayer() != null && p.getPlayer().getEntityName().contains("Player")).executes(Command::ttsScan))))); } private static int chatAIHelp(CommandContext context) { @@ -89,19 +85,6 @@ private static int ttsEnable(CommandContext ctx) { return 0; } - private static int ttsLanguage(CommandContext ctx) { - Set languages = Set.of("en", "es", "fr", "de", "it", "pt", "pl", "tr", "ru", "nl", "cs", "ar", "zh-cn", "hu", "ko", "ja", "hi"); - String language = ctx.getArgument("language", String.class); - if (languages.contains(language)) { - Config.getInstance().onlineTTSLanguage = language; - Config.getInstance().save(); - return 0; - } else { - sendMessage(ctx, "Choose one of: " + String.join(", ", languages)); - return 1; - } - } - private static boolean couldBePersonalityRelated(String phrase) { for (Personality value : Personality.values()) { if (phrase.contains(value.name().toLowerCase(Locale.ROOT))) { @@ -116,7 +99,7 @@ private static int ttsScan(CommandContext ctx) { String key = text.getKey(); if ((key.contains("dialogue.") || key.contains("interaction.") || key.contains("villager.")) && !couldBePersonalityRelated(key)) { String hash = OnlineSpeechManager.INSTANCE.getHash(text.getValue()); - String language = Config.getInstance().onlineTTSLanguage; + String language = ctx.getArgument("language", String.class); CompletableFuture.runAsync(() -> { OnlineSpeechManager.INSTANCE.downloadAudio(language, "male_" + (SpeechManager.TOTAL_VOICES - 1), text.getValue(), hash); }); diff --git a/common/src/main/resources/assets/mca/lang/en_us.json b/common/src/main/resources/assets/mca/lang/en_us.json index 926e8184fd..19a667d398 100644 --- a/common/src/main/resources/assets/mca/lang/en_us.json +++ b/common/src/main/resources/assets/mca/lang/en_us.json @@ -679,6 +679,7 @@ "command.only_one_destiny": "You already decided your destiny.", "command.no_mail": "You have no mails.", "command.tts_busy": "(Whenever villagers remain silent, it means the text-to-speech has to generate that phrase first. It will be there next time.)", + "command.tts_unsupported_language": "Your game language is not supported by the text-to-speech. Please change it to English or disable TTS.", "blueprint.noBuilding": "You need to stand within a building", "blueprint.refreshed": "Buildings refreshed!",