@openfairygui/functions 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{atlas-C6tbl7nn.d.ts → atlas-BtWa1DwO.d.ts} +6 -0
- package/dist/{atlas-CHsu2Y8i.d.cts → atlas-CSqHsG0X.d.cts} +6 -0
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/node.cjs +2 -2
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +2 -2
- package/dist/{publish-Ni90AtjG.js → publish-BCzpqNr9.js} +110 -50
- package/dist/{publish-Cl1b5HtO.cjs → publish-BHoaYgPU.cjs} +110 -50
- package/dist/{restore-C8FYrc7J.d.cts → restore-BOfsCM47.d.ts} +4 -4
- package/dist/{restore-BXJjaSMN.cjs → restore-CLlkcYIw.cjs} +1 -1
- package/dist/{restore-D7RtsnWd.d.ts → restore-D6F1ELdM.d.cts} +4 -4
- package/dist/{restore-teyQ9DXH.js → restore-DovUbh5F.js} +1 -1
- package/dist/web.cjs +41 -1
- package/dist/web.d.cts +2 -2
- package/dist/web.d.ts +2 -2
- package/dist/web.js +41 -1
- package/package.json +2 -2
- package/src/adapters/node/plugins.ts +4 -4
- package/src/adapters/web/publish.ts +2 -0
- package/src/adapters/web/raster.ts +46 -0
- package/src/atlas/packing.ts +22 -13
- package/src/atlas.ts +22 -3
- package/src/codegen.ts +20 -9
- package/src/publish/contracts.ts +3 -0
- package/src/publish/external-resources.ts +12 -6
- package/src/publish/options.ts +11 -3
- package/src/publish/package-context.ts +35 -11
- package/src/publish/resource-references.ts +21 -6
- package/src/publish.ts +22 -2
- package/src/utils.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfairygui/functions",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "FairyGUI Headless Authoring SDK — composable transform functions.",
|
|
5
5
|
"author": "OpenFairyGUI Contributors",
|
|
6
6
|
"license": "MIT",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"fast-xml-parser": "^5.0.0",
|
|
77
77
|
"jiti": "^2.6.1",
|
|
78
|
-
"@openfairygui/core": "0.2.
|
|
78
|
+
"@openfairygui/core": "0.2.6"
|
|
79
79
|
},
|
|
80
80
|
"optionalDependencies": {
|
|
81
81
|
"sharp": ">=0.33.0"
|
|
@@ -50,17 +50,17 @@ async function readPluginManifest(
|
|
|
50
50
|
fs: typeof import('node:fs/promises'),
|
|
51
51
|
path: typeof import('node:path'),
|
|
52
52
|
pluginDir: string,
|
|
53
|
-
): Promise<
|
|
53
|
+
): Promise<PluginManifest | null> {
|
|
54
54
|
const manifestPath = path.join(pluginDir, 'package.json');
|
|
55
55
|
const content = await fs.readFile(manifestPath, 'utf-8');
|
|
56
56
|
const manifest = JSON.parse(content) as PluginPackageJson;
|
|
57
57
|
if (!manifest.name) throw new Error(`Codegen plugin at ${pluginDir} is missing package.json name.`);
|
|
58
58
|
if (!manifest.main) throw new Error(`Codegen plugin "${manifest.name}" is missing package.json main.`);
|
|
59
|
-
return manifest;
|
|
59
|
+
return manifest as PluginManifest;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
function resolvePluginMain(path: typeof import('node:path'), pluginDir: string, manifest:
|
|
63
|
-
const mainPath = path.resolve(pluginDir, manifest.main
|
|
62
|
+
function resolvePluginMain(path: typeof import('node:path'), pluginDir: string, manifest: PluginManifest): string {
|
|
63
|
+
const mainPath = path.resolve(pluginDir, manifest.main);
|
|
64
64
|
const relative = path.relative(pluginDir, mainPath);
|
|
65
65
|
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
66
66
|
throw new Error(`Codegen plugin "${manifest.name}" main must resolve inside its plugin directory.`);
|
|
@@ -27,6 +27,7 @@ interface BrowserContext {
|
|
|
27
27
|
): void;
|
|
28
28
|
fillRect(x: number, y: number, width: number, height: number): void;
|
|
29
29
|
getImageData(sx: number, sy: number, sw: number, sh: number): ImageData;
|
|
30
|
+
putImageData(imageData: ImageData, dx: number, dy: number): void;
|
|
30
31
|
rotate(angle: number): void;
|
|
31
32
|
restore(): void;
|
|
32
33
|
save(): void;
|
|
@@ -308,6 +309,51 @@ class BrowserImagePipeline implements AtlasRasterPipeline {
|
|
|
308
309
|
return this;
|
|
309
310
|
}
|
|
310
311
|
|
|
312
|
+
removeAlpha(): this {
|
|
313
|
+
this.raster = this.raster.then((source) => {
|
|
314
|
+
const context = getBrowserContext(source.canvas);
|
|
315
|
+
const image = context.getImageData(0, 0, source.width, source.height);
|
|
316
|
+
for (let index = 3; index < image.data.length; index += 4) image.data[index] = 255;
|
|
317
|
+
context.putImageData(image, 0, 0);
|
|
318
|
+
return source;
|
|
319
|
+
});
|
|
320
|
+
return this;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
extractChannel(channel: 'alpha'): this {
|
|
324
|
+
if (channel !== 'alpha') throw new Error(`publishBrowser: Unsupported channel "${channel}".`);
|
|
325
|
+
this.raster = this.raster.then((source) => {
|
|
326
|
+
const context = getBrowserContext(source.canvas);
|
|
327
|
+
const image = context.getImageData(0, 0, source.width, source.height);
|
|
328
|
+
for (let index = 0; index < image.data.length; index += 4) {
|
|
329
|
+
const alpha = image.data[index + 3] ?? 0;
|
|
330
|
+
image.data[index] = alpha;
|
|
331
|
+
image.data[index + 1] = alpha;
|
|
332
|
+
image.data[index + 2] = alpha;
|
|
333
|
+
image.data[index + 3] = 255;
|
|
334
|
+
}
|
|
335
|
+
context.putImageData(image, 0, 0);
|
|
336
|
+
return source;
|
|
337
|
+
});
|
|
338
|
+
return this;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
joinChannel(images: Uint8Array[]): this {
|
|
342
|
+
this.raster = Promise.all([this.raster, ...images.map((image) => this.decode(image))]).then(([source, ...channels]) => {
|
|
343
|
+
const context = getBrowserContext(source.canvas);
|
|
344
|
+
const image = context.getImageData(0, 0, source.width, source.height);
|
|
345
|
+
for (const [channelIndex, channel] of channels.slice(0, 2).entries()) {
|
|
346
|
+
const channelData = getBrowserContext(channel.canvas).getImageData(0, 0, channel.width, channel.height).data;
|
|
347
|
+
for (let index = 0; index < image.data.length; index += 4) {
|
|
348
|
+
image.data[index + channelIndex + 1] = channelData[index] ?? 0;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
context.putImageData(image, 0, 0);
|
|
352
|
+
return source;
|
|
353
|
+
});
|
|
354
|
+
return this;
|
|
355
|
+
}
|
|
356
|
+
|
|
311
357
|
resize(options: { width: number; height: number; fit?: 'fill' }): this {
|
|
312
358
|
this.raster = this.raster.then((source) => {
|
|
313
359
|
const target = createRaster(options.width, options.height);
|
package/src/atlas/packing.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Document, ILogger, Package } from '@openfairygui/core';
|
|
2
2
|
import type { AtlasOptions } from '../atlas.js';
|
|
3
|
-
import { COMPAT_NODE_RECT_FLAGS, type CompatNodeRect } from '../max-rects-compat.js';
|
|
3
|
+
import { COMPAT_NODE_RECT_FLAGS, type CompatNodeRect, type CompatPage } from '../max-rects-compat.js';
|
|
4
4
|
import { MaxRectsPackerCompat } from '../max-rects-packer-compat.js';
|
|
5
5
|
import type { AtlasRasterBackend } from '../publish/contracts.js';
|
|
6
6
|
import {
|
|
@@ -289,13 +289,13 @@ function packAtlasPages(
|
|
|
289
289
|
multipleOfFour: boolean;
|
|
290
290
|
square: boolean;
|
|
291
291
|
},
|
|
292
|
-
):
|
|
292
|
+
): CompatPage[] {
|
|
293
293
|
const hasDuplicatePadding = inputs.some((input) => {
|
|
294
294
|
return isImageResource(input.resource) && input.resource.getDuplicatePadding?.() === true;
|
|
295
295
|
});
|
|
296
296
|
const packer = new MaxRectsPackerCompat({
|
|
297
297
|
pot: sizeOverrides?.powerOfTwo ?? options.powerOfTwo,
|
|
298
|
-
mof: sizeOverrides?.multipleOfFour ??
|
|
298
|
+
mof: sizeOverrides?.multipleOfFour ?? options.multipleOfFour,
|
|
299
299
|
padding: options.padding,
|
|
300
300
|
rotation: options.allowRotation,
|
|
301
301
|
minWidth: 16,
|
|
@@ -433,16 +433,25 @@ async function writeAtlasPageImage(
|
|
|
433
433
|
}
|
|
434
434
|
|
|
435
435
|
const outputFile = `${options.outputPath}/${atlasFileName}`;
|
|
436
|
-
|
|
436
|
+
const atlasPipeline = encoder({
|
|
437
437
|
create: {
|
|
438
438
|
width: page.width,
|
|
439
439
|
height: page.height,
|
|
440
440
|
channels: 4 as const,
|
|
441
441
|
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
442
442
|
},
|
|
443
|
-
})
|
|
444
|
-
|
|
445
|
-
.
|
|
443
|
+
}).composite(compositeInputs);
|
|
444
|
+
if (options.extractAlpha) {
|
|
445
|
+
const atlasBuffer = await atlasPipeline.png().toBuffer();
|
|
446
|
+
await encoder(atlasBuffer).removeAlpha().png().toFile(outputFile);
|
|
447
|
+
const alphaBuffer = await encoder(atlasBuffer).extractChannel('alpha').png().toBuffer();
|
|
448
|
+
await encoder(alphaBuffer)
|
|
449
|
+
.joinChannel([alphaBuffer, alphaBuffer])
|
|
450
|
+
.png()
|
|
451
|
+
.toFile(`${options.outputPath}/${insertFileNameSuffix(atlasFileName, '!a')}`);
|
|
452
|
+
} else {
|
|
453
|
+
await atlasPipeline.toFile(outputFile);
|
|
454
|
+
}
|
|
446
455
|
|
|
447
456
|
logger.info(`atlas: Generated ${atlasFileName} (${page.width}x${page.height}, ${page.outputRects.length} sprites)`);
|
|
448
457
|
}
|
|
@@ -504,6 +513,9 @@ function resolveDirectOutputAtlasSize(
|
|
|
504
513
|
if (options.powerOfTwo) {
|
|
505
514
|
resolvedWidth = nextPow2(resolvedWidth);
|
|
506
515
|
resolvedHeight = nextPow2(resolvedHeight);
|
|
516
|
+
} else if (options.multipleOfFour) {
|
|
517
|
+
resolvedWidth = roundUpToMultiple(resolvedWidth, 4);
|
|
518
|
+
resolvedHeight = roundUpToMultiple(resolvedHeight, 4);
|
|
507
519
|
}
|
|
508
520
|
return { width: resolvedWidth, height: resolvedHeight };
|
|
509
521
|
}
|
|
@@ -663,11 +675,8 @@ export function sortResourcesByOrder(
|
|
|
663
675
|
return ordered;
|
|
664
676
|
}
|
|
665
677
|
|
|
666
|
-
function getResourceTextureSetMode(resource: PackInputResource): TextureSetMode {
|
|
667
|
-
|
|
668
|
-
return parseTextureSetMode(resource.getTextureSetMode?.());
|
|
669
|
-
}
|
|
670
|
-
return parseTextureSetMode(resource.getTextureSetMode?.());
|
|
678
|
+
function getResourceTextureSetMode(resource: PackInputResource, maxAtlasIndex: number): TextureSetMode {
|
|
679
|
+
return parseTextureSetMode(resource.getTextureSetMode?.(), maxAtlasIndex);
|
|
671
680
|
}
|
|
672
681
|
|
|
673
682
|
function groupStandaloneInputs(
|
|
@@ -710,7 +719,7 @@ function groupStandaloneInputs(
|
|
|
710
719
|
for (const input of inputs) {
|
|
711
720
|
const branchName = getInputBranchName(input);
|
|
712
721
|
const branchOrdinal = branchOrdinalByName.get(branchName) ?? 0;
|
|
713
|
-
const mode = getResourceTextureSetMode(input.resource);
|
|
722
|
+
const mode = getResourceTextureSetMode(input.resource, options.maxAtlasIndex ?? 10);
|
|
714
723
|
if (mode.kind === 'standalone') {
|
|
715
724
|
const resourceId = getPublishedItemId(input.resource);
|
|
716
725
|
const key = `${branchName}\u0000${resourceId}`;
|
package/src/atlas.ts
CHANGED
|
@@ -62,6 +62,9 @@ export interface AtlasOptions {
|
|
|
62
62
|
|
|
63
63
|
/** Constrain atlas dimensions to powers of two. Default: false. */
|
|
64
64
|
powerOfTwo?: boolean;
|
|
65
|
+
/** Highest fixed atlas page index accepted from resource textureSetMode. Default: 10. */
|
|
66
|
+
maxAtlasIndex?: number;
|
|
67
|
+
multipleOfFour?: boolean;
|
|
65
68
|
|
|
66
69
|
/** Force square atlas (width === height). Default: false. */
|
|
67
70
|
square?: boolean;
|
|
@@ -151,6 +154,8 @@ const ATLAS_DEFAULTS: Required<
|
|
|
151
154
|
allowRotation: true,
|
|
152
155
|
padding: 1,
|
|
153
156
|
powerOfTwo: false,
|
|
157
|
+
maxAtlasIndex: 10,
|
|
158
|
+
multipleOfFour: false,
|
|
154
159
|
square: false,
|
|
155
160
|
multiPage: true,
|
|
156
161
|
trimImage: false,
|
|
@@ -163,7 +168,9 @@ const ATLAS_DEFAULTS: Required<
|
|
|
163
168
|
|
|
164
169
|
interface AtlasReferenceItem {
|
|
165
170
|
icon?: string | null;
|
|
171
|
+
selectedIcon?: string | null;
|
|
166
172
|
url?: string | null;
|
|
173
|
+
propertyOverrides?: Array<{ value: string }>;
|
|
167
174
|
}
|
|
168
175
|
|
|
169
176
|
interface GearWithAtlasRefs {
|
|
@@ -183,12 +190,14 @@ interface TransitionWithAtlasRefs {
|
|
|
183
190
|
}
|
|
184
191
|
|
|
185
192
|
interface ChildWithReferenceUrls extends HasOptionalSrc, HasOptionalUrl {
|
|
193
|
+
getClearOnPublish?(): boolean;
|
|
186
194
|
getDefaultItem?(): string;
|
|
187
195
|
getIcon?(): string;
|
|
188
196
|
getSelectedIcon?(): string;
|
|
189
197
|
getDropdown?(): string;
|
|
190
198
|
getSound?(): string;
|
|
191
199
|
getText?(): string;
|
|
200
|
+
getAutoClearText?(): boolean;
|
|
192
201
|
getFont?(): string;
|
|
193
202
|
getInstanceIcon?(): string;
|
|
194
203
|
getInstanceSelectedIcon?(): string;
|
|
@@ -197,7 +206,10 @@ interface ChildWithReferenceUrls extends HasOptionalSrc, HasOptionalUrl {
|
|
|
197
206
|
getHeaderRes?(): string;
|
|
198
207
|
getFooterRes?(): string;
|
|
199
208
|
getInstanceComboItems?(): Array<{ icon: string | null }>;
|
|
209
|
+
getInstanceAutoClearItems?(): boolean;
|
|
200
210
|
getListItems?(): AtlasReferenceItem[];
|
|
211
|
+
getAutoClearItems?(): boolean;
|
|
212
|
+
getPropertyOverrides?(): Array<{ value: string }>;
|
|
201
213
|
listGears?(): GearWithAtlasRefs[];
|
|
202
214
|
}
|
|
203
215
|
|
|
@@ -303,7 +315,7 @@ async function resolveEditorCompatibleResourceOrder(
|
|
|
303
315
|
const refChild = child as ChildWithReferenceUrls;
|
|
304
316
|
await addResource(resourceMap.get(refChild.getSrc?.() ?? ''));
|
|
305
317
|
for (const ref of [
|
|
306
|
-
refChild.getUrl?.(),
|
|
318
|
+
refChild.getClearOnPublish?.() ? undefined : refChild.getUrl?.(),
|
|
307
319
|
refChild.getDefaultItem?.(),
|
|
308
320
|
refChild.getIcon?.(),
|
|
309
321
|
refChild.getSelectedIcon?.(),
|
|
@@ -319,12 +331,19 @@ async function resolveEditorCompatibleResourceOrder(
|
|
|
319
331
|
]) {
|
|
320
332
|
await addResourceByLocalUiUrl(ref);
|
|
321
333
|
}
|
|
322
|
-
for (const item of refChild.getInstanceComboItems?.() ?? []) {
|
|
334
|
+
for (const item of refChild.getInstanceAutoClearItems?.() ? [] : (refChild.getInstanceComboItems?.() ?? [])) {
|
|
323
335
|
await addResourceByLocalUiUrl(item.icon ?? undefined);
|
|
324
336
|
}
|
|
325
|
-
for (const item of refChild.getListItems?.() ?? []) {
|
|
337
|
+
for (const item of refChild.getAutoClearItems?.() ? [] : (refChild.getListItems?.() ?? [])) {
|
|
326
338
|
await addResourceByLocalUiUrl(item.icon ?? undefined);
|
|
339
|
+
await addResourceByLocalUiUrl(item.selectedIcon ?? undefined);
|
|
327
340
|
await addResourceByLocalUiUrl(item.url ?? undefined);
|
|
341
|
+
for (const property of item.propertyOverrides ?? []) {
|
|
342
|
+
await addResourceByLocalUiUrl(property.value);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
for (const property of refChild.getPropertyOverrides?.() ?? []) {
|
|
346
|
+
await addResourceByLocalUiUrl(property.value);
|
|
328
347
|
}
|
|
329
348
|
for (const gear of refChild.listGears?.() ?? []) {
|
|
330
349
|
await addGearIconResources(gear);
|
package/src/codegen.ts
CHANGED
|
@@ -33,12 +33,13 @@ export interface ResolvedPackageCodegenPlan {
|
|
|
33
33
|
packageFolderName: string;
|
|
34
34
|
packageNamespace: string;
|
|
35
35
|
binderClassName: string;
|
|
36
|
-
settings: CliCodeGenerationSettings
|
|
36
|
+
settings: Required<CliCodeGenerationSettings>;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
interface FguiTypescriptVariant {
|
|
40
40
|
binderMethod: 'setExtension';
|
|
41
41
|
runtimeNamespace: 'fgui';
|
|
42
|
+
runtimeImport: string;
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
const FGUI_TYPESCRIPT_RUNTIME_TYPES = new Set([
|
|
@@ -65,9 +66,15 @@ const FGUI_TYPESCRIPT_RUNTIME_TYPES = new Set([
|
|
|
65
66
|
'Transition',
|
|
66
67
|
]);
|
|
67
68
|
|
|
68
|
-
const
|
|
69
|
+
const LAYABOX_TYPESCRIPT_VARIANT: FguiTypescriptVariant = {
|
|
69
70
|
binderMethod: 'setExtension',
|
|
70
71
|
runtimeNamespace: 'fgui',
|
|
72
|
+
runtimeImport: '',
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const COCOS_CREATOR_TYPESCRIPT_VARIANT: FguiTypescriptVariant = {
|
|
76
|
+
...LAYABOX_TYPESCRIPT_VARIANT,
|
|
77
|
+
runtimeImport: 'import * as fgui from "fairygui-cc";',
|
|
71
78
|
};
|
|
72
79
|
|
|
73
80
|
export interface CodegenMember {
|
|
@@ -101,12 +108,14 @@ export async function publishCodeGeneration(doc: Document, options: PublishCodeG
|
|
|
101
108
|
const settings = resolveCodeGenerationSettings(doc);
|
|
102
109
|
if (!settings.allowGenCode) return;
|
|
103
110
|
|
|
104
|
-
const plugins = options.plugins
|
|
111
|
+
const plugins = options.plugins ?? [];
|
|
105
112
|
if (plugins.length > 0) {
|
|
106
113
|
let handled = false;
|
|
107
114
|
for (const plugin of plugins) {
|
|
115
|
+
const genCode = plugin.plugin.genCode;
|
|
116
|
+
if (!genCode) continue;
|
|
108
117
|
try {
|
|
109
|
-
await
|
|
118
|
+
await genCode(doc, settings, options);
|
|
110
119
|
handled = true;
|
|
111
120
|
logger.info(`publish: Generated code using plugin "${plugin.name}"`);
|
|
112
121
|
} catch (error) {
|
|
@@ -172,7 +181,7 @@ export function resolveCodeGenerationSettings(doc: Document): Required<CliCodeGe
|
|
|
172
181
|
};
|
|
173
182
|
}
|
|
174
183
|
|
|
175
|
-
export function resolvePackageCodegenPlan(pkg: Package, settings: CliCodeGenerationSettings
|
|
184
|
+
export function resolvePackageCodegenPlan(pkg: Package, settings: Required<CliCodeGenerationSettings>, options: PublishCodeGenerationOptions): ResolvedPackageCodegenPlan | null {
|
|
176
185
|
const rawCodePath = (pkg.getCodePath() || settings.codePath || '').trim();
|
|
177
186
|
if (!rawCodePath) return null;
|
|
178
187
|
|
|
@@ -198,11 +207,11 @@ function supportsCodeGenerationLane(doc: Document, codeType: string): boolean {
|
|
|
198
207
|
return false;
|
|
199
208
|
}
|
|
200
209
|
|
|
201
|
-
// Layabox and Cocos Creator currently share the same modern fgui TypeScript output contract.
|
|
202
210
|
function resolveFguiTypescriptVariant(doc: Document): FguiTypescriptVariant | null {
|
|
203
211
|
const projectType = doc.getRoot().getProjectType();
|
|
204
|
-
if (projectType
|
|
205
|
-
return
|
|
212
|
+
if (projectType === ProjectType.LayaBox) return LAYABOX_TYPESCRIPT_VARIANT;
|
|
213
|
+
if (projectType === ProjectType.CocosCreator) return COCOS_CREATOR_TYPESCRIPT_VARIANT;
|
|
214
|
+
return null;
|
|
206
215
|
}
|
|
207
216
|
|
|
208
217
|
async function generateUnityCode(
|
|
@@ -528,9 +537,10 @@ function renderFguiTypescriptBinder(
|
|
|
528
537
|
const bindLines = classes
|
|
529
538
|
.map((classInfo) => `\t\t${variant.runtimeNamespace}.UIObjectFactory.${variant.binderMethod}(${classInfo.encodedClassName}.URL, ${classInfo.encodedClassName});`)
|
|
530
539
|
.join('\n');
|
|
531
|
-
const
|
|
540
|
+
const classImports = classes
|
|
532
541
|
.map((classInfo) => `import ${classInfo.encodedClassName} from "./${classInfo.encodedClassName}";`)
|
|
533
542
|
.join('\n');
|
|
543
|
+
const importLines = [variant.runtimeImport, classImports].filter(Boolean).join('\n');
|
|
534
544
|
|
|
535
545
|
return renderTemplate(FGUI_TYPESCRIPT_BINDER_TEMPLATE, {
|
|
536
546
|
binderClassName: plan.binderClassName,
|
|
@@ -636,6 +646,7 @@ function normalizeTypeName(value: string): string {
|
|
|
636
646
|
|
|
637
647
|
function collectFguiTypescriptImports(classInfo: CodegenClass, variant: FguiTypescriptVariant): string {
|
|
638
648
|
const imports = new Set<string>();
|
|
649
|
+
if (variant.runtimeImport) imports.add(variant.runtimeImport);
|
|
639
650
|
for (const member of classInfo.members) {
|
|
640
651
|
if (member.ignored) continue;
|
|
641
652
|
const translated = translateFguiTypescriptType(member.type, variant);
|
package/src/publish/contracts.ts
CHANGED
|
@@ -65,6 +65,9 @@ export type AtlasRasterInput =
|
|
|
65
65
|
*/
|
|
66
66
|
export interface AtlasRasterPipeline {
|
|
67
67
|
ensureAlpha(): AtlasRasterPipeline;
|
|
68
|
+
removeAlpha(): AtlasRasterPipeline;
|
|
69
|
+
extractChannel(channel: 'alpha'): AtlasRasterPipeline;
|
|
70
|
+
joinChannel(images: Uint8Array[]): AtlasRasterPipeline;
|
|
68
71
|
resize(options: { width: number; height: number; fit?: 'fill' }): AtlasRasterPipeline;
|
|
69
72
|
raw(): AtlasRasterPipeline;
|
|
70
73
|
extract(options: { left: number; top: number; width: number; height: number }): AtlasRasterPipeline;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
isMiscResource,
|
|
11
11
|
isSkeletonResource,
|
|
12
12
|
isSoundResource,
|
|
13
|
+
isSwfResource,
|
|
13
14
|
resolveGenericResourcePath,
|
|
14
15
|
resolveImageFileName,
|
|
15
16
|
resolveImagePath,
|
|
@@ -71,7 +72,7 @@ export async function exportPackageExternalResources(
|
|
|
71
72
|
if (!basePath || !readFileRaw) {
|
|
72
73
|
const hasPublishedExternal = pkg.listResources().some((resource) => {
|
|
73
74
|
return (
|
|
74
|
-
((isMiscResource(resource) || isSkeletonResource(resource)) &&
|
|
75
|
+
((isMiscResource(resource) || isSwfResource(resource) || isSkeletonResource(resource)) &&
|
|
75
76
|
exportedResourceIds.has(resource.getId())) ||
|
|
76
77
|
skeletonDependencyImageIds.has(resource.getId())
|
|
77
78
|
);
|
|
@@ -86,20 +87,25 @@ export async function exportPackageExternalResources(
|
|
|
86
87
|
|
|
87
88
|
for (const resource of pkg.listResources()) {
|
|
88
89
|
const resourceId = resource.getId();
|
|
89
|
-
const
|
|
90
|
-
exportedResourceIds.has(resourceId) &&
|
|
90
|
+
const isExternal =
|
|
91
|
+
exportedResourceIds.has(resourceId) &&
|
|
92
|
+
(isMiscResource(resource) || isSwfResource(resource) || isSkeletonResource(resource));
|
|
91
93
|
const isSkeletonImageDependency = skeletonDependencyImageIds.has(resourceId) && isImageResource(resource);
|
|
92
|
-
if (!
|
|
94
|
+
if (!isExternal && !isSkeletonImageDependency) continue;
|
|
93
95
|
|
|
94
96
|
let sourcePath: string;
|
|
95
97
|
let targetName: string;
|
|
96
98
|
if (isSkeletonImageDependency) {
|
|
97
99
|
sourcePath = resolveImagePath(resource, pkg, basePath);
|
|
98
100
|
targetName = resolveImageFileName(resource);
|
|
99
|
-
} else if (isMiscResource(resource) || isSkeletonResource(resource)) {
|
|
101
|
+
} else if (isMiscResource(resource) || isSwfResource(resource) || isSkeletonResource(resource)) {
|
|
100
102
|
sourcePath = resolveGenericResourcePath(resource, pkg, basePath);
|
|
101
|
-
|
|
103
|
+
const publishedFile =
|
|
102
104
|
((resource.getExtras() as PublishFileExtras | undefined) ?? {})._publishedFile ?? resource.getFile();
|
|
105
|
+
targetName =
|
|
106
|
+
isMiscResource(resource) || isSwfResource(resource)
|
|
107
|
+
? `${pkg.getPublishName() || pkg.getName()}_${publishedFile}`
|
|
108
|
+
: publishedFile;
|
|
103
109
|
} else {
|
|
104
110
|
continue;
|
|
105
111
|
}
|
package/src/publish/options.ts
CHANGED
|
@@ -80,6 +80,8 @@ export interface ResolvedPublishAtlasOptions
|
|
|
80
80
|
| 'allowRotation'
|
|
81
81
|
| 'padding'
|
|
82
82
|
| 'powerOfTwo'
|
|
83
|
+
| 'maxAtlasIndex'
|
|
84
|
+
| 'multipleOfFour'
|
|
83
85
|
| 'square'
|
|
84
86
|
| 'multiPage'
|
|
85
87
|
| 'trimImage'
|
|
@@ -159,10 +161,14 @@ export function resolvePublishOptions(
|
|
|
159
161
|
overrides.fileExtension ??
|
|
160
162
|
(explicitLayaboxTarget ? 'fui' : resolveDefaultPublishFileExtension(projectType, publishSettings));
|
|
161
163
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
const runtimeRejectsCompression =
|
|
165
|
+
projectType === UNITY_PROJECT_TYPE || projectType === COCOS_CREATOR_PROJECT_TYPE;
|
|
166
|
+
if (runtimeRejectsCompression && overrides.compressed === true) {
|
|
167
|
+
throw new Error('publish: The selected target runtime does not support compressed package data.');
|
|
165
168
|
}
|
|
169
|
+
const compressed = runtimeRejectsCompression
|
|
170
|
+
? false
|
|
171
|
+
: (overrides.compressed ?? publishSettings.compressDesc ?? false);
|
|
166
172
|
|
|
167
173
|
const atlasOptions: ResolvedPublishAtlasOptions = {
|
|
168
174
|
maxSize: overrides.atlas?.maxSize ?? atlasSetting.maxSize ?? 2048,
|
|
@@ -171,6 +177,8 @@ export function resolvePublishOptions(
|
|
|
171
177
|
overrides.atlas?.allowRotation ?? (explicitLayaboxTarget ? false : (atlasSetting.allowRotation ?? false)),
|
|
172
178
|
padding: overrides.atlas?.padding ?? atlasSetting.padding ?? 2,
|
|
173
179
|
powerOfTwo: overrides.atlas?.powerOfTwo ?? atlasSetting.sizeOption === 'pot',
|
|
180
|
+
maxAtlasIndex: overrides.atlas?.maxAtlasIndex ?? 10,
|
|
181
|
+
multipleOfFour: overrides.atlas?.multipleOfFour ?? atlasSetting.sizeOption === 'mof',
|
|
174
182
|
square: overrides.atlas?.square ?? atlasSetting.forceSquare ?? false,
|
|
175
183
|
multiPage: overrides.atlas?.multiPage ?? atlasSetting.paging ?? true,
|
|
176
184
|
trimImage: overrides.atlas?.trimImage ?? atlasSetting.trimImage ?? false,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
ProjectType,
|
|
10
10
|
type SoundResource,
|
|
11
11
|
type SpineResource,
|
|
12
|
+
type SwfResource,
|
|
12
13
|
} from '@openfairygui/core';
|
|
13
14
|
import type { AtlasRasterBackend } from './contracts.js';
|
|
14
15
|
import { collectPackageResourceReferences } from './resource-references.js';
|
|
@@ -69,6 +70,12 @@ export function isSoundResource(resource: ReturnType<Package['listResources']>[n
|
|
|
69
70
|
return resource.propertyType === 'SoundResource';
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
export function isSwfResource(
|
|
74
|
+
resource: ReturnType<Package['listResources']>[number],
|
|
75
|
+
): resource is SwfResource {
|
|
76
|
+
return resource.propertyType === 'SwfResource';
|
|
77
|
+
}
|
|
78
|
+
|
|
72
79
|
function isSpineResource(resource: ReturnType<Package['listResources']>[number]): resource is SpineResource {
|
|
73
80
|
return resource.propertyType === 'SpineResource';
|
|
74
81
|
}
|
|
@@ -132,10 +139,15 @@ export function extname(fileName: string): string {
|
|
|
132
139
|
}
|
|
133
140
|
|
|
134
141
|
function resolvePublishedMiscFileName(resource: MiscResource, projectType: number): string {
|
|
135
|
-
const
|
|
136
|
-
if (projectType
|
|
137
|
-
|
|
138
|
-
|
|
142
|
+
const fileName = `${getPublishedId(resource)}${extname(resource.getFile())}`;
|
|
143
|
+
if (projectType === UNITY_PROJECT_TYPE && fileName.toLowerCase().endsWith('.atlas')) {
|
|
144
|
+
return `${fileName}.txt`;
|
|
145
|
+
}
|
|
146
|
+
return fileName;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function resolvePublishedSwfFileName(resource: SwfResource): string {
|
|
150
|
+
return `${getPublishedId(resource)}${extname(resource.getFile()) || '.swf'}`;
|
|
139
151
|
}
|
|
140
152
|
|
|
141
153
|
function resolvePublishedSkeletonFileName(resource: SpineResource | DragonBonesResource, projectType: number): string {
|
|
@@ -235,18 +247,19 @@ function collectHighResolutionItemIds(
|
|
|
235
247
|
resources: ReturnType<Package['listResources']>,
|
|
236
248
|
publishedResourceIds: Set<string>,
|
|
237
249
|
includeHighResolution: number,
|
|
250
|
+
excludedResourceIds: Set<string>,
|
|
238
251
|
): Map<string, Array<string | null>> {
|
|
239
252
|
const result = new Map<string, Array<string | null>>();
|
|
240
253
|
if (includeHighResolution <= 0) return result;
|
|
241
254
|
|
|
242
255
|
const highResolutionResourceByKey = new Map<string, ImageResource | MovieClipResource>();
|
|
243
256
|
for (const resource of resources) {
|
|
244
|
-
if (!isHighResolutionResource(resource)) continue;
|
|
257
|
+
if (!isHighResolutionResource(resource) || excludedResourceIds.has(resource.getId())) continue;
|
|
245
258
|
highResolutionResourceByKey.set(buildHighResolutionResourceKey(resource), resource);
|
|
246
259
|
}
|
|
247
260
|
|
|
248
261
|
for (const resource of resources) {
|
|
249
|
-
if (!isHighResolutionResource(resource)) continue;
|
|
262
|
+
if (!isHighResolutionResource(resource) || excludedResourceIds.has(resource.getId())) continue;
|
|
250
263
|
if (!publishedResourceIds.has(resource.getId())) continue;
|
|
251
264
|
if (isHighResolutionVariantName(resource.getName())) continue;
|
|
252
265
|
|
|
@@ -290,6 +303,7 @@ function collectPackagePublishContext(
|
|
|
290
303
|
},
|
|
291
304
|
): PackagePublishContext {
|
|
292
305
|
const resources = pkg.listResources();
|
|
306
|
+
const excludedResourceIds = new Set(pkg.getSourceAtlasSettings().excludedResourceIds);
|
|
293
307
|
const resourceMap = new Map(resources.map((resource) => [resource.getId(), resource]));
|
|
294
308
|
const referencedIds = collectPackageResourceReferences(pkg).localResourceIds;
|
|
295
309
|
const pixelHitTestImageIds = new Set<string>();
|
|
@@ -304,10 +318,15 @@ function collectPackagePublishContext(
|
|
|
304
318
|
while (changed) {
|
|
305
319
|
changed = false;
|
|
306
320
|
for (const resourceId of [...exportedResourceIds]) {
|
|
321
|
+
if (excludedResourceIds.has(resourceId)) {
|
|
322
|
+
exportedResourceIds.delete(resourceId);
|
|
323
|
+
changed = true;
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
307
326
|
const resource = resourcesById.get(resourceId);
|
|
308
327
|
if (!resource || !isSkeletonResource(resource)) continue;
|
|
309
328
|
for (const requiredId of resource.getRequireIds()) {
|
|
310
|
-
if (!requiredId || exportedResourceIds.has(requiredId)) continue;
|
|
329
|
+
if (!requiredId || excludedResourceIds.has(requiredId) || exportedResourceIds.has(requiredId)) continue;
|
|
311
330
|
exportedResourceIds.add(requiredId);
|
|
312
331
|
changed = true;
|
|
313
332
|
}
|
|
@@ -318,7 +337,7 @@ function collectPackagePublishContext(
|
|
|
318
337
|
|
|
319
338
|
for (const atlas of pkg.listAtlases()) {
|
|
320
339
|
for (const sprite of atlas.listSprites()) {
|
|
321
|
-
spriteItemIds.add(sprite.getItemId());
|
|
340
|
+
if (!excludedResourceIds.has(sprite.getItemId())) spriteItemIds.add(sprite.getItemId());
|
|
322
341
|
}
|
|
323
342
|
}
|
|
324
343
|
|
|
@@ -331,8 +350,8 @@ function collectPackagePublishContext(
|
|
|
331
350
|
const hitTest = component.getHitTest?.()?.trim();
|
|
332
351
|
if (hitTest && !hitTest.includes(',')) {
|
|
333
352
|
const targetChild = childMap.get(hitTest);
|
|
334
|
-
|
|
335
|
-
if (sourceId) {
|
|
353
|
+
const sourceId = (targetChild as { getSrc?(): string } | undefined)?.getSrc?.();
|
|
354
|
+
if (sourceId && !excludedResourceIds.has(sourceId)) {
|
|
336
355
|
const sourceResource = resourceMap.get(sourceId);
|
|
337
356
|
if (sourceResource && isImageResource(sourceResource)) {
|
|
338
357
|
pixelHitTestImageIds.add(sourceId);
|
|
@@ -344,7 +363,7 @@ function collectPackagePublishContext(
|
|
|
344
363
|
const publishedResourceIds = new Set<string>(spriteItemIds);
|
|
345
364
|
for (const resource of resources) {
|
|
346
365
|
const resourceId = resource.getId();
|
|
347
|
-
if (!resourceId) continue;
|
|
366
|
+
if (!resourceId || excludedResourceIds.has(resourceId)) continue;
|
|
348
367
|
if (isComponentResource(resource)) {
|
|
349
368
|
if (resource.getExported() || referencedIds.has(resourceId)) {
|
|
350
369
|
publishedResourceIds.add(resourceId);
|
|
@@ -390,6 +409,7 @@ function collectPackagePublishContext(
|
|
|
390
409
|
resources,
|
|
391
410
|
publishedResourceIds,
|
|
392
411
|
options.includeHighResolution,
|
|
412
|
+
excludedResourceIds,
|
|
393
413
|
);
|
|
394
414
|
|
|
395
415
|
if (!options.includeBranches) {
|
|
@@ -576,6 +596,10 @@ export async function annotatePackagePublishArtifacts(
|
|
|
576
596
|
setPublishedFileExtra(resource, resolvePublishedMiscFileName(resource, options.projectType));
|
|
577
597
|
continue;
|
|
578
598
|
}
|
|
599
|
+
if (isSwfResource(resource)) {
|
|
600
|
+
setPublishedFileExtra(resource, resolvePublishedSwfFileName(resource));
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
579
603
|
if (isSkeletonResource(resource)) {
|
|
580
604
|
setPublishedFileExtra(resource, resolvePublishedSkeletonFileName(resource, options.projectType));
|
|
581
605
|
}
|