From 6b5cc23888bc638c192f91e4c2cbb0e2637db5af Mon Sep 17 00:00:00 2001 From: Asaki Yuki Date: Fri, 30 Jan 2026 01:33:05 +0700 Subject: [PATCH] installer --- src/compilers/FormatProperties.ts | 60 ++++++++++++++++--------------- src/compilers/Memory.ts | 6 ++-- src/compilers/ui/builder.ts | 33 ++++++++++++++--- src/compilers/ui/installer.ts | 2 +- src/compilers/ui/linker.ts | 13 ++++++- src/compilers/ui/prevdata.ts | 11 ++++++ src/components/UI.ts | 21 ++++++++--- src/components/Utils.ts | 29 ++++++++++++--- 8 files changed, 127 insertions(+), 48 deletions(-) create mode 100644 src/compilers/ui/prevdata.ts diff --git a/src/compilers/FormatProperties.ts b/src/compilers/FormatProperties.ts index dae702b..7ab723c 100644 --- a/src/compilers/FormatProperties.ts +++ b/src/compilers/FormatProperties.ts @@ -1,40 +1,42 @@ -import { AnimationKeyframe } from "../components/AnimationKeyframe.js" -import { AnimType } from "../types/enums/AnimType.js" -import { KeyframeAnimationProperties } from "../types/properties/element/Animation.js" -import { Binding } from "../types/properties/value.js" +import { AnimationKeyframe } from "../components/AnimationKeyframe.js"; +import { AnimType } from "../types/enums/AnimType.js"; +import { KeyframeAnimationProperties } from "../types/properties/element/Animation.js"; +import { Binding } from "../types/properties/value.js"; export function FormatProperties(properties: any) { - const property_bag: Record = {} + const property_bag: Record = {}; - for (const key in properties) { - const value = properties[key] + for (const key in properties) { + const value = properties[key]; - if (key.startsWith("#")) { - property_bag[key] = value - delete properties[key] - } - } + if (key.startsWith("#")) { + property_bag[key] = value; + delete properties[key]; + } + } - if (properties.anchor) { - properties.anchor_from = properties.anchor_to = properties.anchor - delete properties.anchor - } + if (properties.anchor) { + properties.anchor_from = properties.anchor_to = properties.anchor; + delete properties.anchor; + } - if (Object.keys(property_bag).length) { - if (properties.property_bag) { - properties.property_bag = { ...property_bag, ...properties.property_bag } - } else { - properties.property_bag = property_bag - } - } + if (Object.keys(property_bag).length) { + if (properties.property_bag) { + properties.property_bag = { ...property_bag, ...properties.property_bag }; + } else { + properties.property_bag = property_bag; + } + } - return properties + return properties; } -export function FormatAnimationProperties(properties: KeyframeAnimationProperties) { - if (properties.next instanceof AnimationKeyframe) { - properties.next = `${properties.next}` - } +export function FormatAnimationProperties( + properties: KeyframeAnimationProperties, +) { + if (properties.next instanceof AnimationKeyframe) { + properties.next = `${properties.next}`; + } - return properties + return properties; } diff --git a/src/compilers/Memory.ts b/src/compilers/Memory.ts index ff2731e..3aa8971 100644 --- a/src/compilers/Memory.ts +++ b/src/compilers/Memory.ts @@ -1,6 +1,6 @@ import { AnimationKeyframe } from "../components/AnimationKeyframe.js" import { Class } from "../components/Class.js" -import { ModifyUI, UI } from "../components/UI.js" +import { UI } from "../components/UI.js" import { AnimType } from "../types/enums/AnimType.js" import { Renderer } from "../types/enums/Renderer.js" import { Type } from "../types/enums/Type.js" @@ -40,9 +40,7 @@ export class Memory extends Class { Memory.files.entries().forEach(([path, { elements, namespace }]) => { const record: Record = {} - elements.forEach(element => { - record[element.name] = element - }) + elements.forEach(element => (record[element.name] = element)) data.set(path, { namespace, diff --git a/src/compilers/ui/builder.ts b/src/compilers/ui/builder.ts index a456da9..8ad69de 100644 --- a/src/compilers/ui/builder.ts +++ b/src/compilers/ui/builder.ts @@ -1,8 +1,10 @@ import { isBuildMode } from "../Configuration.js" import { Memory } from "../Memory.js" -import { createBuildFolder } from "./linker.js" -import fs from "fs/promises" +import { createBuildFolder, linkToGame } from "./linker.js" import { genManifest } from "./manifest.js" +import { UI } from "../../components/UI.js" +import { Type } from "../../types/enums/Type.js" +import fs from "fs/promises" async function buildUI() { const build = Memory.build() @@ -11,6 +13,10 @@ async function buildUI() { ui_defs: Array.from(build.keys()), }) + build.set("build.json", { + files: Array.from(build.keys()), + }) + const out = await Promise.all( build.entries().map(async ([file, value]) => { const outFile = `build/build/${file}` @@ -18,12 +24,30 @@ 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(value), "utf-8") + await fs.writeFile( + outFile, + JSON.stringify( + Object.fromEntries( + Object.entries(value).map(([key, value]: [string, any]) => { + const extend = (value as UI).extend + return [extend ? key + String(extend) : key, value] + }), + ), + ), + "utf-8", + ) build.delete(file) + return file }), ) - await fs.writeFile("build/build/manifest.json", await genManifest(), "utf-8") + await Promise.all([ + fs.writeFile("build/build/manifest.json", await genManifest(), "utf-8"), + fs.writeFile("build/build/.gitignore", [...out, "manifest.json"].join("\n"), "utf-8"), + fs + .stat("build/build/pack_icon.png") + .catch(() => fs.copyFile("node_modules/asajs/resources/pack_icon.png", "build/build/pack_icon.png")), + ]) return out.length } @@ -34,6 +58,7 @@ if (isBuildMode) { if (first) { await createBuildFolder() await buildUI() + await linkToGame() } first = false }) diff --git a/src/compilers/ui/installer.ts b/src/compilers/ui/installer.ts index 191aa05..a22ec50 100644 --- a/src/compilers/ui/installer.ts +++ b/src/compilers/ui/installer.ts @@ -1,7 +1,7 @@ import os from "os" import path from "path" -function getGamedataPath() { +export function getGamedataPath() { switch (os.platform()) { case "win32": { if (/Windows (10|11)/.test(os.version())) { diff --git a/src/compilers/ui/linker.ts b/src/compilers/ui/linker.ts index 1da09d8..9a6ae15 100644 --- a/src/compilers/ui/linker.ts +++ b/src/compilers/ui/linker.ts @@ -1,6 +1,9 @@ import fs from "fs/promises" import { BuildCache } from "./buildcache.js" import { RandomString } from "../../components/Utils.js" +import { prevData } from "./prevdata.js" +import path from "path" +import { getGamedataPath } from "./installer.js" const HEX: string[] = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0")) @@ -22,7 +25,7 @@ function genUUID(): string { } export async function clearBuild() { - await fs.rm("build/build", { recursive: true, force: true }) + await Promise.all(prevData.files.map(file => fs.rm(`build/build/${file}`).catch(() => null))) } export async function createBuildFolder() { @@ -36,6 +39,14 @@ export async function getBuildFolderName() { return await BuildCache.getWithSetDefault("build-key", () => RandomString(16)) } +export async function linkToGame() { + const sourcePath = path.resolve("build/build") + const targetPath = path.resolve(getGamedataPath(), "development_resource_packs", await getBuildFolderName()) + await fs.stat(targetPath).catch(async () => { + await fs.symlink(sourcePath, targetPath, "junction") + }) +} + export async function getUUID(): Promise<[string, string]> { return await BuildCache.getWithSetDefault("uuid", () => { return [genUUID(), genUUID()] diff --git a/src/compilers/ui/prevdata.ts b/src/compilers/ui/prevdata.ts new file mode 100644 index 0000000..868db96 --- /dev/null +++ b/src/compilers/ui/prevdata.ts @@ -0,0 +1,11 @@ +import fs from "fs" + +export let prevData: { + files: string[] +} + +try { + prevData = JSON.parse(fs.readFileSync("build/build/build.json", "utf-8")) +} catch (error) { + prevData = { files: [] } +} diff --git a/src/components/UI.ts b/src/components/UI.ts index e1d3dde..0f42cd5 100644 --- a/src/components/UI.ts +++ b/src/components/UI.ts @@ -15,12 +15,18 @@ import { RandomNamespace } from "../compilers/Random.js" import util from "node:util" +interface ExtendUI { + name: string + namespace: string + toString(): string +} + export class UI extends Class { readonly path: string readonly name: string readonly namespace: string - readonly extend?: UI + readonly extend?: UI | ExtendUI readonly extendable: boolean protected readonly controls = new Map, Properties]>() @@ -53,7 +59,7 @@ export class UI extends Class this.name = name?.match(/^(\w|\/)+/)?.[0] || RandomString(16) this.namespace = namespace || RandomNamespace() - if (!path) this.path = `@/${this.namespace}.json` + if (!path) this.path = `asajs/${this.namespace}.json` else this.path = path this.extendable = this.name.search("/") === -1 @@ -132,8 +138,15 @@ export class UI extends Class * @param namespace * @returns */ - clone(properties?: Properties, name?: string, namespace?: string) { - return ExtendsOf(this, properties, name, namespace) + createExtends(properties?: Properties, name?: string, namespace?: string) { + if (!this.extendable) throw new Error("This element is not extendable") + const ui = new UI(undefined, name, namespace) + if (properties) ui.setProperties(properties) + // @ts-ignore + ui.extend = this + // @ts-ignore + ui.extendType = this.type || this.extendType + return ui } protected toString() { diff --git a/src/components/Utils.ts b/src/components/Utils.ts index bf98c40..625a643 100644 --- a/src/components/Utils.ts +++ b/src/components/Utils.ts @@ -37,7 +37,7 @@ import { AnimationKeyframe } from "./AnimationKeyframe.js" import { AnimationProperties, KeyframeAnimationProperties } from "../types/properties/element/Animation.js" import { Animation } from "./Animation.js" import { SmartAnimation } from "../types/enums/SmartAnimation.js" -import { Memory, MemoryModify } from "../compilers/Memory.js" +import { MemoryModify } from "../compilers/Memory.js" type CompileBinding = `[${string}]` @@ -250,9 +250,7 @@ export function ExtendsOf( namespace?: string, name?: string, ) { - if (!element.extendable) { - throw new Error("Cannot extend a UI that cannot be extended") - } + if (!element.extendable) throw new Error("Cannot extend a UI that cannot be extended") const ui = new UI(undefined, name, namespace) if (properties) ui.setProperties(properties) // @ts-ignore @@ -262,6 +260,27 @@ export function ExtendsOf( return ui as typeof element } +export function VanillaExtendsOf, `${string}/${string}`>>( + originNamespace: T, + originName: K, + // @ts-ignore + properties?: Properties, null>, + namespace?: string, + name?: string, +) { + // @ts-ignore + const ui = new UI, null>(undefined, name, namespace) + if (properties) ui.setProperties(properties) + // @ts-ignore + ui.extend = { + name: originName, + namespace: originNamespace, + toString: () => `@${originNamespace}.${originName}`, + } + + return ui +} + // Quick Keyframe export function KeyframeOffset( properties?: KeyframeAnimationProperties, @@ -359,7 +378,7 @@ export function AnimationAlpha(...keyframes: AnimWithSmartAnim) return new Animation(AnimType.ALPHA, ...keyframes) } -// Animation Extendof +// Animation ExtendsOf export function AnimationExtendsOf( animation: AnimationKeyframe | Animation, properties?: AnimationProperties,