Skip to content

Minecraft资源包/数据包构建工具

古镇天Gugle@XeKr-Dev(gugle@xekr.dev)

摘要

本项目是一个基于Web的模块化Minecraft资源包/数据包构建工具,通过创新性的纯前端架构解决了传统资源包开发中的模块复用、版本兼容和分发效率问题。 系统采用Vue3 + TypeScript + Vite技术栈,利用GitHub API实时获取仓库资源,通过智能版本适配引擎(PathFormatter和RecipeFormatter) 自动转换不同Minecraft版本的资源格式, 支持用户自定义模块组合和预设合集选择。核心构建器采用抽象工厂模式(AbstractBuilder) 和权重排序算法解决模块冲突问题,支持模块绑定、互斥检测和递归依赖管理,并可将资源包打包为Fabric/Quilt/Forge/NeoForge模组格式。 项目采用双构建器模式(OnlineBuilder和FileBuilder)分别支持在线和离线构建场景,提供了标准化项目模板和配置文件格式, 显著降低了资源包开发门槛,促进了Minecraft社区的协作与创新。

关键词

Minecraft资源包构建、Minecraft数据包构建、模块化架构、版本适配系统、前端构建引擎、GitHub集成、Zip打包、社区协作

Minecraft Pack Builder

Abstract

This project is a web-based modular Minecraft Pack Builder that addresses the issues of module reuse, version compatibility, and distribution efficiency in traditional resource pack development through an innovative pure front-end architecture. Built with Vue3 + TypeScript + Vite stack, the system utilizes the GitHub API to fetch repository resources in real-time, automatically converting resource formats across different Minecraft versions via an intelligent version adaptation engine (PathFormatter and RecipeFormatter), and supporting user-customized module composition and preset collections. The core builder employs a weighted sorting algorithm to resolve module conflicts, supports module bindings and mutual exclusion detection, and can package resource packs into Fabric/Quilt/Forge/NeoForge mod formats. The project provides standardized project templates and configuration file formats, significantly lowering the barrier to entry for resource pack development and fostering community collaboration.

Key words:

Minecraft Resource Pack Building, Minecraft Data Pack Building, Modular Architecture, Version Adaptation System, Front-end Build Engine, GitHub API Integration, JSZip Packaging, Abstract Factory Pattern, Weight-based Module Merging, Community Collaboration

体验

仓库地址

体验项目

一、引言

Minecraft(我的世界)作为一款风靡全球的沙盒游戏,其可扩展性通过资源包(Resource Pack)和数据包(Data Pack)得到极大增强。 资源包用于修改游戏的纹理、声音和模型等资源,而数据包则用于修改游戏逻辑、添加进度和配方等。然而,随着资源包和数据包的功能日益复杂, 其构建和管理过程也变得繁琐。特别是当开发者希望提供多个可选模块供用户自定义时,手动合并模块并确保兼容性成为一项挑战。

Minecraft资源包/数据包构建工具是一个基于Web的前端应用,旨在解决Minecraft社区中资源包和数据包开发与分发的痛点问题。传统资源包开发面临以下挑战:

  • 模块化不足:资源包通常作为整体分发,用户无法按需选择功能模块
  • 版本兼容性:不同Minecraft版本需要不同的资源格式
  • 分发效率低:开发者需要手动打包不同配置的资源包

本项目通过创新的模块化架构和自动化构建流程,实现了:

  • 用户自定义选择:允许用户自由组合所需模块
  • 智能版本适配:自动转换资源格式以适应目标版本
  • 云端构建系统:基于GitHub API实现一键式打包分发
  • 开源协作模式:标准化项目结构促进社区贡献

二、详细解读

1. 系统架构

mermaid
graph TD
    A[用户界面] --> B[配置加载]
    B --> C[模块选择]
    C --> D[版本适配]
    D --> E[构建引擎]
    E --> F[ZIP生成]
    F --> G[下载]

2. 项目结构

项目采用Vue3作为前端框架,使用TypeScript进行类型安全开发,Vite作为构建工具,主要代码位于src目录下:

核心目录结构:

  • src/components:UI组件层
    • FileSelectorDialog.vue:文件选择对话框(用于file_mode本地构建)
    • FakeProgress.vue:伪进度条(提供构建过程视觉反馈)
    • MarkdownView.vue:Markdown渲染器(展示仓库README)
    • Notice.vue:通知组件
    • PageHeader.vue:页面头部组件
  • src/pages:页面层
    • HomePage.vue:主页面,实现核心用户交互逻辑(555行)
  • src/scripts:核心业务逻辑层
    • builder:构建器模块(抽象工厂模式实现)
      • impl/index.ts:AbstractBuilder抽象基类(407行,定义核心构建流程)
      • impl/online.ts:OnlineBuilder在线构建器(通过GitHub API递归获取文件树)
      • impl/file.ts:FileBuilder本地构建器(从用户上传的ZIP文件构建)
      • index.ts:Builder工厂类(统一构建入口)
    • formatter:格式转换器模块
      • impl/path.ts:PathFormatter路径转换器(处理data/assets目录结构变化)
      • impl/recipe.ts:RecipeFormatter配方转换器(234行,处理三代配方格式演进)
      • index.ts:导出统一接口
    • github/index.ts:GithubAPI封装(支持代理切换,含4个代理池)
    • message/index.ts:消息提示系统(基于Arco Design)
    • request/index.ts:HTTP请求封装(基于Axios,支持GitHub PAT认证)
    • type/index.ts:TypeScript类型定义(ConfigJson、ModuleConfigJson等核心接口)
    • util/index.ts:工具函数(Base64编解码、图片放大等)
    • version/index.ts:Minecraft版本比较工具

