installer

This commit is contained in:
Asaki Yuki 2026-01-30 01:33:05 +07:00
parent 3158c3cec8
commit 6b5cc23888
8 changed files with 127 additions and 48 deletions

View file

@ -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<Binding, any> = {}
const property_bag: Record<Binding, any> = {};
for (const key in properties) {
const value = properties[key]
for (const key in properties) {
const value = properties[key];
if (key.startsWith("#")) {
property_bag[<Binding>key] = value
delete properties[key]
}
}
if (key.startsWith("#")) {
property_bag[<Binding>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<AnimType>) {
if (properties.next instanceof AnimationKeyframe) {
properties.next = `${properties.next}`
}
export function FormatAnimationProperties(
properties: KeyframeAnimationProperties<AnimType>,
) {
if (properties.next instanceof AnimationKeyframe) {
properties.next = `${properties.next}`;
}
return properties
return properties;
}

View file

@ -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<string, any> = {}
elements.forEach(element => {
record[element.name] = element
})
elements.forEach(element => (record[element.name] = element))
data.set(path, {
namespace,

View file

@ -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<Type>).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
})

View file

@ -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())) {

View file

@ -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()]

View file

@ -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: [] }
}

View file

@ -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<T extends Type, K extends Renderer | null = null> extends Class {
readonly path: string
readonly name: string
readonly namespace: string
readonly extend?: UI<Type, Renderer | null>
readonly extend?: UI<Type, Renderer | null> | ExtendUI
readonly extendable: boolean
protected readonly controls = new Map<string, [UI<Type, Renderer | null>, Properties<Type, Renderer | null>]>()
@ -53,7 +59,7 @@ export class UI<T extends Type, K extends Renderer | null = null> 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<T extends Type, K extends Renderer | null = null> extends Class
* @param namespace
* @returns
*/
clone(properties?: Properties<T, K>, name?: string, namespace?: string) {
return ExtendsOf(this, properties, name, namespace)
createExtends(properties?: Properties<T, K>, name?: string, namespace?: string) {
if (!this.extendable) throw new Error("This element is not extendable")
const ui = new UI<T, K>(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() {

View file

@ -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<T extends Type, K extends Renderer | null>(
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<T, K>(undefined, name, namespace)
if (properties) ui.setProperties(properties)
// @ts-ignore
@ -262,6 +260,27 @@ export function ExtendsOf<T extends Type, K extends Renderer | null>(
return ui as typeof element
}
export function VanillaExtendsOf<T extends Namespace, K extends Exclude<Element<T>, `${string}/${string}`>>(
originNamespace: T,
originName: K,
// @ts-ignore
properties?: Properties<VanillaType<T, K>, null>,
namespace?: string,
name?: string,
) {
// @ts-ignore
const ui = new UI<VanillaType<T, K>, 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<AnimType.OFFSET>,
@ -359,7 +378,7 @@ export function AnimationAlpha(...keyframes: AnimWithSmartAnim<AnimType.ALPHA>)
return new Animation(AnimType.ALPHA, ...keyframes)
}
// Animation Extendof
// Animation ExtendsOf
export function AnimationExtendsOf<T extends AnimType>(
animation: AnimationKeyframe<T> | Animation<T>,
properties?: AnimationProperties<T>,