@bscotch/gml-parser 1.14.2
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/LICENSE.md +29 -0
- package/README.md +151 -0
- package/assets/GmlSpec.xml +11419 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/jsdoc.d.ts +79 -0
- package/dist/jsdoc.d.ts.map +1 -0
- package/dist/jsdoc.feather.d.ts +23 -0
- package/dist/jsdoc.feather.d.ts.map +1 -0
- package/dist/jsdoc.feather.js +143 -0
- package/dist/jsdoc.feather.js.map +1 -0
- package/dist/jsdoc.js +468 -0
- package/dist/jsdoc.js.map +1 -0
- package/dist/jsdoc.test.d.ts +2 -0
- package/dist/jsdoc.test.d.ts.map +1 -0
- package/dist/jsdoc.test.js +185 -0
- package/dist/jsdoc.test.js.map +1 -0
- package/dist/lexer.d.ts +3 -0
- package/dist/lexer.d.ts.map +1 -0
- package/dist/lexer.js +14 -0
- package/dist/lexer.js.map +1 -0
- package/dist/lexer.test.d.ts +2 -0
- package/dist/lexer.test.d.ts.map +1 -0
- package/dist/lexer.test.js +78 -0
- package/dist/lexer.test.js.map +1 -0
- package/dist/lib.objects.d.ts +190 -0
- package/dist/lib.objects.d.ts.map +1 -0
- package/dist/lib.objects.js +242 -0
- package/dist/lib.objects.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +14 -0
- package/dist/logger.js.map +1 -0
- package/dist/modules.d.ts +19 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +320 -0
- package/dist/modules.js.map +1 -0
- package/dist/modules.test.d.ts +2 -0
- package/dist/modules.test.d.ts.map +1 -0
- package/dist/modules.test.js +57 -0
- package/dist/modules.test.js.map +1 -0
- package/dist/modules.types.d.ts +78 -0
- package/dist/modules.types.d.ts.map +1 -0
- package/dist/modules.types.js +2 -0
- package/dist/modules.types.js.map +1 -0
- package/dist/modules.util.d.ts +5 -0
- package/dist/modules.util.d.ts.map +1 -0
- package/dist/modules.util.js +13 -0
- package/dist/modules.util.js.map +1 -0
- package/dist/parser.d.ts +121 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +571 -0
- package/dist/parser.js.map +1 -0
- package/dist/parser.test.d.ts +2 -0
- package/dist/parser.test.d.ts.map +1 -0
- package/dist/parser.test.js +143 -0
- package/dist/parser.test.js.map +1 -0
- package/dist/parser.utility.d.ts +29 -0
- package/dist/parser.utility.d.ts.map +1 -0
- package/dist/parser.utility.js +125 -0
- package/dist/parser.utility.js.map +1 -0
- package/dist/project.asset.d.ts +115 -0
- package/dist/project.asset.d.ts.map +1 -0
- package/dist/project.asset.js +802 -0
- package/dist/project.asset.js.map +1 -0
- package/dist/project.code.d.ts +130 -0
- package/dist/project.code.d.ts.map +1 -0
- package/dist/project.code.js +570 -0
- package/dist/project.code.js.map +1 -0
- package/dist/project.d.ts +533 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.diagnostics.d.ts +32 -0
- package/dist/project.diagnostics.d.ts.map +1 -0
- package/dist/project.diagnostics.js +23 -0
- package/dist/project.diagnostics.js.map +1 -0
- package/dist/project.js +1216 -0
- package/dist/project.js.map +1 -0
- package/dist/project.location.d.ts +133 -0
- package/dist/project.location.d.ts.map +1 -0
- package/dist/project.location.js +219 -0
- package/dist/project.location.js.map +1 -0
- package/dist/project.native.d.ts +26 -0
- package/dist/project.native.d.ts.map +1 -0
- package/dist/project.native.js +321 -0
- package/dist/project.native.js.map +1 -0
- package/dist/project.spec.d.ts +1298 -0
- package/dist/project.spec.d.ts.map +1 -0
- package/dist/project.spec.js +263 -0
- package/dist/project.spec.js.map +1 -0
- package/dist/project.test.d.ts +2 -0
- package/dist/project.test.d.ts.map +1 -0
- package/dist/project.test.js +633 -0
- package/dist/project.test.js.map +1 -0
- package/dist/shaderDefaults.d.ts +3 -0
- package/dist/shaderDefaults.d.ts.map +1 -0
- package/dist/shaderDefaults.js +32 -0
- package/dist/shaderDefaults.js.map +1 -0
- package/dist/signifiers.d.ts +54 -0
- package/dist/signifiers.d.ts.map +1 -0
- package/dist/signifiers.flags.d.ts +38 -0
- package/dist/signifiers.flags.d.ts.map +1 -0
- package/dist/signifiers.flags.js +131 -0
- package/dist/signifiers.flags.js.map +1 -0
- package/dist/signifiers.js +117 -0
- package/dist/signifiers.js.map +1 -0
- package/dist/spine.d.ts +28 -0
- package/dist/spine.d.ts.map +1 -0
- package/dist/spine.js +64 -0
- package/dist/spine.js.map +1 -0
- package/dist/spine.test.d.ts +2 -0
- package/dist/spine.test.d.ts.map +1 -0
- package/dist/spine.test.js +420 -0
- package/dist/spine.test.js.map +1 -0
- package/dist/spine.types.d.ts +89 -0
- package/dist/spine.types.d.ts.map +1 -0
- package/dist/spine.types.js +2 -0
- package/dist/spine.types.js.map +1 -0
- package/dist/test.lib.d.ts +3 -0
- package/dist/test.lib.d.ts.map +1 -0
- package/dist/test.lib.js +16 -0
- package/dist/test.lib.js.map +1 -0
- package/dist/tokens.categories.d.ts +22 -0
- package/dist/tokens.categories.d.ts.map +1 -0
- package/dist/tokens.categories.js +78 -0
- package/dist/tokens.categories.js.map +1 -0
- package/dist/tokens.code.d.ts +2 -0
- package/dist/tokens.code.d.ts.map +1 -0
- package/dist/tokens.code.js +523 -0
- package/dist/tokens.code.js.map +1 -0
- package/dist/tokens.d.ts +130 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +13 -0
- package/dist/tokens.js.map +1 -0
- package/dist/tokens.lib.d.ts +15 -0
- package/dist/tokens.lib.d.ts.map +1 -0
- package/dist/tokens.lib.js +12 -0
- package/dist/tokens.lib.js.map +1 -0
- package/dist/tokens.shared.d.ts +4 -0
- package/dist/tokens.shared.d.ts.map +1 -0
- package/dist/tokens.shared.js +35 -0
- package/dist/tokens.shared.js.map +1 -0
- package/dist/tokens.strings.d.ts +5 -0
- package/dist/tokens.strings.d.ts.map +1 -0
- package/dist/tokens.strings.js +111 -0
- package/dist/tokens.strings.js.map +1 -0
- package/dist/types.checks.d.ts +50 -0
- package/dist/types.checks.d.ts.map +1 -0
- package/dist/types.checks.js +246 -0
- package/dist/types.checks.js.map +1 -0
- package/dist/types.d.ts +152 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.feather.d.ts +21 -0
- package/dist/types.feather.d.ts.map +1 -0
- package/dist/types.feather.js +156 -0
- package/dist/types.feather.js.map +1 -0
- package/dist/types.hover.d.ts +4 -0
- package/dist/types.hover.d.ts.map +1 -0
- package/dist/types.hover.js +99 -0
- package/dist/types.hover.js.map +1 -0
- package/dist/types.js +457 -0
- package/dist/types.js.map +1 -0
- package/dist/types.primitives.d.ts +10 -0
- package/dist/types.primitives.d.ts.map +1 -0
- package/dist/types.primitives.js +88 -0
- package/dist/types.primitives.js.map +1 -0
- package/dist/types.sprites.d.ts +8 -0
- package/dist/types.sprites.d.ts.map +1 -0
- package/dist/types.sprites.js +417 -0
- package/dist/types.sprites.js.map +1 -0
- package/dist/types.test.d.ts +2 -0
- package/dist/types.test.d.ts.map +1 -0
- package/dist/types.test.js +62 -0
- package/dist/types.test.js.map +1 -0
- package/dist/util.d.ts +50 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +168 -0
- package/dist/util.js.map +1 -0
- package/dist/util.test.d.ts +3 -0
- package/dist/util.test.d.ts.map +1 -0
- package/dist/util.test.js +63 -0
- package/dist/util.test.js.map +1 -0
- package/dist/visitor.assign.d.ts +24 -0
- package/dist/visitor.assign.d.ts.map +1 -0
- package/dist/visitor.assign.js +112 -0
- package/dist/visitor.assign.js.map +1 -0
- package/dist/visitor.d.ts +89 -0
- package/dist/visitor.d.ts.map +1 -0
- package/dist/visitor.functionExpression.d.ts +7 -0
- package/dist/visitor.functionExpression.d.ts.map +1 -0
- package/dist/visitor.functionExpression.js +216 -0
- package/dist/visitor.functionExpression.js.map +1 -0
- package/dist/visitor.globals.d.ts +59 -0
- package/dist/visitor.globals.d.ts.map +1 -0
- package/dist/visitor.globals.js +271 -0
- package/dist/visitor.globals.js.map +1 -0
- package/dist/visitor.identifierAccessor.d.ts +6 -0
- package/dist/visitor.identifierAccessor.d.ts.map +1 -0
- package/dist/visitor.identifierAccessor.js +381 -0
- package/dist/visitor.identifierAccessor.js.map +1 -0
- package/dist/visitor.js +605 -0
- package/dist/visitor.js.map +1 -0
- package/dist/visitor.processor.d.ts +66 -0
- package/dist/visitor.processor.d.ts.map +1 -0
- package/dist/visitor.processor.js +147 -0
- package/dist/visitor.processor.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { pathy } from '@bscotch/pathy';
|
|
3
|
+
import { sequential } from '@bscotch/utility';
|
|
4
|
+
import { Yy, yyObjectEventSchema, yyRoomInstanceLayerSchema, yyRoomInstanceSchema, yySchemas, yySpriteSchema, } from '@bscotch/yy';
|
|
5
|
+
import { logger } from './logger.js';
|
|
6
|
+
import { Code } from './project.code.js';
|
|
7
|
+
import { Diagnostic } from './project.diagnostics.js';
|
|
8
|
+
import { Signifier } from './signifiers.js';
|
|
9
|
+
import { Type } from './types.js';
|
|
10
|
+
import { assert, getPngSize, groupPathToPosix, ok } from './util.js';
|
|
11
|
+
export function isAssetOfKind(asset, kind) {
|
|
12
|
+
return (asset !== null && typeof asset === 'object' && asset.assetKind === kind);
|
|
13
|
+
}
|
|
14
|
+
export function assertIsAssetOfKind(asset, kind) {
|
|
15
|
+
assert(isAssetOfKind(asset, kind), `Expected asset to be of kind ${kind}`);
|
|
16
|
+
}
|
|
17
|
+
export class Asset {
|
|
18
|
+
project;
|
|
19
|
+
resource;
|
|
20
|
+
$tag = 'Asset';
|
|
21
|
+
assetKind;
|
|
22
|
+
gmlFiles = new Map();
|
|
23
|
+
yy;
|
|
24
|
+
yyPath;
|
|
25
|
+
signifier;
|
|
26
|
+
/** For objects, their instance type. */
|
|
27
|
+
instanceType;
|
|
28
|
+
assetType;
|
|
29
|
+
variables;
|
|
30
|
+
nativeVariables;
|
|
31
|
+
/** For objects, their parent */
|
|
32
|
+
_parent = undefined;
|
|
33
|
+
initalized = {
|
|
34
|
+
globals: false,
|
|
35
|
+
locals: false,
|
|
36
|
+
};
|
|
37
|
+
constructor(project, resource, yyPath) {
|
|
38
|
+
this.project = project;
|
|
39
|
+
this.resource = resource;
|
|
40
|
+
assert(yyPath, 'Must provide a YY path');
|
|
41
|
+
this.assetKind = resource.id.path.split(/[/\\]/)[0];
|
|
42
|
+
this.yyPath = yyPath.withValidator(yySchemas[this.assetKind]);
|
|
43
|
+
// Create the symbol
|
|
44
|
+
this.signifier = new Signifier(this.project.self, this.name);
|
|
45
|
+
this.signifier.def = {};
|
|
46
|
+
this.signifier.global = true;
|
|
47
|
+
this.signifier.asset = true;
|
|
48
|
+
// Create the Asset.<> type
|
|
49
|
+
this.assetType = new Type(this.assetTypeKind).named(this.name);
|
|
50
|
+
this.signifier.setType(this.assetType);
|
|
51
|
+
this.assetType.signifier = this.signifier;
|
|
52
|
+
// Add this asset to the project lookup, unless it is a script.
|
|
53
|
+
if (!['scripts', 'extensions'].includes(this.assetKind)) {
|
|
54
|
+
this.project.self.addMember(this.signifier);
|
|
55
|
+
if (this.assetType.kind !== 'Any') {
|
|
56
|
+
this.project.types.set(this.typeName, this.assetType);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// If this is an object, also create the instance type
|
|
60
|
+
if (this.assetKind === 'objects') {
|
|
61
|
+
this.nativeVariables = Type.Struct;
|
|
62
|
+
// Create the base struct-type to store all of the variables.
|
|
63
|
+
for (const member of this.project.native.objectInstanceBase.listMembers()) {
|
|
64
|
+
if (member.name === 'id')
|
|
65
|
+
continue; // This is added later
|
|
66
|
+
const copy = member.copy();
|
|
67
|
+
copy.override = true; // Guarantee we keep this as a copy
|
|
68
|
+
this.nativeVariables.addMember(copy);
|
|
69
|
+
}
|
|
70
|
+
this.variables = new Type('Struct');
|
|
71
|
+
this.variables.extends = this.nativeVariables;
|
|
72
|
+
this.variables.signifier = this.signifier;
|
|
73
|
+
// It will be used as the parent for the Instance/Asset types
|
|
74
|
+
this.assetType.extends = this.variables;
|
|
75
|
+
this.instanceType = new Type('Id.Instance').named(this.name);
|
|
76
|
+
this.instanceType.extends = this.variables;
|
|
77
|
+
this.instanceType.signifier = this.signifier;
|
|
78
|
+
const id = new Signifier(this.variables, 'id', this.instanceType);
|
|
79
|
+
id.instance = true;
|
|
80
|
+
id.native = 'Base';
|
|
81
|
+
id.writable = false;
|
|
82
|
+
id.override = true; // We are guaranteeing that we're using
|
|
83
|
+
this.variables.addMember(id);
|
|
84
|
+
this.project.types.set(this.instanceTypeName, this.instanceType);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
get typeName() {
|
|
88
|
+
return `${this.assetType.kind}.${this.name}`;
|
|
89
|
+
}
|
|
90
|
+
get instanceTypeName() {
|
|
91
|
+
return `Id.Instance.${this.name}`;
|
|
92
|
+
}
|
|
93
|
+
async saveYy() {
|
|
94
|
+
assert(this.yyPath, 'Cannot save YY without a path');
|
|
95
|
+
await Yy.write(this.yyPath.absolute, this.yy, this.assetKind, this.project.yyp);
|
|
96
|
+
}
|
|
97
|
+
get isScript() {
|
|
98
|
+
return this.assetKind === 'scripts';
|
|
99
|
+
}
|
|
100
|
+
get isObject() {
|
|
101
|
+
return this.assetKind === 'objects';
|
|
102
|
+
}
|
|
103
|
+
get isSound() {
|
|
104
|
+
return this.assetKind === 'sounds';
|
|
105
|
+
}
|
|
106
|
+
get isRoom() {
|
|
107
|
+
return this.assetKind === 'rooms';
|
|
108
|
+
}
|
|
109
|
+
get isSprite() {
|
|
110
|
+
return this.assetKind === 'sprites';
|
|
111
|
+
}
|
|
112
|
+
get isSpineSprite() {
|
|
113
|
+
if (this.assetKind !== 'sprites') {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const yy = this.yy;
|
|
117
|
+
return yy.type === 2;
|
|
118
|
+
}
|
|
119
|
+
get soundFile() {
|
|
120
|
+
assert(isAssetOfKind(this, 'sounds'), 'Can only get sound files from sound assets');
|
|
121
|
+
const yy = this.yy;
|
|
122
|
+
return this.dir.join(yy.soundFile);
|
|
123
|
+
}
|
|
124
|
+
get sprite() {
|
|
125
|
+
assert(isAssetOfKind(this, 'objects'), 'Can only get sprites from objects');
|
|
126
|
+
const yy = this.yy;
|
|
127
|
+
const spriteName = yy.spriteId?.name;
|
|
128
|
+
const sprite = spriteName
|
|
129
|
+
? this.project.getAssetByName(spriteName)
|
|
130
|
+
: undefined;
|
|
131
|
+
if (spriteName && !sprite) {
|
|
132
|
+
logger.warn(`Sprite ${spriteName} has no asset`);
|
|
133
|
+
}
|
|
134
|
+
return sprite;
|
|
135
|
+
}
|
|
136
|
+
set sprite(sprite) {
|
|
137
|
+
assert(isAssetOfKind(this, 'objects'), 'Can only set sprites on objects');
|
|
138
|
+
const yy = this.yy;
|
|
139
|
+
yy.spriteId = sprite ? sprite.resource.id : null;
|
|
140
|
+
// Fire off async to avoid blocking
|
|
141
|
+
void this.saveYy();
|
|
142
|
+
}
|
|
143
|
+
get children() {
|
|
144
|
+
assert(isAssetOfKind(this, 'objects'), 'Can only get children of objects');
|
|
145
|
+
const children = [];
|
|
146
|
+
for (const asset of this.project.assets.values()) {
|
|
147
|
+
if (isAssetOfKind(asset, 'objects') && asset.parent === this) {
|
|
148
|
+
children.push(asset);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return children;
|
|
152
|
+
}
|
|
153
|
+
get parent() {
|
|
154
|
+
return this._parent;
|
|
155
|
+
}
|
|
156
|
+
set parent(parent) {
|
|
157
|
+
const oldParent = this._parent;
|
|
158
|
+
if (oldParent === parent) {
|
|
159
|
+
// No change!
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
this._parent = parent;
|
|
163
|
+
if (parent) {
|
|
164
|
+
// The instanceType parent is a struct that holds all of this
|
|
165
|
+
// object's instance variables. We need to set ITS parent to
|
|
166
|
+
// the parent's instanceType.
|
|
167
|
+
this.variables.extends = parent.variables;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
this.variables.extends = this.nativeVariables;
|
|
171
|
+
}
|
|
172
|
+
// Do we need to change the yy file?
|
|
173
|
+
const yy = this.yy;
|
|
174
|
+
const parentFromYy = this.project.getAssetByName(yy.parentObjectId?.name);
|
|
175
|
+
if (parentFromYy !== parent) {
|
|
176
|
+
// Then we need to update the yy. Just fire it off async for now so
|
|
177
|
+
// that this function can remain synchronous.
|
|
178
|
+
if (!parent) {
|
|
179
|
+
yy.parentObjectId = null;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
yy.parentObjectId = parent.resource.id;
|
|
183
|
+
}
|
|
184
|
+
// TODO: Maybe reprocess?
|
|
185
|
+
this.updateDiagnostics();
|
|
186
|
+
void this.saveYy();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get the entire parent heirarchy, with immediate first
|
|
191
|
+
* and most-distant last
|
|
192
|
+
*/
|
|
193
|
+
get parents() {
|
|
194
|
+
if (!this.parent) {
|
|
195
|
+
return [];
|
|
196
|
+
}
|
|
197
|
+
return [this.parent, ...this.parent.parents];
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Get the first GML file belonging to this resource.
|
|
201
|
+
* For scripts, this is the *only* GML file.*/
|
|
202
|
+
get gmlFile() {
|
|
203
|
+
return this.gmlFilesArray[0];
|
|
204
|
+
}
|
|
205
|
+
get gmlFilesArray() {
|
|
206
|
+
return [...this.gmlFiles.values()].sort((a, b) => {
|
|
207
|
+
if (a.name === 'Create_0') {
|
|
208
|
+
return -1;
|
|
209
|
+
}
|
|
210
|
+
else if (b.name === 'Create_0') {
|
|
211
|
+
return 1;
|
|
212
|
+
}
|
|
213
|
+
return 0;
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
getEventByName(name) {
|
|
217
|
+
assert(this.isObject, 'Can only get events for objects');
|
|
218
|
+
return this.gmlFilesArray.find((gml) => gml.name === name);
|
|
219
|
+
}
|
|
220
|
+
get shaderPaths() {
|
|
221
|
+
if (this.assetKind !== 'shaders') {
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
vertex: this.yyPath.changeExtension('vsh'),
|
|
226
|
+
fragment: this.yyPath.changeExtension('fsh'),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
get roomInstances() {
|
|
230
|
+
assertIsAssetOfKind(this, 'rooms');
|
|
231
|
+
const instances = new Map();
|
|
232
|
+
// Loop through each instance layer's instances to get IDs and objects
|
|
233
|
+
const yy = this.yy;
|
|
234
|
+
for (const layer of yy.layers) {
|
|
235
|
+
if (layer.resourceType !== 'GMRInstanceLayer') {
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
for (const instance of layer.instances || []) {
|
|
239
|
+
const obj = this.project.getAssetByName(instance.objectId.name);
|
|
240
|
+
if (isAssetOfKind(obj, 'objects')) {
|
|
241
|
+
instances.set(instance.name, obj);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// Loop through the instance order to get everything in the expected order
|
|
246
|
+
return yy.instanceCreationOrder
|
|
247
|
+
.map((x) => ({
|
|
248
|
+
instanceId: x.name,
|
|
249
|
+
object: instances.get(x.name),
|
|
250
|
+
}))
|
|
251
|
+
.filter((x) => !!x.object);
|
|
252
|
+
}
|
|
253
|
+
get frameIds() {
|
|
254
|
+
if (this.assetKind !== 'sprites') {
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
const yy = this.yy;
|
|
258
|
+
return yy.frames.map((f) => f.name);
|
|
259
|
+
}
|
|
260
|
+
get framePaths() {
|
|
261
|
+
const paths = [];
|
|
262
|
+
if (this.assetKind !== 'sprites') {
|
|
263
|
+
return paths;
|
|
264
|
+
}
|
|
265
|
+
const yy = this.yy;
|
|
266
|
+
for (const frame of yy.frames || []) {
|
|
267
|
+
paths.push(this.dir.join(`${frame.name}.png`));
|
|
268
|
+
}
|
|
269
|
+
return paths;
|
|
270
|
+
}
|
|
271
|
+
get spinePaths() {
|
|
272
|
+
if (!this.isSpineSprite) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
const yy = this.yy;
|
|
276
|
+
const frameId = yy.frames?.[0].name;
|
|
277
|
+
if (!frameId) {
|
|
278
|
+
return undefined;
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
json: this.dir.join(`${frameId}.json`),
|
|
282
|
+
atlas: this.dir.join(`${frameId}.atlas`),
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* During an Object asset rename, we need to ensure that all references to the
|
|
287
|
+
* old name are updated to the new name. This includes the object's name in rooms.
|
|
288
|
+
*/
|
|
289
|
+
async renameRoomInstanceObjects(oldObjectName, newObjectName) {
|
|
290
|
+
assert(this.isRoom, 'Can only rename object instances in rooms'); // Iterate through each instance layer and remove any instances with the given ID
|
|
291
|
+
const yy = this.yy;
|
|
292
|
+
let didUpdate = false;
|
|
293
|
+
for (const layer of yy.layers) {
|
|
294
|
+
if (layer.resourceType !== 'GMRInstanceLayer') {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
layer.instances.forEach((instance) => {
|
|
298
|
+
if (instance.objectId.name.toLowerCase() === oldObjectName.toLowerCase()) {
|
|
299
|
+
instance.objectId.name = newObjectName;
|
|
300
|
+
instance.objectId.path = `objects/${newObjectName}/${newObjectName}.yy`;
|
|
301
|
+
didUpdate = true;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
if (didUpdate) {
|
|
306
|
+
await this.saveYy();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
async removeRoomInstance(instanceId) {
|
|
310
|
+
assert(this.isRoom, 'Can only add object instances to rooms');
|
|
311
|
+
const yy = this.yy;
|
|
312
|
+
// Iterate through each instance layer and remove any instances with the given ID
|
|
313
|
+
for (const layer of yy.layers) {
|
|
314
|
+
if (layer.resourceType !== 'GMRInstanceLayer') {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
layer.instances = (layer.instances || []).filter((x) => x.name !== instanceId);
|
|
318
|
+
}
|
|
319
|
+
// Remove the instance from the creation order
|
|
320
|
+
yy.instanceCreationOrder = (yy.instanceCreationOrder || []).filter((x) => x.name !== instanceId);
|
|
321
|
+
await this.saveYy();
|
|
322
|
+
}
|
|
323
|
+
async reorganizeRoomInstances(instanceIds) {
|
|
324
|
+
assert(this.isRoom, 'Can only add object instances to rooms');
|
|
325
|
+
const instanceIdsSet = new Set(instanceIds);
|
|
326
|
+
assert(instanceIds.length === instanceIdsSet.size, 'Cannot have duplicate instance IDs');
|
|
327
|
+
const yy = this.yy;
|
|
328
|
+
const currentIds = new Set(yy.instanceCreationOrder.map((x) => x.name));
|
|
329
|
+
// Ensure that the new order includes all existing instances
|
|
330
|
+
assert(instanceIdsSet.size === currentIds.size &&
|
|
331
|
+
[...instanceIdsSet].every((x) => currentIds.has(x)), 'New order must include all existing instances');
|
|
332
|
+
yy.instanceCreationOrder = instanceIds.map((name) => ({
|
|
333
|
+
name,
|
|
334
|
+
path: `rooms/${this.name}/${this.name}.yy`,
|
|
335
|
+
}));
|
|
336
|
+
await this.saveYy();
|
|
337
|
+
}
|
|
338
|
+
async addRoomInstance(obj, x = 0, y = 0) {
|
|
339
|
+
assert(this.isRoom, 'Can only add object instances to rooms');
|
|
340
|
+
const yy = this.yy;
|
|
341
|
+
// Ensure we have an instance layer
|
|
342
|
+
let instanceLayer = yy.layers.find((x) => x.resourceType === 'GMRInstanceLayer');
|
|
343
|
+
if (!instanceLayer) {
|
|
344
|
+
instanceLayer = yyRoomInstanceLayerSchema.parse({});
|
|
345
|
+
yy.layers.unshift(instanceLayer);
|
|
346
|
+
}
|
|
347
|
+
// Add a new instance
|
|
348
|
+
const instance = yyRoomInstanceSchema.parse({
|
|
349
|
+
objectId: obj.resource.id,
|
|
350
|
+
x,
|
|
351
|
+
y,
|
|
352
|
+
});
|
|
353
|
+
instanceLayer.instances.push(instance);
|
|
354
|
+
yy.instanceCreationOrder ||= [];
|
|
355
|
+
yy.instanceCreationOrder.push({
|
|
356
|
+
name: instance.name,
|
|
357
|
+
path: `rooms/${this.name}/${this.name}.yy`,
|
|
358
|
+
});
|
|
359
|
+
await this.saveYy();
|
|
360
|
+
}
|
|
361
|
+
get folder() {
|
|
362
|
+
return groupPathToPosix(this.yy.parent.path);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Check if this asset is in the given asset group ("folder").
|
|
366
|
+
* @param path E.g. `my/folder/of/stuff`
|
|
367
|
+
*/
|
|
368
|
+
isInFolder(path) {
|
|
369
|
+
// Normalize the incoming path
|
|
370
|
+
path = groupPathToPosix(path);
|
|
371
|
+
const currentFolder = this.folder;
|
|
372
|
+
return path === currentFolder || currentFolder.startsWith(`${path}/`);
|
|
373
|
+
}
|
|
374
|
+
/** Move to a different, *existing* folder. */
|
|
375
|
+
async moveToFolder(path) {
|
|
376
|
+
assert(path, 'Must provide a path with non-zero length!');
|
|
377
|
+
if (!path.endsWith('.yy')) {
|
|
378
|
+
path = `folders/${path}.yy`;
|
|
379
|
+
}
|
|
380
|
+
const folderName = path
|
|
381
|
+
.split(/[/\\]+/)
|
|
382
|
+
.pop()
|
|
383
|
+
.replace(/\.yy$/, '');
|
|
384
|
+
// Make sure that folder exists.
|
|
385
|
+
assert(folderName, 'Folder name is empty');
|
|
386
|
+
assert(this.project.yyp.Folders.find((x) => x.folderPath === path), `Folder ${path} does not exist`);
|
|
387
|
+
assert(this.yy.parent, 'Asset has no folder field');
|
|
388
|
+
// @ts-expect-error
|
|
389
|
+
logger.info('moving', this.name, 'from', this.yy.parent.path, 'to', path);
|
|
390
|
+
this.yy.parent = { name: folderName, path };
|
|
391
|
+
await this.saveYy();
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Re-order the existing frames of a sprite.
|
|
395
|
+
* Any frames not included in the new order will be deleted.
|
|
396
|
+
*/
|
|
397
|
+
async reorganizeFrames(newFrameIdOrder) {
|
|
398
|
+
assert(this.isSprite, 'Can only delete frames from a sprite');
|
|
399
|
+
assert(!this.isSpineSprite, 'Cannot delete frames from a Spine sprite');
|
|
400
|
+
if (!newFrameIdOrder.length)
|
|
401
|
+
return;
|
|
402
|
+
let yy = this.yy;
|
|
403
|
+
const oldFrameIds = yy.frames.map((x) => x.name);
|
|
404
|
+
assert(newFrameIdOrder.every((x) => oldFrameIds.includes(x)), "Can't reorder frames that don't exist");
|
|
405
|
+
yy.frames = newFrameIdOrder.map((frameId) => {
|
|
406
|
+
const oldFrame = yy.frames.find((x) => x.name === frameId);
|
|
407
|
+
assert(oldFrame, 'Frame not found');
|
|
408
|
+
return oldFrame;
|
|
409
|
+
});
|
|
410
|
+
await this.saveYy();
|
|
411
|
+
// Delete any old frame images
|
|
412
|
+
await Promise.all(oldFrameIds
|
|
413
|
+
.filter((x) => !newFrameIdOrder.includes(x))
|
|
414
|
+
.map((frameId) => {
|
|
415
|
+
const path = this.dir.join(`${frameId}.png`);
|
|
416
|
+
return path.delete();
|
|
417
|
+
}));
|
|
418
|
+
}
|
|
419
|
+
async deleteFrames(frameIds) {
|
|
420
|
+
assert(this.isSprite, 'Can only delete frames from a sprite');
|
|
421
|
+
assert(!this.isSpineSprite, 'Cannot delete frames from a Spine sprite');
|
|
422
|
+
if (!frameIds.length)
|
|
423
|
+
return;
|
|
424
|
+
let yy = this.yy;
|
|
425
|
+
yy.frames = yy.frames.filter((x) => !frameIds.includes(x.name));
|
|
426
|
+
await this.saveYy();
|
|
427
|
+
// TODO: Delete the image files
|
|
428
|
+
await Promise.all(frameIds.map((frameId) => {
|
|
429
|
+
const path = this.dir.join(`${frameId}.png`);
|
|
430
|
+
return path.delete();
|
|
431
|
+
}));
|
|
432
|
+
}
|
|
433
|
+
async addFrames(sourceImages) {
|
|
434
|
+
assert(this.isSprite, 'Can only add frames to a sprite');
|
|
435
|
+
assert(!this.isSpineSprite, 'Cannot add frames to a Spine sprite');
|
|
436
|
+
if (!sourceImages.length)
|
|
437
|
+
return;
|
|
438
|
+
assert(sourceImages.every((x) => x.hasExtension('png')), 'All frames must be PNGs');
|
|
439
|
+
let yy = this.yy;
|
|
440
|
+
let expectedDims;
|
|
441
|
+
if (!yy.frames.length) {
|
|
442
|
+
// Then get the expected dimensions from the first image
|
|
443
|
+
expectedDims = await getPngSize(sourceImages[0]);
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
expectedDims = {
|
|
447
|
+
width: yy.width,
|
|
448
|
+
height: yy.height,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
const frameSizes = await Promise.all(sourceImages.map((x) => getPngSize(x)));
|
|
452
|
+
assert(frameSizes.every((x) => x.width === expectedDims.width && x.height === expectedDims.height), `Expected all frames to have width ${expectedDims.width} and height ${expectedDims.height}`);
|
|
453
|
+
const startingFrameCount = yy.frames.length;
|
|
454
|
+
// Update the YY file to get new frameIds
|
|
455
|
+
yy.frames.length = startingFrameCount + sourceImages.length;
|
|
456
|
+
yy = yySpriteSchema.parse(yy); // Will fill out the new frames
|
|
457
|
+
// Copy the new frames over.
|
|
458
|
+
await Promise.all(sourceImages.map((source, i) => {
|
|
459
|
+
const dest = this.dir.join(`${yy.frames[startingFrameCount + i].name}.png`);
|
|
460
|
+
return source.copy(dest);
|
|
461
|
+
}));
|
|
462
|
+
await this.saveYy();
|
|
463
|
+
}
|
|
464
|
+
async createEvent(eventInfo) {
|
|
465
|
+
assert(this.isObject, 'Can only create events for objects');
|
|
466
|
+
// Create the file if it doesn't already exist
|
|
467
|
+
const path = this.dir.join(`${eventInfo.name}.gml`);
|
|
468
|
+
if (!(await path.exists())) {
|
|
469
|
+
await path.write('/// ');
|
|
470
|
+
}
|
|
471
|
+
// Update the YY file
|
|
472
|
+
const yy = this.yy;
|
|
473
|
+
yy.eventList ||= [];
|
|
474
|
+
if (yy.eventList.find((x) => x.eventNum === eventInfo.eventNum &&
|
|
475
|
+
x.eventType === eventInfo.eventType)) {
|
|
476
|
+
logger.warn(`Event ${eventInfo.name} already exists on ${this.name}`);
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
yy.eventList.push(yyObjectEventSchema.parse({
|
|
480
|
+
eventNum: eventInfo.eventNum,
|
|
481
|
+
eventType: eventInfo.eventType,
|
|
482
|
+
}));
|
|
483
|
+
await this.saveYy();
|
|
484
|
+
return this.addGmlFile(path);
|
|
485
|
+
}
|
|
486
|
+
async readYy() {
|
|
487
|
+
let asPath = pathy(this.yyPath);
|
|
488
|
+
if (!(await asPath.exists())) {
|
|
489
|
+
const filePattern = new RegExp(`${this.name}\\.yy$`, 'i');
|
|
490
|
+
const paths = await pathy(this.dir).listChildren();
|
|
491
|
+
asPath = paths.find((x) => filePattern.test(x.basename));
|
|
492
|
+
}
|
|
493
|
+
ok(asPath, `Could not find a .yy file for ${this.name}`);
|
|
494
|
+
this.yy = await Yy.read(asPath.absolute, this.assetKind);
|
|
495
|
+
return this.yy;
|
|
496
|
+
}
|
|
497
|
+
get dir() {
|
|
498
|
+
return this.yyPath.up();
|
|
499
|
+
}
|
|
500
|
+
get name() {
|
|
501
|
+
return this.resource.id.name;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Reprocess an existing file after it has been modified.
|
|
505
|
+
*/
|
|
506
|
+
async reloadFile(path, virtualContent) {
|
|
507
|
+
const gml = this.getGmlFile(path);
|
|
508
|
+
if (!gml) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
await gml.reload(virtualContent, { reloadDirty: true });
|
|
512
|
+
}
|
|
513
|
+
getGmlFile(path) {
|
|
514
|
+
assert(path, 'GML Path does not exist');
|
|
515
|
+
return this.gmlFiles.get(path.absolute.toLocaleLowerCase());
|
|
516
|
+
}
|
|
517
|
+
updateParent() {
|
|
518
|
+
if (this.assetKind !== 'objects') {
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const yy = this.yy;
|
|
522
|
+
if (!yy.parentObjectId) {
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
const parent = this.project.getAssetByName(yy.parentObjectId.name);
|
|
526
|
+
if (!parent || parent.assetKind !== 'objects') {
|
|
527
|
+
// TODO: Add diagnostic if parent missing
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
// Set the parent
|
|
531
|
+
this.parent = parent;
|
|
532
|
+
}
|
|
533
|
+
updateGlobals(initial = false) {
|
|
534
|
+
this.updateParent();
|
|
535
|
+
// Ensure parent is updated first
|
|
536
|
+
if (initial && !this.initalized.globals && this.parent) {
|
|
537
|
+
this.parent.updateGlobals(initial);
|
|
538
|
+
}
|
|
539
|
+
else if (initial && this.initalized.globals) {
|
|
540
|
+
// Already initialized by a child
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
for (const gml of this.gmlFilesArray) {
|
|
544
|
+
gml.updateGlobals();
|
|
545
|
+
}
|
|
546
|
+
this.initalized.globals = true;
|
|
547
|
+
}
|
|
548
|
+
updateAllSymbols(initial = false) {
|
|
549
|
+
// Ensure parent is updated first
|
|
550
|
+
if (initial && !this.initalized.locals && this.parent) {
|
|
551
|
+
this.parent.updateAllSymbols(initial);
|
|
552
|
+
}
|
|
553
|
+
else if (initial && this.initalized.locals) {
|
|
554
|
+
// Already initialized by a child
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
for (const gml of this.gmlFilesArray) {
|
|
558
|
+
gml.updateAllSymbols();
|
|
559
|
+
}
|
|
560
|
+
this.initalized.locals = true;
|
|
561
|
+
}
|
|
562
|
+
updateDiagnostics() {
|
|
563
|
+
for (const gml of this.gmlFilesArray) {
|
|
564
|
+
gml.updateDiagnostics();
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
addGmlFile(path) {
|
|
568
|
+
const gml = this.getGmlFile(path) ||
|
|
569
|
+
new Code(this, path);
|
|
570
|
+
assert(path, 'Cannot add GML file, path does not exist');
|
|
571
|
+
this.gmlFiles.set(path.absolute.toLocaleLowerCase(), gml);
|
|
572
|
+
return gml;
|
|
573
|
+
}
|
|
574
|
+
async reload() {
|
|
575
|
+
// Find all immediate children, which might include legacy GML files
|
|
576
|
+
const [, children] = await Promise.all([
|
|
577
|
+
await this.readYy(),
|
|
578
|
+
this.dir.listChildren(),
|
|
579
|
+
]);
|
|
580
|
+
if (this.assetKind === 'scripts') {
|
|
581
|
+
this.addScriptFile(children);
|
|
582
|
+
}
|
|
583
|
+
else if (this.assetKind === 'objects') {
|
|
584
|
+
this.gmlFiles.clear();
|
|
585
|
+
this.addObjectFile(children);
|
|
586
|
+
}
|
|
587
|
+
else if (this.assetKind === 'extensions') {
|
|
588
|
+
const diagnostics = [];
|
|
589
|
+
// Load constants and functions from the extension
|
|
590
|
+
const typeIndexToName = (idx) => {
|
|
591
|
+
return idx === 1 ? 'String' : 'Real';
|
|
592
|
+
};
|
|
593
|
+
const yy = this.yy;
|
|
594
|
+
for (const file of yy.files) {
|
|
595
|
+
for (const constant of file.constants) {
|
|
596
|
+
if (constant.hidden) {
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
if (this.project.self.getMember(constant.name)) {
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
try {
|
|
603
|
+
// Get the type by parsing the value. For now we'll just check for number or string, else "Any".
|
|
604
|
+
const type = constant.value.startsWith('"')
|
|
605
|
+
? 'String'
|
|
606
|
+
: constant.value.match(/^-?[\d_.]+$/)
|
|
607
|
+
? 'Real'
|
|
608
|
+
: 'Any';
|
|
609
|
+
const signifier = new Signifier(this.project.self, constant.name, new Type(type));
|
|
610
|
+
signifier.macro = true;
|
|
611
|
+
signifier.global = true;
|
|
612
|
+
signifier.writable = false;
|
|
613
|
+
signifier.def = {};
|
|
614
|
+
this.project.self.addMember(signifier);
|
|
615
|
+
}
|
|
616
|
+
catch (err) {
|
|
617
|
+
diagnostics.push(new Diagnostic(`Error loading extension constant: ${constant.name}`, {
|
|
618
|
+
start: { line: 0, column: 0, offset: 0 },
|
|
619
|
+
end: { line: 0, column: 0, offset: 0 },
|
|
620
|
+
}, 'error', err));
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
for (const func of file.functions) {
|
|
624
|
+
if (func.hidden) {
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
if (this.project.self.getMember(func.externalName)) {
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
try {
|
|
631
|
+
const type = new Type('Function')
|
|
632
|
+
.named(func.externalName)
|
|
633
|
+
.describe(func.help);
|
|
634
|
+
type.setReturnType(new Type(typeIndexToName(func.returnType)));
|
|
635
|
+
for (let i = 0; i < func.args.length; i++) {
|
|
636
|
+
const typeIdx = func.args[i];
|
|
637
|
+
type.addParameter(i, `argument${i}`, {
|
|
638
|
+
type: new Type(typeIndexToName(typeIdx)),
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
const signifier = new Signifier(this.project.self, func.name, type);
|
|
642
|
+
signifier.global = true;
|
|
643
|
+
signifier.writable = false;
|
|
644
|
+
signifier.def = {};
|
|
645
|
+
this.project.self.addMember(signifier);
|
|
646
|
+
this.project.types.set(`Function.${func.externalName}`, type);
|
|
647
|
+
}
|
|
648
|
+
catch (err) {
|
|
649
|
+
diagnostics.push(new Diagnostic(`Error loading extension function: ${func.name}`, {
|
|
650
|
+
start: { line: 1, column: 1, offset: 0 },
|
|
651
|
+
end: { line: 1, column: 1, offset: 0 },
|
|
652
|
+
}, 'error', err));
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
this.project.emitDiagnostics(this.yyPath.absolute, diagnostics);
|
|
657
|
+
}
|
|
658
|
+
await this.initiallyReadAndParseGml();
|
|
659
|
+
}
|
|
660
|
+
async onRemove() {
|
|
661
|
+
await Promise.all(this.gmlFilesArray.map((gml) => gml.remove()));
|
|
662
|
+
// Remove this signifier and any global types from the project
|
|
663
|
+
this.project.self.removeMember(this.signifier.name);
|
|
664
|
+
for (const typeName of [this.typeName, this.instanceTypeName]) {
|
|
665
|
+
const type = this.project.types.get(typeName);
|
|
666
|
+
if (type) {
|
|
667
|
+
this.project.types.delete(this.typeName);
|
|
668
|
+
// Try to get any refereneces using this type updated
|
|
669
|
+
for (const ref of type.signifier?.refs || []) {
|
|
670
|
+
ref.file.dirty = true;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
// Remove the associated files
|
|
675
|
+
await this.dir.delete({ force: true, recursive: true });
|
|
676
|
+
}
|
|
677
|
+
addObjectFile(children) {
|
|
678
|
+
// Objects have one file per event, named after the event.
|
|
679
|
+
// The YY file includes the list of events, but references them by
|
|
680
|
+
// numeric identifiers instead of their name. For now we'll just
|
|
681
|
+
// assume that the GML files are correct.
|
|
682
|
+
children
|
|
683
|
+
.filter((p) => p.hasExtension('gml'))
|
|
684
|
+
.forEach((p) => this.addGmlFile(p));
|
|
685
|
+
}
|
|
686
|
+
addScriptFile(children) {
|
|
687
|
+
// Scripts should have exactly one GML file, which is the script itself,
|
|
688
|
+
// named the same as the script (though there could be casing variations)
|
|
689
|
+
const matches = children.filter((p) => p.basename.toLocaleLowerCase() ===
|
|
690
|
+
`${this.name?.toLocaleLowerCase?.()}.gml`);
|
|
691
|
+
if (matches.length !== 1) {
|
|
692
|
+
logger.error(`Script ${this.name} has ${matches.length} GML files. Expected 1.`);
|
|
693
|
+
}
|
|
694
|
+
else {
|
|
695
|
+
this.addGmlFile(matches[0]);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
async initiallyReadAndParseGml() {
|
|
699
|
+
const parseWaits = [];
|
|
700
|
+
for (const file of this.gmlFilesArray) {
|
|
701
|
+
parseWaits.push(file.parse());
|
|
702
|
+
}
|
|
703
|
+
return await Promise.all(parseWaits);
|
|
704
|
+
}
|
|
705
|
+
get assetTypeKind() {
|
|
706
|
+
switch (this.assetKind) {
|
|
707
|
+
case 'objects':
|
|
708
|
+
return 'Asset.GMObject';
|
|
709
|
+
case 'rooms':
|
|
710
|
+
return 'Asset.GMRoom';
|
|
711
|
+
case 'scripts':
|
|
712
|
+
return 'Asset.GMScript';
|
|
713
|
+
case 'sprites':
|
|
714
|
+
return 'Asset.GMSprite';
|
|
715
|
+
case 'sounds':
|
|
716
|
+
return 'Asset.GMSound';
|
|
717
|
+
case 'paths':
|
|
718
|
+
return 'Asset.GMPath';
|
|
719
|
+
case 'shaders':
|
|
720
|
+
return 'Asset.GMShader';
|
|
721
|
+
case 'timelines':
|
|
722
|
+
return 'Asset.GMTimeline';
|
|
723
|
+
case 'fonts':
|
|
724
|
+
return 'Asset.GMFont';
|
|
725
|
+
default:
|
|
726
|
+
return 'Any';
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
static async from(project, resource) {
|
|
730
|
+
let yyPath = project.dir.join(resource.id.path);
|
|
731
|
+
if (!(await yyPath.exists())) {
|
|
732
|
+
const assetsDir = yyPath.up(2);
|
|
733
|
+
const namePattern = new RegExp(`^${resource.id.name}$`, 'i');
|
|
734
|
+
const dir = (await assetsDir.listChildren()).find((p) => p.basename.match(namePattern));
|
|
735
|
+
if (dir) {
|
|
736
|
+
const yyPattern = new RegExp(`^${resource.id.name}\\.yy$`, 'i');
|
|
737
|
+
yyPath = (await dir.listChildren()).find((p) => p.basename.match(yyPattern));
|
|
738
|
+
if (!yyPath) {
|
|
739
|
+
logger.warn(`Could not find file for "${resource.id.path}"`);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
logger.warn(`Could not find folder for "${resource.id.path}"`);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
if (!yyPath) {
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
const item = new Asset(project, resource, yyPath);
|
|
750
|
+
await item.reload();
|
|
751
|
+
return item;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
__decorate([
|
|
755
|
+
sequential,
|
|
756
|
+
__metadata("design:type", Function),
|
|
757
|
+
__metadata("design:paramtypes", []),
|
|
758
|
+
__metadata("design:returntype", Promise)
|
|
759
|
+
], Asset.prototype, "saveYy", null);
|
|
760
|
+
__decorate([
|
|
761
|
+
sequential,
|
|
762
|
+
__metadata("design:type", Function),
|
|
763
|
+
__metadata("design:paramtypes", [String, String]),
|
|
764
|
+
__metadata("design:returntype", Promise)
|
|
765
|
+
], Asset.prototype, "renameRoomInstanceObjects", null);
|
|
766
|
+
__decorate([
|
|
767
|
+
sequential,
|
|
768
|
+
__metadata("design:type", Function),
|
|
769
|
+
__metadata("design:paramtypes", [String]),
|
|
770
|
+
__metadata("design:returntype", Promise)
|
|
771
|
+
], Asset.prototype, "removeRoomInstance", null);
|
|
772
|
+
__decorate([
|
|
773
|
+
sequential,
|
|
774
|
+
__metadata("design:type", Function),
|
|
775
|
+
__metadata("design:paramtypes", [Array]),
|
|
776
|
+
__metadata("design:returntype", Promise)
|
|
777
|
+
], Asset.prototype, "reorganizeRoomInstances", null);
|
|
778
|
+
__decorate([
|
|
779
|
+
sequential,
|
|
780
|
+
__metadata("design:type", Function),
|
|
781
|
+
__metadata("design:paramtypes", [Asset, Object, Object]),
|
|
782
|
+
__metadata("design:returntype", Promise)
|
|
783
|
+
], Asset.prototype, "addRoomInstance", null);
|
|
784
|
+
__decorate([
|
|
785
|
+
sequential,
|
|
786
|
+
__metadata("design:type", Function),
|
|
787
|
+
__metadata("design:paramtypes", [Array]),
|
|
788
|
+
__metadata("design:returntype", Promise)
|
|
789
|
+
], Asset.prototype, "reorganizeFrames", null);
|
|
790
|
+
__decorate([
|
|
791
|
+
sequential,
|
|
792
|
+
__metadata("design:type", Function),
|
|
793
|
+
__metadata("design:paramtypes", [Array]),
|
|
794
|
+
__metadata("design:returntype", Promise)
|
|
795
|
+
], Asset.prototype, "deleteFrames", null);
|
|
796
|
+
__decorate([
|
|
797
|
+
sequential,
|
|
798
|
+
__metadata("design:type", Function),
|
|
799
|
+
__metadata("design:paramtypes", [Array]),
|
|
800
|
+
__metadata("design:returntype", Promise)
|
|
801
|
+
], Asset.prototype, "addFrames", null);
|
|
802
|
+
//# sourceMappingURL=project.asset.js.map
|