配置文件:

  • config.json:资源包基本信息(名称、作者、版本、主模块、版本模块等)
  • module.config.json:模块配置(模块名、权重、互斥关系、绑定关系)
  • *.set.config.json:预设合集配置

技术栈:

  • 核心框架:Vue3(v3.5.17) + TypeScript(v5.8.3) + Vite(v7.0.0)
  • UI组件库:Arco Design(v2.57.0)
  • HTTP客户端:Axios(v1.10.0,支持GitHub API认证)
  • ZIP处理:JSZip(v3.10.1,客户端压缩打包)
  • Markdown渲染:Marked(v16.0.0) + DOMPurify(v3.2.6,XSS防护)
  • 文件下载:FileSaver(v2.0.5)
  • 样式预处理:Sass(v1.89.2)
  • 代码规范:ESLint(v9.30.0) + Prettier(v3.6.2)
  • 许可证:AGPL-3.0-or-later

3. 核心功能实现

(1) 配置解析

工具首先加载并解析仓库根目录的config.json,获取资源包/数据包的基本配置,包括主模块路径、版本模块映射等。

(2) 模块选择与权重排序

用户可通过两种方式选择模块:

  1. 直接选择:从模块列表中勾选所需模块
  2. 合集选择:选择作者预设的模块组合

智能依赖处理:

  • 模块互斥(breaks):双向冲突检测,自动禁用不兼容选项
  • 模块绑定(bindings):递归依赖管理,自动选中传递依赖
  • 权重排序:模块按weight值从小到大排序,高权重模块覆盖低权重模块的同名文件

核心算法实现(HomePage.vue第246-285行):

typescript
// 检查模块是否因冲突被禁用(双向检测)
function checkModuleDisabled(key: string) {
    const basePath = Builder.getBasePath(status.config!)
    const self = status.modules.get(key)
    if (self == undefined) return true
    // 正向检测:检查当前模块是否与已选模块冲突
    for (const subKey of status.selectedModules) {
        for (let breakKey of self.breaks) {
            breakKey = `${basePath}/${breakKey}`
            if (subKey == breakKey) return true
        }
        // 反向检测:检查已选模块是否与当前模块冲突
        const sub = status.modules.get(subKey)
        if (sub == undefined) continue
        for (const breakKey of sub.breaks) {
            if (`${basePath}/${breakKey}` == key) return true
        }
    }
    // 递归检查绑定模块是否可用(传递依赖)
    if (self.bindings) {
        for (let binding of self.bindings) {
            binding = `${basePath}/${binding}`
            if (!binding || binding == key) return true
            if (checkModuleDisabled(binding)) return true // 递归检测
        }
    }
    return false
}

// 递归选择绑定的模块(深度优先遍历)
function selectWithBindings(key: string) {
    const basePath = Builder.getBasePath(status.config!)
    const self = status.modules.get(key)
    if (self == undefined) return
    if (!status.selectedModules.includes(key)) {
        status.selectedModules.push(key)
    }
    if (self.bindings) {
        for (let binding of self.bindings) {
            binding = `${basePath}/${binding}`
            if (!binding || binding == key) return
            selectWithBindings(binding) // 递归选择依赖
        }
    }
}

(3) 构建流程

构建流程由AbstractBuilder.build方法实现,采用异步Promise链式处理:

1. 版本信息确定

typescript
const minecraftVersion = mcVersions[this.version]
const packFormat = this.type === "data"
    ? minecraftVersion.datapack_version
    : minecraftVersion.resources_version

2. 生成pack.mcmeta元数据

typescript
const metaJson: MetaJson = {
    pack: {
        description: [{text: `§6§l${this.config.description} v${this.config.version}\n`}],
        // 根据版本使用pack_format(旧)或min_format/max_format(新)
    }
}

3. 加载主模块

typescript
this.getFileTree(`${basePath}/${this.config.main_module}`).then(res => {
    let pack: FileOrTree = res
    // 注入或更新pack.mcmeta
})

4. 处理版本模块

typescript
// noinspection JSAnnotator

if (this.config.version_modules) {
    // 版本比较,选择最合适的版本模块
    if (Version.compareMC(this.version, versionModule.version) < 0) continue
    if (strict && Version.compareMC(...) !== 0) continue
    // 版本模块可覆盖主模块或其他模块
}

5. 合并选中的模块(按权重排序)

typescript
moduleList = moduleList.sort((a, b) => a.weight - b.weight)
for (let module of moduleList) {
    pack = this.mergeFileOrTree(pack, module.files!!)
    // 应用该模块的版本模块(如果有)
}

