build system
This commit is contained in:
parent
33a13cb1cc
commit
5730c94552
10 changed files with 32023 additions and 19272 deletions
|
|
@ -14,8 +14,8 @@ if (!fs.existsSync(".gitignore")) {
|
|||
export const config: Config = require(path.resolve(process.cwd(), "asajs.config.cjs")).config
|
||||
|
||||
export let isBuildMode = config.compiler?.enabled ?? false
|
||||
export let isLinkMode = config.compiler?.linked ?? false
|
||||
export let unLinked = !(config.compiler?.linked ?? true)
|
||||
export let isLinkMode = config.compiler?.autoImport ?? false
|
||||
export let unLinked = !(config.compiler?.autoImport ?? true)
|
||||
|
||||
for (const arg of process.argv) {
|
||||
if (arg === "--build") isBuildMode = true
|
||||
|
|
|
|||
|
|
@ -17,3 +17,24 @@ Map.prototype.toJSON = function () {
|
|||
Array.prototype.lastItem = function () {
|
||||
return this[this.length - 1]
|
||||
}
|
||||
|
||||
const now = performance.now()
|
||||
type LogType = "INFO"
|
||||
|
||||
function TypeHighlight(type: LogType) {
|
||||
switch (type) {
|
||||
case "INFO":
|
||||
return `\x1b[32mINFO\x1b[0m`
|
||||
default:
|
||||
return type satisfies never
|
||||
}
|
||||
}
|
||||
|
||||
export function Log(type: LogType, message: string) {
|
||||
console.log(
|
||||
`\x1b[90m[${(performance.now() - now).toFixed(2)}ms]\x1b[0m`,
|
||||
`[${TypeHighlight(type)}]`,
|
||||
message,
|
||||
"\x1b[0m",
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
import { config, isBuildMode, isLinkMode, unLinked } from "../Configuration.js"
|
||||
import { Memory } from "../Memory.js"
|
||||
import { createBuildFolder, linkToGame, unlink } from "./linker.js"
|
||||
import { genManifest } from "./manifest.js"
|
||||
import { createBuildFolder, gamePath, getBuildFolderName, linkToGame, unlink } from "./linker.js"
|
||||
import { genManifest, version } from "./manifest.js"
|
||||
import { UI } from "../../components/UI.js"
|
||||
import { Type } from "../../types/enums/Type.js"
|
||||
import fs from "fs/promises"
|
||||
import { BuildCache } from "./buildcache.js"
|
||||
import { disableRSP, enableRSP } from "./installer.js"
|
||||
import { Log } from "../PreCompile.js"
|
||||
import path from "path"
|
||||
|
||||
async function buildUI() {
|
||||
const build = Memory.build()
|
||||
|
|
@ -23,30 +26,38 @@ async function buildUI() {
|
|||
.stat(outFile.split(/\\|\//g).slice(0, -1).join("/"))
|
||||
.catch(async () => await fs.mkdir(outFile.split(/\\|\//g).slice(0, -1).join("/"), { recursive: true }))
|
||||
|
||||
await fs.writeFile(
|
||||
outFile,
|
||||
JSON.stringify(
|
||||
Object.fromEntries(
|
||||
Object.entries(value).map(([key, value]: [string, any]) => {
|
||||
const extend = (value as UI<Type>).extend
|
||||
return [extend ? key + String(extend) : key, value]
|
||||
}),
|
||||
await fs
|
||||
.writeFile(
|
||||
outFile,
|
||||
JSON.stringify(
|
||||
Object.fromEntries(
|
||||
Object.entries(value).map(([key, value]: [string, any]) => {
|
||||
const extend = (value as UI<Type>).extend
|
||||
return [extend ? key + String(extend) : key, value]
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
"utf-8",
|
||||
)
|
||||
"utf-8",
|
||||
)
|
||||
.then(() => Log("INFO", `${outFile} with ${Object.keys(value).length} elements created!`))
|
||||
build.delete(file)
|
||||
return file
|
||||
}),
|
||||
)
|
||||
|
||||
await Promise.all([
|
||||
fs.writeFile("build/manifest.json", await genManifest(), "utf-8"),
|
||||
fs.writeFile("build/.gitignore", [...out, "manifest.json"].join("\n"), "utf-8"),
|
||||
BuildCache.set("build-files", [...out, "manifest.json"]),
|
||||
fs
|
||||
.writeFile("build/manifest.json", await genManifest(), "utf-8")
|
||||
.then(() => Log("INFO", "build/manifest.json created!")),
|
||||
fs
|
||||
.writeFile("build/.gitignore", [...out, "manifest.json"].join("\n"), "utf-8")
|
||||
.then(() => Log("INFO", "build/.gitignore created!")),
|
||||
BuildCache.set("build-files", [...out, "manifest.json"]).then(() => Log("INFO", "build-files set!")),
|
||||
BuildCache.set("version", version).then(() => Log("INFO", "version set!")),
|
||||
fs
|
||||
.stat("build/pack_icon.png")
|
||||
.catch(() => fs.copyFile("node_modules/asajs/resources/pack_icon.png", "build/pack_icon.png")),
|
||||
.catch(() => fs.copyFile("node_modules/asajs/resources/pack_icon.png", "build/pack_icon.png"))
|
||||
.then(() => Log("INFO", "build/pack_icon.png copied!")),
|
||||
])
|
||||
|
||||
return out.length
|
||||
|
|
@ -59,6 +70,20 @@ if (isBuildMode) {
|
|||
await createBuildFolder()
|
||||
await buildUI()
|
||||
if (isLinkMode) await linkToGame()
|
||||
if (config.compiler?.autoEnable) await enableRSP()
|
||||
else await disableRSP()
|
||||
Log("INFO", "Build completed!")
|
||||
console.log("========================= PACK INFO =========================")
|
||||
console.log("Name:", `\x1b[32m${config.packinfo?.name || "MyPack"}\x1b[0m`)
|
||||
console.log(
|
||||
"Description:",
|
||||
`\x1b[32m${config.packinfo?.description || "Create your Minecraft JSON-UI resource packs using JavaScript."}\x1b[0m`,
|
||||
)
|
||||
console.log("Version:", config.packinfo?.version || [4, 0, 0])
|
||||
console.log("UUID:", await BuildCache.get<[string, string]>("uuid"))
|
||||
if (gamePath)
|
||||
console.log("Install Path:", `\x1b[32m"${path.join(gamePath, await getBuildFolderName())}"\x1b[0m`)
|
||||
console.log("=============================================================")
|
||||
}
|
||||
first = false
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,17 +1,180 @@
|
|||
import os from "os"
|
||||
import path from "path"
|
||||
import fs from "fs"
|
||||
import fsp from "fs/promises"
|
||||
import { config } from "../Configuration.js"
|
||||
import { BuildCache } from "./buildcache.js"
|
||||
import { version } from "./manifest.js"
|
||||
import { Log } from "../PreCompile.js"
|
||||
|
||||
interface PackInfo {
|
||||
pack_id: string
|
||||
subpack?: string
|
||||
version: [number, number, number]
|
||||
}
|
||||
|
||||
export interface PathInfo<Platform = NodeJS.Platform> {
|
||||
os: Platform
|
||||
isGdk: Platform extends "win32" ? boolean : never
|
||||
gamepath: string | null
|
||||
}
|
||||
|
||||
export const pathinfo: PathInfo = {
|
||||
os: os.platform(),
|
||||
isGdk: false,
|
||||
gamepath: null,
|
||||
}
|
||||
|
||||
function getGlobalResourcePackFile(gamepath: string) {
|
||||
return path.join(gamepath, "minecraftpe/global_resource_packs.json")
|
||||
}
|
||||
|
||||
async function readGlobalRspFile(filepath: string) {
|
||||
try {
|
||||
if (await fsp.stat(filepath)) {
|
||||
return JSON.parse(await fsp.readFile(filepath, "utf-8")) as PackInfo[]
|
||||
}
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function writeGlobalRspFile(filepath: string, data: PackInfo[]) {
|
||||
try {
|
||||
await fsp.writeFile(filepath, JSON.stringify(data), "utf-8")
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function enable(uuid: string, version: [number, number, number], filepath: string) {
|
||||
try {
|
||||
const globalRsp = await readGlobalRspFile(filepath)
|
||||
if (!globalRsp) return null
|
||||
const index = globalRsp.findIndex(data => data.pack_id === uuid)
|
||||
if (index === -1) {
|
||||
globalRsp.push({ pack_id: uuid, version })
|
||||
await writeGlobalRspFile(filepath, globalRsp)
|
||||
return true
|
||||
} else if (globalRsp[index].version.join(".") !== version.join(".")) {
|
||||
globalRsp[index].version = version
|
||||
await writeGlobalRspFile(filepath, globalRsp)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function disable(uuid: string, filepath: string) {
|
||||
try {
|
||||
let globalRsp = await readGlobalRspFile(filepath)
|
||||
if (!globalRsp) return null
|
||||
let isWrite = false
|
||||
globalRsp = globalRsp.filter(data => {
|
||||
if (data.pack_id === uuid) isWrite = true
|
||||
return data.pack_id !== uuid
|
||||
})
|
||||
if (isWrite) {
|
||||
await writeGlobalRspFile(filepath, globalRsp)
|
||||
return true
|
||||
} else return false
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function enableRSP() {
|
||||
if (pathinfo.isGdk && pathinfo.gamepath) {
|
||||
const ids: string[] = [],
|
||||
gamepath = path.join(pathinfo.gamepath, "../../..")
|
||||
if (config.compiler?.gdkUserId && /^\d+$/.test(config.compiler.gdkUserId)) ids.push(config.compiler.gdkUserId)
|
||||
else
|
||||
ids.push(...(await fsp.readdir(gamepath, { withFileTypes: false })).filter((id: string) => id !== "Shared"))
|
||||
|
||||
const [uuid] = await Promise.all([BuildCache.get<[string, string]>("uuid")])
|
||||
|
||||
if (!uuid) return
|
||||
await Promise.all(
|
||||
ids.map(async (id: string) =>
|
||||
enable(uuid[0]!, version, getGlobalResourcePackFile(path.join(gamepath, id, "games/com.mojang"))).then(
|
||||
v => {
|
||||
if (v) {
|
||||
Log("INFO", "Resource Pack enabled automaticly for " + id)
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
} else if (pathinfo.gamepath) {
|
||||
const [uuid] = await Promise.all([BuildCache.get<[string, string]>("uuid")])
|
||||
if (!uuid) return
|
||||
await enable(uuid[0]!, version, getGlobalResourcePackFile(pathinfo.gamepath)).then(v => {
|
||||
if (v) {
|
||||
Log("INFO", "Resource Pack enabled automaticly")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export async function disableRSP() {
|
||||
if (pathinfo.isGdk && pathinfo.gamepath) {
|
||||
const gamepath = path.join(pathinfo.gamepath, "../../..")
|
||||
const [uuid] = await Promise.all([BuildCache.get<[string, string]>("uuid")])
|
||||
if (!uuid) return
|
||||
await Promise.all(
|
||||
(await fsp.readdir(gamepath, { withFileTypes: false })).map(async (id: string) =>
|
||||
disable(uuid[0]!, getGlobalResourcePackFile(path.join(gamepath, id, "games/com.mojang"))).then(v => {
|
||||
if (v) {
|
||||
Log("INFO", "Resource Pack disabled automaticly for " + id)
|
||||
}
|
||||
}),
|
||||
),
|
||||
)
|
||||
} else if (pathinfo.gamepath) {
|
||||
const [uuid] = await Promise.all([BuildCache.get<[string, string]>("uuid")])
|
||||
if (!uuid) return
|
||||
await disable(uuid[0]!, getGlobalResourcePackFile(pathinfo.gamepath)).then(v => {
|
||||
if (v) {
|
||||
Log("INFO", "Resource Pack disabled automaticly")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function getGamedataPath() {
|
||||
switch (os.platform()) {
|
||||
switch (pathinfo.os) {
|
||||
case "win32": {
|
||||
if (/Windows (10|11)/.test(os.version())) {
|
||||
return path.join(process.env.APPDATA!, "Minecraft Bedrock\\Users\\Shared\\games\\com.mojang")
|
||||
let gamedata = path.join(
|
||||
process.env.APPDATA!,
|
||||
config.compiler?.importToPreview ? "Minecraft Bedrock Preview" : "Minecraft Bedrock",
|
||||
"\\Users\\Shared\\games\\com.mojang",
|
||||
)
|
||||
|
||||
if (fs.existsSync(gamedata)) {
|
||||
pathinfo.isGdk = true
|
||||
return (pathinfo.gamepath = gamedata)
|
||||
}
|
||||
|
||||
gamedata = path.join(
|
||||
process.env.LOCALAPPDATA!,
|
||||
"Packages",
|
||||
config.compiler?.importToPreview
|
||||
? "Microsoft.MinecraftWindowsBeta_8wekyb3d8bbwe"
|
||||
: "Microsoft.MinecraftUWP_8wekyb3d8bbwe",
|
||||
"LocalState\\games\\com.mojang",
|
||||
)
|
||||
|
||||
if (fs.existsSync(gamedata)) {
|
||||
return (pathinfo.gamepath = gamedata)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default: {
|
||||
console.error(`Your platform is not supported the install feature yet! \nYour OS version: ${os.version()}`)
|
||||
process.exit(1)
|
||||
console.warn(`Your platform is not supported the install feature yet! \nYour OS version: ${os.version()}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import fs from "fs/promises"
|
|||
import { BuildCache } from "./buildcache.js"
|
||||
import { RandomString } from "../../components/Utils.js"
|
||||
import path from "path"
|
||||
import { getGamedataPath } from "./installer.js"
|
||||
import { getGamedataPath, PathInfo, pathinfo } from "./installer.js"
|
||||
import { Log } from "../PreCompile.js"
|
||||
|
||||
const HEX: string[] = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"))
|
||||
|
||||
|
|
@ -25,13 +26,17 @@ function genUUID(): string {
|
|||
|
||||
export async function clearBuild() {
|
||||
const files: string[] = (await BuildCache.get("build-files")) || []
|
||||
await Promise.all(files.map(file => fs.rm(`build/${file}`).catch(() => null)))
|
||||
await Promise.all(files.map(file => fs.rm(`build/${file}`).catch(() => null))).then(() => {
|
||||
if (files.length) {
|
||||
Log("INFO", `Build folder cleared (${files.length} files removed)!`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export async function createBuildFolder() {
|
||||
return fs
|
||||
.stat("build")
|
||||
.catch(() => fs.mkdir("build"))
|
||||
.catch(() => fs.mkdir("build").then(() => Log("INFO", "Build folder created!")))
|
||||
.then(() => clearBuild())
|
||||
}
|
||||
|
||||
|
|
@ -39,18 +44,28 @@ export async function getBuildFolderName() {
|
|||
return await BuildCache.getWithSetDefault("build-key", () => RandomString(16))
|
||||
}
|
||||
|
||||
export let gamePath: string | null = null
|
||||
export async function linkToGame() {
|
||||
const sourcePath = path.resolve("build")
|
||||
const targetPath = path.resolve(getGamedataPath(), "development_resource_packs", await getBuildFolderName())
|
||||
await fs.stat(targetPath).catch(async () => {
|
||||
await fs.symlink(sourcePath, targetPath, "junction")
|
||||
})
|
||||
const gamedataPath = getGamedataPath()
|
||||
await BuildCache.set("last-gamedata-path", pathinfo)
|
||||
if (gamedataPath) {
|
||||
const sourcePath = path.resolve("build")
|
||||
const targetPath = path.resolve(gamedataPath, "development_resource_packs", await getBuildFolderName())
|
||||
await fs.stat(targetPath).catch(async () => {
|
||||
await fs
|
||||
.symlink(sourcePath, targetPath, "junction")
|
||||
.then(() => Log("INFO", "Linked build folder to gamedata!"))
|
||||
})
|
||||
gamePath = gamedataPath
|
||||
} else console.warn("No gamedata path found, cannot link!")
|
||||
}
|
||||
|
||||
export async function unlink() {
|
||||
const targetPath = path.resolve(getGamedataPath(), "development_resource_packs", await getBuildFolderName())
|
||||
const gamedataPath = await BuildCache.get<PathInfo>("last-gamedata-path")
|
||||
if (!gamedataPath?.gamepath) return
|
||||
const targetPath = path.resolve(gamedataPath.gamepath, "development_resource_packs", await getBuildFolderName())
|
||||
try {
|
||||
await fs.unlink(targetPath)
|
||||
await fs.unlink(targetPath).then(() => Log("INFO", "Unlinked build folder from gamedata!"))
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { config } from "../Configuration.js"
|
||||
import { getUUID } from "./linker.js"
|
||||
|
||||
export const version = config.packinfo?.version || [4, 0, 0]
|
||||
|
||||
export async function genManifest() {
|
||||
const [uuid1, uuid2] = await getUUID()
|
||||
return JSON.stringify({
|
||||
|
|
@ -10,7 +12,7 @@ export async function genManifest() {
|
|||
description:
|
||||
config.packinfo?.description || "Create your Minecraft JSON-UI resource packs using JavaScript.",
|
||||
uuid: uuid1,
|
||||
version: config.packinfo?.version || [4, 0, 0],
|
||||
version,
|
||||
min_engine_version: [1, 21, 80],
|
||||
},
|
||||
modules: [
|
||||
|
|
@ -18,7 +20,7 @@ export async function genManifest() {
|
|||
description: "This resource pack generate by AsaJS.",
|
||||
type: "resources",
|
||||
uuid: uuid2,
|
||||
version: [4, 0, 0],
|
||||
version: version,
|
||||
},
|
||||
],
|
||||
subpacks: config.packinfo?.subpacks,
|
||||
|
|
|
|||
Reference in a new issue