diff --git a/src/main/kotlin/net/mcbrawls/packin/lang/LanguageList.kt b/src/main/kotlin/net/mcbrawls/packin/lang/LanguageList.kt new file mode 100644 index 0000000..8385ef4 --- /dev/null +++ b/src/main/kotlin/net/mcbrawls/packin/lang/LanguageList.kt @@ -0,0 +1,168 @@ +package net.mcbrawls.packin.lang + +/** + * A utility class for all of Minecraft's languages. + */ +object LanguageList { + /** + * The store of languages. + */ + private val languages: List = listOf( + "af_za", + "ar_sa", + "ast_es", + "az_az", + "ba_ru", + "bar", + "be_by", + "bg_bg", + "br_fr", + "brb", + "bs_ba", + "ca_es", + "cs_cz", + "cy_gb", + "da_dk", + "de_at", + "de_ch", + "de_de", + "el_gr", + "en_au", + "en_ca", + "en_gb", + "en_nz", + "en_pt", + "en_ud", + "en_us", + "enp", + "enws", + "eo_uy", + "es_ar", + "es_cl", + "es_ec", + "es_es", + "es_mx", + "es_uy", + "es_ve", + "esan", + "et_ee", + "eu_es", + "fa_ir", + "fi_fi", + "fil_ph", + "fo_fo", + "fr_ca", + "fr_fr", + "fra_de", + "fur_it", + "fy_nl", + "ga_ie", + "gd_gb", + "gl_es", + "haw_us", + "he_il", + "hi_in", + "hr_hr", + "hu_hu", + "hy_am", + "id_id", + "ig_ng", + "io_en", + "is_is", + "isv", + "it_it", + "ja_jp", + "jbo_en", + "ka_ge", + "kk_kz", + "kn_in", + "ko_kr", + "ksh", + "kw_gb", + "la_la", + "lb_lu", + "li_li", + "lmo", + "lol_us", + "lt_lt", + "lv_lv", + "lzh", + "mk_mk", + "mn_mn", + "ms_my", + "mt_mt", + "nah", + "nds_de", + "nl_be", + "nl_nl", + "nn_no", + "no_no", + "oc_fr", + "ovd", + "pl_pl", + "pt_br", + "pt_pt", + "qya_aa", + "ro_ro", + "rpr", + "ru_ru", + "ry_ua", + "se_no", + "sk_sk", + "sl_si", + "so_so", + "sq_al", + "sr_sp", + "sv_se", + "sxu", + "szl", + "ta_in", + "th_th", + "tl_ph", + "tlh_aa", + "tok", + "tr_tr", + "tt_ru", + "uk_ua", + "val_es", + "vec_it", + "vi_vn", + "yi_de", + "yo_ng", + "zh_cn", + "zh_hk", + "zh_tw", + "zlm_arab", + ) + + val containers = listOf( + "barrel", + "blast_furnace", + "brewing", + "cartography_table", + "chest", + "chestDouble", + "crafting", + "dispenser", + "dropper", + "enderchest", + "furnace", + "grindstone_title", + "hopper", + "inventory", + "loom", + "repair", + "shulkerBox", + "smoker", + "stonecutter", + "merchant.trades", + ).map { "container.$it" } + + fun forEachLanguage(action: (String) -> Unit) { + languages.forEach(action) + } + + fun forEachContainer(action: (String) -> Unit) { + containers.forEach(action) + } +} diff --git a/src/main/kotlin/net/mcbrawls/packin/listener/PackinResourceLoader.kt b/src/main/kotlin/net/mcbrawls/packin/listener/PackinResourceLoader.kt index 918b482..ed31ae3 100644 --- a/src/main/kotlin/net/mcbrawls/packin/listener/PackinResourceLoader.kt +++ b/src/main/kotlin/net/mcbrawls/packin/listener/PackinResourceLoader.kt @@ -10,10 +10,17 @@ import org.slf4j.LoggerFactory import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor +/** + * Loads Packin source files from Minecraft resources. + */ object PackinResourceLoader : SimpleResourceReloadListener> { - val LISTENER_ID: Identifier = Identifier.of(PackinMod.MOD_ID, "resources") val LOGGER: Logger = LoggerFactory.getLogger("PackinResourceLoader") + /** + * The unique identfiier of this reload listener. + */ + val LISTENER_ID: Identifier = Identifier.of(PackinMod.MOD_ID, "resources") + const val ROOT_PATH: String = "packin_resources" private val sourceResources: MutableList = mutableListOf() @@ -75,6 +82,19 @@ object PackinResourceLoader : SimpleResourceReloadListener resource.path == id } } + /** + * Gets all loaded resources for the given pack id and filter. + */ + fun getAll(pack: String?, filter: (Identifier) -> Boolean = { true }): Set { + val resources = if (pack == null) { + resources.toSet() + } else { + resourcesByPack[pack] ?: return emptySet() + } + + return resources.filter { filter(it.path) }.toSet() + } + override fun getFabricId(): Identifier { return LISTENER_ID } diff --git a/src/main/kotlin/net/mcbrawls/packin/resource/provider/DirectResourceProvider.kt b/src/main/kotlin/net/mcbrawls/packin/resource/provider/DirectResourceProvider.kt new file mode 100644 index 0000000..8772400 --- /dev/null +++ b/src/main/kotlin/net/mcbrawls/packin/resource/provider/DirectResourceProvider.kt @@ -0,0 +1,42 @@ +package net.mcbrawls.packin.resource.provider + +import net.mcbrawls.packin.listener.PackinResourceLoader +import net.mcbrawls.packin.resource.pack.PackinResourcePack +import net.mcbrawls.packin.resource.pack.ResourceCollector +import net.minecraft.util.Identifier + +/** + * Provides the contents of a Packin pack. + */ +class DirectResourceProvider( + /** + * A predicate to test the path of a resource to include. + */ + val pathPredicate: (Identifier) -> Boolean = { true }, + + /** + * The id of the Packin pack to provide. + */ + val packId: String? = null, +) : ResourceProvider { + constructor(paths: Set, packId: String? = null) : this(paths::contains, packId) + constructor(vararg paths: Identifier, packId: String? = null) : this(paths.toSet(), packId) + + /** + * Creates a provider which checks within a namespace against a collection of starting path predicates. + */ + constructor(namespace: String, vararg startingPaths: String, packId: String? = null) : this( + createStartingPathPredicate(namespace, *startingPaths), packId + ) + + override fun collectResources(pack: PackinResourcePack, collector: ResourceCollector) { + val allResources = PackinResourceLoader.getAll(packId, pathPredicate) + allResources.forEach(collector::collect) + } + + companion object { + fun createStartingPathPredicate(namespace: String, vararg startingPaths: String): (Identifier) -> Boolean { + return { id -> id.namespace == namespace && startingPaths.any(id.path::startsWith) } + } + } +} diff --git a/src/main/kotlin/net/mcbrawls/packin/resource/provider/LanguageProvider.kt b/src/main/kotlin/net/mcbrawls/packin/resource/provider/LanguageProvider.kt new file mode 100644 index 0000000..5a1e5ee --- /dev/null +++ b/src/main/kotlin/net/mcbrawls/packin/resource/provider/LanguageProvider.kt @@ -0,0 +1,33 @@ +package net.mcbrawls.packin.resource.provider + +import com.google.gson.JsonObject +import net.mcbrawls.packin.resource.pack.PackinResourcePack +import net.mcbrawls.packin.resource.pack.ResourceCollector +import net.minecraft.util.Identifier + +/** + * A resource provider to add a language override. + */ +class LanguageProvider( + /** + * The language code of this provider. + * For example, "minecraft:en_us". + */ + val language: Identifier, + + /** + * All translations for this provider. + */ + val translations: Map, +) : ResourceProvider { + constructor(language: Identifier, builder: MutableMap.() -> Unit) : this(language, mutableMapOf().apply(builder)) + + override fun collectResources(pack: PackinResourcePack, collector: ResourceCollector) { + val languageJson = JsonObject().apply { + translations.forEach(::addProperty) + } + + val languagePath = language.withPath { "lang/$it.json" } + collector.collect(languagePath, languageJson.toString().encodeToByteArray()) + } +} diff --git a/src/test/kotlin/net/mcbrawls/packin/test/PackinTest.kt b/src/test/kotlin/net/mcbrawls/packin/test/PackinTest.kt index d533bd4..4265bc5 100644 --- a/src/test/kotlin/net/mcbrawls/packin/test/PackinTest.kt +++ b/src/test/kotlin/net/mcbrawls/packin/test/PackinTest.kt @@ -10,9 +10,12 @@ import net.fabricmc.loader.api.FabricLoader import net.mcbrawls.packin.font.FontMetrics import net.mcbrawls.packin.font.FontMetrics.Companion.minecraftHeight import net.mcbrawls.packin.font.FontMetrics.Companion.minecraftWidth +import net.mcbrawls.packin.lang.LanguageList import net.mcbrawls.packin.resource.pack.PackMetadata import net.mcbrawls.packin.resource.pack.PackinResourcePack +import net.mcbrawls.packin.resource.provider.DirectResourceProvider import net.mcbrawls.packin.resource.provider.FontProvider +import net.mcbrawls.packin.resource.provider.LanguageProvider import net.mcbrawls.packin.resource.provider.SoundProvider import net.mcbrawls.packin.resource.provider.VanillaSoundRemovalProvider import net.minecraft.command.argument.IdentifierArgumentType @@ -21,6 +24,7 @@ import net.minecraft.text.Text import net.minecraft.util.Identifier import kotlin.io.path.Path import kotlin.io.path.writeBytes +import kotlin.math.floor import kotlin.math.round object PackinTest : ModInitializer { @@ -58,9 +62,32 @@ object PackinTest : ModInitializer { "block.lava.pop" ) ) + + LanguageList.forEachLanguage { code -> + addProvider( + LanguageProvider(Identifier.ofVanilla(code)) { + LanguageList.forEachContainer { key -> + this[key] = "" + } + + this["effect.minecraft.hunger"] = "MC Brawls" + } + ) + } + + addProvider( + LanguageProvider(Identifier.of("brawls", "en_us")) { + this["item.brawls.rocket_launcher"] = "Rocket Launcher" + } + ) + + addProvider(DirectResourceProvider("packin-test:brawls", Identifier.DEFAULT_NAMESPACE, "textures/")) + addProvider(DirectResourceProvider(Identifier.ofVanilla("models/item/template_skull.json"))) + // addProvider(PackResourceProvider(packId = "packin-test:mcc")) }.createZip() val path = Path("out.zip") path.writeBytes(packBytes) + context.source.sendFeedback({ Text.literal("Output pack: ~${floor(packBytes.size / 1024.0).toInt()}KB") }, true) }.exceptionOrNull()?.printStackTrace() 1 }