6. 文件树合并算法(深度优先递归)

typescript
class AbstractBuilder {
    public mergeFileOrTree(file1: FileOrTree, file2: FileOrTree): FileOrTree {
        if (file1.children === undefined || file2.children === undefined) {
            throw new Error("file1 or file2 is not a tree")
        }
        const file: FileOrTree = {path: file2.path}
        file.children = file1.children
        // 遍历file2的所有子节点
        for (let child of file2.children) {
            let contain = false
            // 查找file1中是否存在同名节点
            for (let child1 of file.children) {
                if (child1.path == child.path) {
                    // 情况1:文件节点,直接覆盖内容
                    if (child1.content !== undefined && child.content !== undefined) {
                        child1.content = child.content
                        contain = true
                        break
                    }
                    // 情况2:目录节点,递归合并子树
                    if (child1.children !== undefined && child.children !== undefined) {
                        const merged = this.mergeFileOrTree(child, child1)
                        child1.children = merged.children
                        contain = true
                        break
                    }
                }
            }
            // 情况3:file1中不存在该节点,直接添加
            if (contain) continue
            file.children.push(child)
        }
        return file
    }
}

7. 内容预处理与格式转换(AbstractBuilder第126-137行)

typescript
class AbstractBuilder {
    public preprocessContent(content: string, path: string) {
        const pathSplit = path.split("/")
        const type = pathSplit[2] // 提取资源类型(如recipe/recipes)
        if (!type) return content
        // 仅对配方文件进行格式转换
        if (type === "recipe" || type === "recipes") {
            content = RecipeFormatter.format(content, this.minecraftVersion)
        }
        return content
    }
}

8. ZIP文件生成(AbstractBuilder第398-401行)

typescript
// 创建JSZip实例
const zip: JSZip = new JSZip()
// 递归将文件树添加到ZIP(根据type过滤data/assets)
this.fileTreeToZip(zip, pack)
// 模组模式:额外生成模组元数据文件
if (this.mod) this.buildModZip(zip)
// 异步生成Blob对象(用于浏览器下载)
zip.generateAsync({type: "blob"}).then(blob => resolve(blob))

9. 模组格式支持(AbstractBuilder第185-263行)

typescript
class AbstractBuilder {
    public buildModZip(zip: JSZip) {
        const modID = this.config.pack_name.toLowerCase().replace(/[^a-z0-9]/g, '_')
        const license = this.config.license ?? 'All Right Reserved'

        // Forge模组配置(lowcodefml加载器)
        const modsToml = `
modLoader = "lowcodefml"
loaderVersion = "[25,)"
license="${license}"
[[mods]]
modId = "${modID}"
version = "${this.config.version}"
displayName = "${this.config.pack_name}"
description = "${this.config.description}"
logoFile = "pack.png"
authors = "${this.config.author}"`

        // NeoForge模组配置(javafml加载器)
        const neoForgeModsToml = `
modLoader = "javafml"
loaderVersion = "[1,)"
...`

        // Fabric模组配置(依赖fabric-resource-loader-v0)
        const fabricModJson = {
            id: modID,
            version: this.config.version,
            environment: "*",
            depends: {"fabric-resource-loader-v0": "*"}
        }

        // Quilt模组配置(依赖quilt_resource_loader)
        const quiltModJson = {
            quilt_loader: {
                depends: [{
                    id: "quilt_resource_loader",
                    versions: "*",
                    unless: "fabric-resource-loader-v0"
                }]
            }
        }

        // 写入文件
        zip.folder("META-INF")
        zip.file("META-INF/mods.toml", modsToml)
        zip.file("META-INF/neoforge.mods.toml", neoForgeModsToml)
        this.fileToZip(zip, utob64(JSON.stringify(fabricModJson, null, 4)), "fabric.mod.json")
        this.fileToZip(zip, utob64(JSON.stringify(quiltModJson, null, 4)), "quilt.mod.json")
    }
}

构建器模式:

系统采用抽象工厂模式实现双构建器:

  • AbstractBuilder(抽象基类,407行):
    • 定义核心构建流程:build()方法(265-405行)
    • 实现文件树合并:mergeFileOrTree()(95-124行)
    • 实现内容预处理:preprocessContent()(126-137行)
    • 实现模组打包:buildModZip()(185-263行)
  • OnlineBuilder(在线构建器,45行):
    • 继承AbstractBuilder
    • 通过GithubAPI.getRepoContents()递归获取文件树(第6-44行)
    • 支持GitHub代理模式(从4个代理池随机选择)
  • FileBuilder(本地构建器,80行):
    • 继承AbstractBuilder
    • 从用户上传的ZIP文件构建(基于JSZip)
    • 支持私有仓库和离线场景

(4) 版本适配系统

版本数据库(minecraft_version.json)

json
{
  "1.21.7": {
    "type": "release",
    "datapack_version": 69,
    "resources_version": 46
  }
}

PathFormatter - 路径格式转换器

不同Minecraft版本对数据包路径命名有变化,如1.21(pack_format 45)后:

typescript
PathFormatter.dataPathMap.set(45, [
    {from: "structures", to: "structure"},
    {from: "advancements", to: "advancement"},
    {from: "recipes", to: "recipe"},
    {from: "loot_tables", to: "loot_table"},
    {from: "predicates", to: "predicate"},
    {from: "item_modifiers", to: "item_modifier"},
    {from: "functions", to: "function"}
])

转换逻辑:

typescript
class PathFormatter {
    public static format(path: string, version): string {
        const pathSplit = path.split("/")
        if (version.datapack_version >= 45) {
            // structures -> structure
        } else {
            // structure -> structures (反向转换)
        }
    }
}

RecipeFormatter - 配方格式转换器

Minecraft配方格式经历三次重大变更:

  1. 24w10a前 (datapack_version < 34):

    json
    {
      "result": {
        "item": "minecraft:diamond",
        "count": 1
      }
    }
  2. 24w10a-24w33a (34 ≤ datapack_version < 49):

    json
    {
      "result": {
        "id": "minecraft:diamond",
        "count": 1
      }
    }
  3. 24w33a后 (datapack_version ≥ 49):

    json5
    {
      "key": {
        "#": "#minecraft:diamond" // tag简化为#标记
      },
      "ingredient": "minecraft:stick", // 直接使用字符串
      "result": {
        "id": "minecraft:diamond",
        "count": 1
      }
    }

转换器自动检测并转换:

typescript
class RecipeFormatter {
    // 核心转换入口(第217-233行)
    public static format(content: string, version): string {
        let recipe: Recipe = JSON.parse(b64tou(content))
        if (version.datapack_version >= 49) {
            recipe = RecipeFormatter.toMore24w33a(recipe)      // →最新格式
        } else if (version.datapack_version >= 34) {
            recipe = RecipeFormatter.toBetween24w10aTo24w33a(recipe) // →中间格式
        } else {
            recipe = RecipeFormatter.toLess24w10a(recipe)      // →旧格式
        }
        return utob64(JSON.stringify(recipe, null, 4))
    }

    // 转换链:任意格式→24w33a+→24w10a-24w33a→24w10a前
    // 保证任意版本间的兼容性转换
}

(5) GitHub API集成

API封装(src/scripts/github/index.ts,31行):

typescript
// noinspection JSAnnotator

export class GithubAPI {
    // 代理池:随机选择4个GitHub镜像之一
    public static readonly proxies: string[] = [
        "https://gh.llkk.cc/",
        "https://gh-proxy.top/",
        "https://cdn.gh-proxy.org/",
        "https://gh-proxy.org/"
    ]
    public static readonly proxy: string = GithubAPI.proxies[Math.floor(Math.random() * GithubAPI.proxies.length)]

    // 获取仓库信息
    static async getRepoInfo(repo: string, proxy: boolean = false)

    // 获取仓库内容(文件/目录)
    static async getRepoContents(repo: string, path: string = "", proxy: boolean = false)

    // 获取README文件
    static async getRepoReadme(repo: string, proxy: boolean = false)

    // 下载仓库ZIP包(用于file_mode)
    static getRepoZip(repo: string, _branch: string = "", proxy: boolean = false)
}

认证机制:(基于Request模块)

  • 未认证用户:60请求/小时(GitHub API限制)
  • Personal Access Token:5000请求/小时
  • 所需权限:public_reporead:project
  • 存储方式:localStorage(纯前端,无后端,保护隐私)
  • 请求头:Authorization: token ${PAT}

数据获取流程:

  1. 加载config.json获取基本配置
  2. 递归获取模块目录下的module.config.json
  3. 加载sets_path下的合集配置
  4. 加载README.md用于展示
  5. 构建时递归获取文件树(OnlineBuilder)

在线/离线构建模式:

  • online模式(默认):
    • 使用OnlineBuilder实时从GitHub API获取文件
    • 适用于公开仓库
    • 支持代理模式(HomePage.vue第40-45行,localStorage持久化)
  • file模式:
    • 使用FileBuilder从用户上传的ZIP构建
    • 适用于私有仓库或网络受限环境
    • 配置:config.json中设置file_mode: true
    • 流程:点击构建→下载ZIP→上传ZIP→本地构建(HomePage.vue第338-380行)

4. 关键技术点

1. 抽象工厂模式(Builder模块)

  • 设计模式:AbstractBuilder抽象基类定义构建流程,OnlineBuilder和FileBuilder实现具体获取逻辑
  • 优势:
    • 将构建逻辑与数据源解耦,便于扩展(AbstractBuilder第54-406行)
    • 代码复用:核心流程在AbstractBuilder中实现,子类仅需实现getFileTree()
    • 易于测试:可单独测试合并、转换逻辑,无需依赖网络

2. 策略模式(Formatter模块)

  • 设计模式:PathFormatter和RecipeFormatter封装不同的转换策略
  • 优势:
    • 版本适配逻辑隔离,不污染构建器代码
    • 易于添加新版本支持:仅需修改Formatter
    • 静态方法设计,无需实例化,降低内存开销

3. 反应式状态管理(HomePage.vue)

  • 设计模式:Vue3 Composition API + reactive状态对象(HomePage.vue第72-91行)

  • 优势:

    • 自动UI更新:状态变化自动触发视图重渲染
    • 集中式状态:所有状态在status对象中统一管理
    • 简化逻辑:避免手动DOM操作和事件监听
  • 主模块 + 可选模块 + 版本模块的三层结构

  • 每个模块独立开发和维护,支持热插拔

  • 模块配置标准化(module.config.json)

2. 智能版本适配系统

  • 双层版本控制:数据包版本(datapack_version)和资源包版本(resources_version)独立管理
  • 版本模块系统:为不同Minecraft版本提供差异化内容
    • strict模式:严格版本匹配
    • 非strict:向后兼容(选择≤目标版本的最新版本模块)
    • version_reverse:支持反向版本排序
  • 格式自动转换:PathFormatter和RecipeFormatter无缝转换资源格式

3. 冲突检测与依赖管理

  • 互斥关系(breaks):声明不兼容模块,UI自动禁用冲突选项
  • 绑定关系(bindings):自动选择依赖模块
  • 权重系统(weight):细粒度控制文件覆盖优先级

4. 双构建器模式

  • OnlineBuilder:GitHub API实时构建,适用于公开仓库
  • FileBuilder:本地ZIP构建,支持私有仓库和离线场景
  • 统一接口设计(AbstractBuilder抽象类)

5. 跨平台模组支持

  • 一键打包为Fabric/Quilt/Forge/NeoForge模组
  • 自动生成模组元数据文件:
    • fabric.mod.json(Fabric)
    • quilt.mod.json(Quilt)
    • META-INF/mods.toml(Forge)
    • META-INF/neoforge.mods.toml(NeoForge)

6. 纯前端架构

  • 无需服务器,静态部署即可运行
  • 数据安全:PAT存储在用户本地浏览器
  • JSZip实现客户端ZIP打包

7. 用户体验优化

  • URL路由记忆仓库地址(/#/owner/repo)
  • 伪进度条提供构建反馈
  • Markdown渲染README展示项目说明
  • 版本选择支持快照版本过滤

5. 完整工作流程

阶段一:仓库加载

  1. 用户输入GitHub仓库URL(如https://github.com/XeKr-Dev/minecraft-pack-template)
  2. 点击"加载"按钮,触发loadRepo()
  3. 解析仓库地址,更新URL路由(/#/XeKr-Dev/minecraft-pack-template)
  4. 并行请求:
    • config.json:获取基本配置
    • README.md:获取项目说明
    • 图标文件:加载并放大处理(imageMagnify)
  5. 递归加载所有模块的module.config.json
  6. 加载sets_path下的所有合集配置

阶段二:用户配置

  1. 选择模块:
    • 直接勾选模块列表
    • 或选择预设合集(自动填充模块)
  2. 实时冲突检测:
    • 禁用与已选模块互斥的选项
    • 自动选中绑定的依赖模块
  3. 选择目标Minecraft版本:
    • 支持快照版本显示切换
    • 显示对应的数据包/资源包格式版本号
  4. 选择构建类型:
    • "全部":同时包含资源包和数据包
    • "资源包":仅包含assets/
    • "数据包":仅包含data/
  5. 可选:勾选"构建模组"生成Fabric/Quilt/Forge/NeoForge兼容格式

阶段三:构建过程

  1. 点击"构建"按钮,触发build()
  2. 构建器初始化:
    • 确定使用OnlineBuilder或FileBuilder
    • 获取目标版本的pack_format信息
  3. 文件获取:
    • 加载主模块文件树
    • 根据目标版本选择并加载版本模块
    • 按权重排序加载用户选中的模块
  4. 内容处理:
    • 路径格式转换(PathFormatter)
    • 配方格式转换(RecipeFormatter)
    • 文件树递归合并(高权重覆盖低权重)
  5. 元数据生成:
    • 注入或更新pack.mcmeta
    • 添加pack.png图标
    • (模组模式)生成模组配置文件
  6. ZIP打包:
    • JSZip递归添加文件
    • 根据构建类型过滤目录
    • 生成Blob对象

阶段四:交付下载

  1. 使用FileSaver.js触发浏览器下载
  2. 文件命名格式:{pack_name}-{version}-{type}-mc{minecraft_version}.{jar|zip}
  3. 示例:BetterTools-1.0.0-all-mc1.21.7.zip

三、用例

用例1:创建一个名为“BetterTools”的资源包

场景:开发者创建了一个资源包,并希望将工具材质从原版材质替换为金质材质或钻石材质。

  • 假设开发者“XeKr”创建了一个名为“BetterTools”的资源包,该资源包包含以下模块:

    • main:主模块,包含基础纹理。
    • gold:将工具纹理替换为金质。
    • diamond:将工具纹理替换为钻石质。
  • 用户希望同时使用金质和钻石质纹理,但钻石质模块应覆盖金质模块(即钻石质工具优先)。开发者配置如下:

    1. config.json:

      json
      { 
          "pack_name": "BetterTools", 
          "author": "XeKr", 
          "description":"Better tools texture", 
          "version": "1.0.0", 
          "base_path": "./src", 
          "main_module": "main", 
          "icon": "./icon.png"
      }
    2. module.config.json(位于gold模块内):

      json
      { 
          "module_name": "gold", 
          "support_version": "*", 
          "weight": 0 
      }
    3. module.config.json(位于diamond模块内):

      json
      { 
          "module_name": "diamond", 
          "support_version": "*", 
          "weight": 1 
      }

用户操作步骤:

  1. 在工具界面输入仓库地址:https://github.com/XeKr-Dev/BetterTools
  2. 加载配置后,选择golddiamond模块(注意:由于钻石模块权重更高,它将覆盖金质模块的纹理)。
  3. 选择目标Minecraft版本(如1.20.1)。
  4. 点击“构建”按钮,工具将生成一个资源包ZIP文件。 生成的文件中,钻石质工具的纹理将覆盖金质工具的纹理,最终效果为钻石质工具。

用例2:用户自定义资源包

场景:玩家想要创建包含高清材质动态光影但不包含真实物理的资源包

  1. 访问构建器页面
  2. 输入资源包仓库URL
  3. 加载配置后,勾选高清材质动态光影模块,不勾选真实物理模块
  4. 选择Minecraft 1.20.1版本
  5. 点击构建按钮
  6. 获取定制化资源包ZIP

用例3:开发者维护多版本支持

场景:开发者需要为1.191.20提供兼容的资源包

  1. 创建version_1.19和version_1.20模块
  2. 在config.json中配置版本映射
    json
    {
      "version_modules": {
        "1.19": {"module": "version_1.19", "strict": false},
        "1.20": {"module": "version_1.20", "strict": true}
      }
    }

3.用户选择版本时自动加载对应模块

用例4:社区模块共享

场景:社区开发者贡献新模型模块

  1. 在仓库中创建new_creatures目录
  2. 添加module.config.json:
    json
    {
      "module_name": "fantasy_creatures",
      "description": "添加奇幻模型",
      "support_version": "*",
      "weight": 5,
      "breaks": ["realistic_physics"]
    }
  3. 用户即可在构建器中看到并选择该模块

5. 关键设计模式

1. 抽象工厂模式(Builder模块)

  • 设计模式:AbstractBuilder抽象基类定义构建流程,OnlineBuilder和FileBuilder实现具体获取逻辑
  • 优势:
    • 将构建逻辑与数据源解耦,便于扩展(AbstractBuilder第54-406行)
    • 代码复用:核心流程在AbstractBuilder中实现,子类仅需实现getFileTree()
    • 易于测试:可单独测试合并、转换逻辑,无需依赖网络

2. 策略模式(Formatter模块)

  • 设计模式:PathFormatter和RecipeFormatter封装不同的转换策略
  • 优势:
    • 版本适配逻辑隔离,不污染构建器代码
    • 易于添加新版本支持:仅需修改Formatter
    • 静态方法设计,无需实例化,降低内存开销

3. 响应式状态管理(HomePage.vue)

  • 设计模式:Vue3 Composition API + reactive状态对象(HomePage.vue第72-91行)
  • 优势:
    • 自动UI更新:状态变化自动触发视图重渲染
    • 集中式状态:所有状态在status对象中统一管理
    • 简化逻辑:避免手动DOM操作和事件监听

4. 依赖注入模式

  • GitHub API封装:GithubAPI静态类提供统一接口,内部处理认证和代理
  • Request模块:封装Axios,自动添加GitHub PAT认证头
  • 优势:便于单元测试(可模拟API响应)和Mock测试

四、创新点

1. 三层模块化覆盖系统

  • 主模块提供基础内容
  • 版本模块提供版本差异化适配
  • 可选模块提供功能扩展
  • 权重机制实现精细化文件覆盖控制

2. 智能版本适配引擎

  • 自动化格式转换:
    • PathFormatter自动处理pack_format 45+的路径变化(复数↔单数双向转换)
    • RecipeFormatter实现三代配方格式的链式转换(保证任意版本间兼容)
  • 版本智能匹配:
    • 非严格模式:自动选择≤目标版本的最新版本模块(AbstractBuilder第360-361行)
    • 严格模式(配置strict: true):版本必须完全匹配(AbstractBuilder第361行)
    • 反向排序(配置version_reverse: true):支持旧版本在前的排序逻辑
  • 双版本系统:
    • datapack_version:1-69+,每个快照版都可能变化
    • resources_version:1-46+,资源包版本独立管理
    • 根据构建类型自动选择对应的pack_format(AbstractBuilder第268行)
  • 支持版本跨度:
    • minecraft_version.json包含200+版本信息(从远古版本到1.21.11+)
    • 支持release和snapshot两种版本类型
    • UI可切换显示/隐藏快照版本(HomePage.vue第456-467行)

3. 纯前端零服务架构

  • 完全静态部署:无需后端服务器,降低运维成本
  • 数据隐私保护:GitHub PAT存储于用户本地浏览器
  • 客户端构建:JSZip实现浏览器内ZIP打包
  • 实时构建:直接从GitHub仓库拉取最新内容

4. 依赖关系图谱系统

  • 互斥检测(breaks):自动禁用冲突模块
  • 依赖绑定(bindings):自动选择依赖项
  • UI实时反馈:视觉化显示模块可用状态

5. 多平台模组一键打包

  • 支持Fabric、Quilt、Forge、NeoForge四大模组加载器
  • 自动生成对应元数据文件
  • 单一资源包同时兼容原版和模组环境

6. 标准化开源协作模式

  • 项目模板仓库:minecraft-pack-template提供开箱即用的项目结构
  • 配置文件标准化:
    • config.json:12个字段定义资源包基本信息(TypeScript接口定义)
    • module.config.json:6个字段定义模块属性(权重、互斥、绑定)
    • *.set.config.json:3个字段定义预设合集
  • 降低贡献门槛:
    • 无需编程知识,仅需编辑JSON配置
    • 支持Fork模板仓库后直接修改内容
  • 去中心化分发:
    • 通过GitHub实现版本控制和协作
    • 用户直接输入仓库URL即可使用
    • 支持多人协作Pull Request模式

7. 双构建模式支持

  • online模式:
    • OnlineBuilder递归调用GitHub API获取文件树
    • 适用于公开仓库,实时获取最新内容
    • 支持代理模式:从4个国内镜像随机选择,解决网络访问问题
  • file模式:
    • FileBuilder从用户上传的ZIP解析文件树
    • 支持私有仓库和完全离线环境
    • ZIP处理:自动移除根目录(仓库名前缀)(HomePage.vue第348-356行)
  • 统一接口:AbstractBuilder定义抽象方法,两种模式使用相同的构建流程

8. 渐进式用户体验

  • URL路由记忆:
    • 仓库加载后自动更新URL为/#/owner/repo(HomePage.vue第133行)
    • 支持直接分享链接,打开后自动加载指定仓库
  • 伪进度条:
    • FakeProgress组件模拟构建过程(0%→90%动画)
    • 实际完成后瞬间跳转100%,提供视觉反馈
  • Markdown渲染:
    • MarkdownView组件集成Marked + DOMPurify
    • 直接展示仓库README,无需跳转GitHub页面
  • 建议版本自动预选:
    • config.json中配置suggested_version字段
    • 加载仓库后自动选中建议版本(HomePage.vue第137行)
  • 代理状态持久化:
    • localStorage保存用户的代理选择(HomePage.vue第39-49行)
    • 下次访问自动恢复设置

五、技术亮点与性能优化

1. 异步并发处理

系统在多个关键节点采用Promise.all()并发处理,显著提升性能:

typescript
// 场景1:并发加载所有模块(HomePage.vue第134-152行)
const promises: Promise<any>[] = []
promises.push(loadModules())
promises.push(loadSets())
Promise.all(promises).then(() => {
    status.loaded = true
})
typescript
// 场景2:并发获取所有模块文件树(AbstractBuilder第303-307行)
const promises: Promise<any>[] = []
for (let module of moduleList) {
    const promise = this.getFileTree(module.path, proxy).then(tree => module.files = tree)
    promises.push(promise)
}
Promise.all(promises).then(() => { /* 合并处理 */
})
typescript
// 场景3:并发加载版本模块和图标(AbstractBuilder第371-383行)
for (const versionModuleKey in versionModuleMap) {
    const promise = this.getFileTree(versionModule.path, proxy).then(res => versionModule.files = res)
    promises.push(promise)
}
if (this.config.icon) {
    const promise = this.getFileTree(this.config.icon, proxy).then(icon => {
        icon.path = "pack.png"
        pack.children?.push(icon)
    })
    promises.push(promise)
}

并发加载所有模块文件树,相比串行加载可减少60%-80%的网络等待时间。

2. 懒加载与按需获取

  • 懒加载策略:
    • 仓库加载时仅获取config.jsonmodule.config.json(元数据)
    • 文件内容仅在点击"构建"时才获取(HomePage.vue第287-336行)
    • 避免不必要的网络请求,节省API配额
  • 按需过滤:
    • 构建"资源包"时跳过data/目录(OnlineBuilder第28-30行)
    • 构建"数据包"时跳过assets/目录(OnlineBuilder第31-33行)
    • 在文件树递归过程中提前过滤,减少约50%的API调用

3. Base64编码优化

GitHub API返回的文件内容为Base64编码,系统采用高效解码策略:

typescript
class AbstractBuilder {
    // Base64解码优化(第141-149行)
    public fileToZip(zip: JSZip, b64: string, path: string) {
        const cleanBase64 = b64.replace(/\s+/g, '') // 清理空白字符(减小内存占用)
        const binaryString = atob(cleanBase64)      // 浏览器原生Base64解码
        const buffer = new ArrayBuffer(binaryString.length)
        const bytes = new Uint8Array(buffer)        // 高效二进制转换
        for (let i = 0; i < binaryString.length; i++) {
            bytes[i] = binaryString.charCodeAt(i)
        }
        zip.file(path, buffer) // 直接传入ArrayBuffer,避免字符串中转
    }
}

4. 递归树结构处理

  • 文件树结构:FileOrTree接口采用递归定义
    typescript
    interface FileOrTree {
        path: string
        content?: string      // 文件节点
        children?: FileOrTree[] // 目录节点(递归)
    }
  • 深度优先遍历:
    • mergeFileOrTree()采用DFS合并策略,O(n)时间复杂度(AbstractBuilder第95-124行)
    • fileTreeToZip()递归遍历文件树生成ZIP(AbstractBuilder第152-175行)
  • 路径处理优化:
    • processPath()统一处理相对路径和绝对路径(AbstractBuilder第82-93行)
    • 缓存basePath避免重复计算(AbstractBuilder第78行)

5. 版本智能缓存

typescript
class AbstractBuilder {
    // 版本信息在构造函数中缓存(第62-79行)
    public constructor(/* ... */) {
        this.minecraftVersion = mcVersions[this.version] // 缓存版本对象
        this.basePath = this.getBasePath()               // 缓存基础路径
    }

    // 避免在循环中重复查询
    public preprocessContent(content: string, path: string) {
        // 直接使用this.minecraftVersion,无需每次查询mcVersions
        return RecipeFormatter.format(content, this.minecraftVersion)
    }
}

6. 内存优化策略

  • 流式ZIP生成:JSZip采用流式API,大文件不会全部加载到内存
  • Blob异步生成:zip.generateAsync({type: "blob"})异步处理,避免阻塞UI线程
  • 模块权重排序:构建前一次性排序(O(n log n)),避免每次合并时排序(AbstractBuilder第308行)
  • 事件监听清理:Vue组件卸载时自动清理状态,防止内存泄漏

六、应用场景

1. 资源包开发者

  • 提供多个可选材质模块,让玩家自由组合
  • 维护多版本兼容,自动适配目标版本
  • 示例:PvP材质包(低火、短剑、清爽界面等可选模块)

2. 数据包开发者

  • 模块化游戏机制(如RPG系统、技能树、经济系统)
  • 玩家可按需选择功能模块
  • 示例:小游戏合集(空岛生存、跑酷、PvP竞技场等)

3. 整合包制作者

  • 快速定制符合整合包主题的资源包
  • 批量生成不同配置的资源包分发给玩家

结论

本项目通过创新的纯前端架构和模块化设计,为Minecraft资源包/数据包开发提供了一套完整的工具链解决方案。核心技术贡献包括:

1. 架构创新

  • 抽象工厂模式的构建器系统:AbstractBuilder(407行)定义核心流程,OnlineBuilder和FileBuilder实现双模式支持
  • 三层模块化覆盖系统:主模块+版本模块+可选模块的灵活组合,权重机制实现精细化文件覆盖控制
  • 零服务器架构:完全静态部署,GitHub PAT本地存储,JSZip浏览器内打包,降低运维成本并保护用户隐私

2. 技术突破

  • 智能版本适配引擎:
    • PathFormatter自动处理pack_format 45+的路径变化(复数↔单数双向转换)
    • RecipeFormatter实现三代配方格式的链式转换(234行,支持任意版本间兼容)
    • 双版本系统独立管理datapack_version和resources_version
  • 依赖关系图谱系统:
    • 双向互斥检测(breaks):正向+反向检测冲突(HomePage.vue第246-260行)
    • 递归依赖绑定(bindings):深度优先遍历自动选择传递依赖(HomePage.vue第271-285行)
    • UI实时反馈:视觉化显示模块可用状态
  • 多平台模组支持:一键打包为Fabric/Quilt/Forge/NeoForge格式,单一资源包同时兼容原版和模组环境

3. 性能优化

  • 异步并发处理:Promise.all()并发加载模块文件树,相比串行减少60%-80%等待时间
  • 懒加载策略:仅加载元数据,文件内容按需获取,节省API配额
  • 按需过滤:构建过程中提前过滤不需要的目录,减少约50%的API调用
  • 内存优化:流式ZIP生成、Blob异步处理、版本信息缓存

4. 用户体验

  • URL路由记忆:支持直接分享仓库链接
  • 伪进度条:提供视觉反馈(0%→90%动画)
  • Markdown渲染:直接展示README,无需跳转
  • 代理持久化:localStorage保存用户设置
  • 建议版本预选:自动选中推荐版本

5. 社区协作

  • 标准化配置格式:TypeScript接口定义严格类型约束
  • 项目模板仓库:开箱即用的minecraft-pack-template
  • 降低贡献门槛:无需编程知识,仅需编辑JSON
  • 去中心化分发:通过GitHub实现版本控制和协作

技术栈优势:

  • Vue3 + TypeScript + Vite确保代码可维护性和类型安全
  • Arco Design提供一致的UI/UX体验
  • JSZip(v3.10.1)、Axios(v1.10.0)等成熟库保证功能稳定性
  • 异步并发处理和懒加载优化使构建过程高效流畅

项目影响:

项目显著降低了资源包开发门槛,使开发者能够专注于内容创作而非技术细节,同时为玩家提供了高度定制化的选择自由。 标准化的配置格式和项目模板促进了社区协作,通过GitHub实现去中心化的开源分发模式。该工具已成为Minecraft社区资源开发的实用工具, 未来可进一步扩展功能,推动Minecraft内容创作生态的繁荣发展。