@neocompose/cli 0.64.0 → 0.65.0
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/CHANGELOG.md +11 -0
- package/dist/neo.mjs +81 -28
- package/dist/test-worker.mjs +42 -17
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +1 -1
- package/skills/neocompose-cli/references/animation-and-world-authoring.md +31 -0
- package/skills/neocompose-cli/references/cli-development.md +1 -1
- package/skills/neocompose-cli/references/neoscript.md +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.65.0] - 2026-10-03
|
|
4
|
+
|
|
5
|
+
- Move `Collider` from `NeoObject` to `NeoObjectBase`, so sprite objects and layer groups can carry a box collider too. Unity codegen implements `INeoColliderSource` on `NeoObjectBase`.
|
|
6
|
+
- Segment tracks may target a Class member, such as `NeoObjectBase.Collider`. Each frame plays a whole value or `null`. A segment whose class does not fit the target member reports which class it plays. A segment of nullable values cannot target a required member.
|
|
7
|
+
- Constructor arguments and object initializers typed by a class's generic parameter take the site's type argument. `new NeoAnimationSegmentFrame<NeoCollider?>(value: null)` and `{ Value = null }` now compile.
|
|
8
|
+
- Authoring `null` over a member that held a class instance drops the instance's class and constructor metadata. Previously the row kept them, and push rejected it as an invalid value record.
|
|
9
|
+
|
|
10
|
+
## [0.64.1] - 2026-10-02
|
|
11
|
+
|
|
12
|
+
- Reserve `OnChanged` as a member name. Every generated Unity class declares the SDK's `OnChanged` change subscription, so a member by that name now reports `reserved-project-name` instead of pushing the SDK method aside as `OnChanged_2`.
|
|
13
|
+
|
|
3
14
|
## [0.64.0] - 2026-10-02
|
|
4
15
|
|
|
5
16
|
- Compare Class, interface, List, Set, and Dictionary values by identity in `==`, `!=`, `Contains`, `IndexOf`, and `Remove`. Two values with identical fields are no longer equal; two reads of one stored value still are. Primitives, enums, vectors, and media references still compare by value. Compiler revision 16 recompiles every stored body, so existing scripts switch too. A CLI upgrade now invalidates the local build cache, which previously kept serving IR from the older compiler for unchanged source.
|
package/dist/neo.mjs
CHANGED
|
@@ -822,7 +822,11 @@ var init_project_source_identifiers = __esm({
|
|
|
822
822
|
...NEOSCRIPT_KEYWORDS,
|
|
823
823
|
...NEOSCRIPT_BUILTIN_NAMESPACES
|
|
824
824
|
]);
|
|
825
|
-
PROJECT_MEMBER_RESERVED_NAMES = new Set(
|
|
825
|
+
PROJECT_MEMBER_RESERVED_NAMES = /* @__PURE__ */ new Set([
|
|
826
|
+
...NEOSCRIPT_KEYWORDS,
|
|
827
|
+
// Every generated C# class declares the SDK's change subscription.
|
|
828
|
+
"OnChanged"
|
|
829
|
+
]);
|
|
826
830
|
PROJECT_BINDING_RESERVED_NAMES = /* @__PURE__ */ new Set([
|
|
827
831
|
...PROJECT_RESERVED_NAMES,
|
|
828
832
|
"this",
|
|
@@ -14188,11 +14192,18 @@ function validateExpression(expression, expected, scope, environment, uri, range
|
|
|
14188
14192
|
siteArgumentNames,
|
|
14189
14193
|
siteInitializerNames
|
|
14190
14194
|
);
|
|
14195
|
+
const siteTypeArguments = expression.typeArguments?.map(semanticAstType) ?? (expression.className === null ? expected?.arguments : void 0) ?? [];
|
|
14196
|
+
const siteBindings = new Map(
|
|
14197
|
+
declaration.genericParameters.flatMap((parameter4, index) => {
|
|
14198
|
+
const argument2 = siteTypeArguments[index];
|
|
14199
|
+
return argument2 ? [[parameter4.name, argument2]] : [];
|
|
14200
|
+
})
|
|
14201
|
+
);
|
|
14191
14202
|
for (const diagnostic of validateNeoConstructionSite(
|
|
14192
14203
|
environment.construction,
|
|
14193
14204
|
{
|
|
14194
14205
|
className: declaration.name,
|
|
14195
|
-
typeArguments:
|
|
14206
|
+
typeArguments: siteTypeArguments,
|
|
14196
14207
|
argumentNames: variantSite?.argumentNames ?? siteArgumentNames,
|
|
14197
14208
|
initializerNames: variantSite?.initializerNames ?? siteInitializerNames
|
|
14198
14209
|
}
|
|
@@ -14228,7 +14239,7 @@ function validateExpression(expression, expected, scope, environment, uri, range
|
|
|
14228
14239
|
(candidate) => candidate.name === (variantMember ?? named)
|
|
14229
14240
|
) : fields[index];
|
|
14230
14241
|
const expectedType = parameter4?.type ?? field?.type;
|
|
14231
|
-
const expectedSemanticType = declaration.name === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME && named === "collectionValue" ? { name: "string" } : expectedType ? semanticType(expectedType) : void 0;
|
|
14242
|
+
const expectedSemanticType = declaration.name === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME && named === "collectionValue" ? { name: "string" } : expectedType ? substituteSemanticType(semanticType(expectedType), siteBindings) : void 0;
|
|
14232
14243
|
validateExpression(
|
|
14233
14244
|
argument2,
|
|
14234
14245
|
expectedSemanticType,
|
|
@@ -14249,8 +14260,11 @@ function validateExpression(expression, expected, scope, environment, uri, range
|
|
|
14249
14260
|
validateExpression(
|
|
14250
14261
|
entry.value,
|
|
14251
14262
|
field ? substituteSemanticType(
|
|
14252
|
-
|
|
14253
|
-
|
|
14263
|
+
substituteSemanticType(
|
|
14264
|
+
semanticType(field.member.type),
|
|
14265
|
+
field.bindings
|
|
14266
|
+
),
|
|
14267
|
+
siteBindings
|
|
14254
14268
|
) : void 0,
|
|
14255
14269
|
scope,
|
|
14256
14270
|
environment,
|
|
@@ -14465,7 +14479,7 @@ function sourceClassMemberByName(declaration, name, environment, initialBindings
|
|
|
14465
14479
|
function substituteSemanticType(type, bindings) {
|
|
14466
14480
|
const bound = bindings.get(type.name);
|
|
14467
14481
|
if (bound !== void 0 && (type.arguments ?? []).length === 0) {
|
|
14468
|
-
return type.nullable ===
|
|
14482
|
+
return type.nullable === true ? { ...bound, nullable: true } : bound;
|
|
14469
14483
|
}
|
|
14470
14484
|
const argumentsList2 = (type.arguments ?? []).map(
|
|
14471
14485
|
(argument2) => substituteSemanticType(argument2, bindings)
|
|
@@ -22774,7 +22788,12 @@ var init_strict_resolver = __esm({
|
|
|
22774
22788
|
};
|
|
22775
22789
|
});
|
|
22776
22790
|
fields.push(
|
|
22777
|
-
...this.resolveCallSiteInitializerFields(
|
|
22791
|
+
...this.resolveCallSiteInitializerFields(
|
|
22792
|
+
schemaClass2,
|
|
22793
|
+
targetType,
|
|
22794
|
+
expression,
|
|
22795
|
+
scope
|
|
22796
|
+
)
|
|
22778
22797
|
);
|
|
22779
22798
|
const schemaClassInfo = toWireType(targetType, this.project);
|
|
22780
22799
|
if (schemaClassInfo.type !== 7 /* Class */) {
|
|
@@ -22900,6 +22919,7 @@ var init_strict_resolver = __esm({
|
|
|
22900
22919
|
) : [];
|
|
22901
22920
|
const fields = this.resolveCallSiteInitializerFields(
|
|
22902
22921
|
schemaClass2,
|
|
22922
|
+
targetType,
|
|
22903
22923
|
expression,
|
|
22904
22924
|
scope
|
|
22905
22925
|
);
|
|
@@ -23014,7 +23034,7 @@ var init_strict_resolver = __esm({
|
|
|
23014
23034
|
* the class's own schema exactly as a `classConstructor` field is, and
|
|
23015
23035
|
* applied after the body so an explicit assignment always wins.
|
|
23016
23036
|
*/
|
|
23017
|
-
resolveCallSiteInitializerFields(schemaClass2, expression, scope) {
|
|
23037
|
+
resolveCallSiteInitializerFields(schemaClass2, targetType, expression, scope) {
|
|
23018
23038
|
const entries = expression.initializer ?? [];
|
|
23019
23039
|
const seen = /* @__PURE__ */ new Set();
|
|
23020
23040
|
return entries.map((entry) => {
|
|
@@ -23059,10 +23079,15 @@ var init_strict_resolver = __esm({
|
|
|
23059
23079
|
entry.pos
|
|
23060
23080
|
);
|
|
23061
23081
|
}
|
|
23062
|
-
const
|
|
23063
|
-
|
|
23082
|
+
const memberType2 = substituteTypeParameters(
|
|
23083
|
+
member.type,
|
|
23084
|
+
targetType,
|
|
23085
|
+
schemaClass2
|
|
23086
|
+
);
|
|
23087
|
+
const value = this.resolveExpression(entry.value, scope, memberType2);
|
|
23088
|
+
if (!isNeoScriptTypeAssignable(value.type, memberType2, this.project)) {
|
|
23064
23089
|
throw new CompileError(
|
|
23065
|
-
`Object initializer '${member.name}' expected ${this.describe(
|
|
23090
|
+
`Object initializer '${member.name}' expected ${this.describe(memberType2)} but got ${this.describe(value.type)}.`,
|
|
23066
23091
|
entry.pos
|
|
23067
23092
|
);
|
|
23068
23093
|
}
|
|
@@ -29930,7 +29955,7 @@ var init_registry = __esm({
|
|
|
29930
29955
|
"../packages/manifest/schema-contract/registry.mjs"() {
|
|
29931
29956
|
"use strict";
|
|
29932
29957
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
29933
|
-
cliVersion: "0.
|
|
29958
|
+
cliVersion: "0.65.0",
|
|
29934
29959
|
projectFileUploadBatchSize: 32,
|
|
29935
29960
|
documentRecords: {
|
|
29936
29961
|
member: {
|
|
@@ -40272,7 +40297,7 @@ var init_neoscript_compiler_revision = __esm({
|
|
|
40272
40297
|
"use strict";
|
|
40273
40298
|
init_strict_ir();
|
|
40274
40299
|
ACTIVE_NEOSCRIPT_COMPILER_REVISION_ROLLOUT = // <neoscript-compiler-revision-rollout>
|
|
40275
|
-
|
|
40300
|
+
null;
|
|
40276
40301
|
}
|
|
40277
40302
|
});
|
|
40278
40303
|
|
|
@@ -43298,6 +43323,9 @@ function createMergeMemo() {
|
|
|
43298
43323
|
function resolveInheritanceChain(classId, classes, draft) {
|
|
43299
43324
|
return [...indexClasses(classes).inheritanceChain(classId, draft)];
|
|
43300
43325
|
}
|
|
43326
|
+
function resolveInheritanceChainFromIndex(classId, classIndex, draft) {
|
|
43327
|
+
return resolveChainFromIndex(classId, classIndex, draft);
|
|
43328
|
+
}
|
|
43301
43329
|
function resolveChainFromIndex(classId, index, draft) {
|
|
43302
43330
|
const chain = [];
|
|
43303
43331
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -44370,6 +44398,14 @@ var init_world_system_classes_generated = __esm({
|
|
|
44370
44398
|
docsText: "When false, this object and its children are neither rendered nor collided with. The value stays live: member writes still apply and a running animation clip keeps playing. Disabling an object hides its whole subtree regardless of each child's own value, and re-enabling it restores exactly what was there.",
|
|
44371
44399
|
requirement: 1 /* Required */,
|
|
44372
44400
|
schemaKey: "Enabled"
|
|
44401
|
+
},
|
|
44402
|
+
{
|
|
44403
|
+
memberId: "system_a0083c92-72f7-405f-8863-ff86f995d36d",
|
|
44404
|
+
memberKind: "class",
|
|
44405
|
+
defaultValue: null,
|
|
44406
|
+
docsText: "The object's box collider, or null for none. Any world object can carry one: placed objects, nested children, and sprites alike.",
|
|
44407
|
+
schemaClassWorldKind: "objectCollider",
|
|
44408
|
+
schemaKey: "Collider"
|
|
44373
44409
|
}
|
|
44374
44410
|
],
|
|
44375
44411
|
worldKind: "objectBase"
|
|
@@ -44579,13 +44615,6 @@ var init_world_system_classes_generated = __esm({
|
|
|
44579
44615
|
requirement: 1 /* Required */,
|
|
44580
44616
|
schemaKey: "Children"
|
|
44581
44617
|
},
|
|
44582
|
-
{
|
|
44583
|
-
memberId: "system_a0083c92-72f7-405f-8863-ff86f995d36d",
|
|
44584
|
-
memberKind: "class",
|
|
44585
|
-
defaultValue: null,
|
|
44586
|
-
schemaClassWorldKind: "objectCollider",
|
|
44587
|
-
schemaKey: "Collider"
|
|
44588
|
-
},
|
|
44589
44618
|
{
|
|
44590
44619
|
memberId: "system_c609fed3-53e4-5147-b493-e4aa23031d79",
|
|
44591
44620
|
memberKind: "computed",
|
|
@@ -61096,7 +61125,7 @@ function resolveMemberDeclaredTypeInfoInternal(member, members, seen) {
|
|
|
61096
61125
|
members,
|
|
61097
61126
|
nextSeen
|
|
61098
61127
|
);
|
|
61099
|
-
return argumentType === null ? [] : [[genericParamId,
|
|
61128
|
+
return argumentType === null ? [] : [[genericParamId, argumentType]];
|
|
61100
61129
|
}
|
|
61101
61130
|
)
|
|
61102
61131
|
);
|
|
@@ -69918,6 +69947,7 @@ function evaluateNSGetterWithEffects(getter, ctx, argumentValues = [], options =
|
|
|
69918
69947
|
getter.typeInfo
|
|
69919
69948
|
);
|
|
69920
69949
|
result.value = preserveReadOnlyReturnIdentity(result.value, runtimeCtx);
|
|
69950
|
+
options.inspectResult?.(result.value, runtimeCtx);
|
|
69921
69951
|
const createdSessionValues = exportedSessionValuesSince(
|
|
69922
69952
|
runtimeCtx,
|
|
69923
69953
|
creationCheckpoint,
|
|
@@ -73502,7 +73532,7 @@ function runtimeTypeCheck(value, checkType, ctx, seenCollections = /* @__PURE__
|
|
|
73502
73532
|
function runtimeValueMatchesType(value, typeInfo, ctx, seenCollections = /* @__PURE__ */ new Set()) {
|
|
73503
73533
|
if (typeInfo.type === NS_TYPE_UNKNOWN) return true;
|
|
73504
73534
|
if (value === null || value === void 0) {
|
|
73505
|
-
return typeInfo.type === 0 /* Null */ || !typeInfo.required;
|
|
73535
|
+
return typeInfo.type === 0 /* Null */ || typeInfo.type === 21 /* Generic */ || !typeInfo.required;
|
|
73506
73536
|
}
|
|
73507
73537
|
return runtimeTypeCheck(value, typeInfo, ctx, seenCollections);
|
|
73508
73538
|
}
|
|
@@ -73866,7 +73896,8 @@ function createUnorderedListProjectionCache() {
|
|
|
73866
73896
|
byContainerId: /* @__PURE__ */ new Map(),
|
|
73867
73897
|
containerIdByArray: /* @__PURE__ */ new WeakMap(),
|
|
73868
73898
|
scalarEntryIds: /* @__PURE__ */ new Set(),
|
|
73869
|
-
referenceEntryIndexesByArray: /* @__PURE__ */ new WeakMap()
|
|
73899
|
+
referenceEntryIndexesByArray: /* @__PURE__ */ new WeakMap(),
|
|
73900
|
+
referenceEntryKeysByRecord: /* @__PURE__ */ new WeakMap()
|
|
73870
73901
|
};
|
|
73871
73902
|
}
|
|
73872
73903
|
function createUnorderedScalarProjectionEntry(containerValueId, value, ctx, consumeEntryBudget = true) {
|
|
@@ -75399,6 +75430,7 @@ function evalFunction(fn, scope, ctx) {
|
|
|
75399
75430
|
const isList = isListCollection(c);
|
|
75400
75431
|
const out = isList ? [] : {};
|
|
75401
75432
|
const referenceEntryIndexes = /* @__PURE__ */ new Set();
|
|
75433
|
+
const referenceEntryKeys = /* @__PURE__ */ new Set();
|
|
75402
75434
|
const callback = prepareCollectionCallback(
|
|
75403
75435
|
innerFn,
|
|
75404
75436
|
scope,
|
|
@@ -75418,6 +75450,7 @@ function evalFunction(fn, scope, ctx) {
|
|
|
75418
75450
|
}
|
|
75419
75451
|
out.push(valueId ?? entry);
|
|
75420
75452
|
} else {
|
|
75453
|
+
if (valueId !== null) referenceEntryKeys.add(String(key));
|
|
75421
75454
|
out[String(key)] = valueId ?? entry;
|
|
75422
75455
|
}
|
|
75423
75456
|
return 0 /* Continue */;
|
|
@@ -75430,6 +75463,11 @@ function evalFunction(fn, scope, ctx) {
|
|
|
75430
75463
|
referenceEntryIndexes
|
|
75431
75464
|
);
|
|
75432
75465
|
}
|
|
75466
|
+
if (!isList)
|
|
75467
|
+
unorderedListProjectionCache(ctx).referenceEntryKeysByRecord.set(
|
|
75468
|
+
out,
|
|
75469
|
+
referenceEntryKeys
|
|
75470
|
+
);
|
|
75433
75471
|
return out;
|
|
75434
75472
|
}
|
|
75435
75473
|
case "first" /* first */:
|
|
@@ -103103,11 +103141,26 @@ var init_animation_clips = __esm({
|
|
|
103103
103141
|
`${args.label} targets "${boundChildName}.${targetEntry.schemaKey}" of kind ${MemberKind[targetMember.kind]}, but its segment plays ${MemberKind[valueBindingMember.kind]} values.`
|
|
103104
103142
|
);
|
|
103105
103143
|
}
|
|
103106
|
-
if (!
|
|
103107
|
-
|
|
103144
|
+
if (isMemberClass(targetMember) && isMemberClass(valueBindingMember) && !resolveInheritanceChainFromIndex(
|
|
103145
|
+
valueBindingMember.classId,
|
|
103146
|
+
this.classById
|
|
103147
|
+
).some((current) => current.id === targetMember.classId)) {
|
|
103148
|
+
const targetClassName = this.classById.get(targetMember.classId)?.name ?? targetMember.classId;
|
|
103149
|
+
const valueClassName2 = this.classById.get(valueBindingMember.classId)?.name ?? valueBindingMember.classId;
|
|
103150
|
+
throw new Error(
|
|
103151
|
+
`${args.label} targets "${boundChildName}.${targetEntry.schemaKey}" of class ${targetClassName}, but its segment plays ${valueClassName2} values.`
|
|
103152
|
+
);
|
|
103153
|
+
}
|
|
103154
|
+
if (isRequiredMember2(targetMember) && !isRequiredMember2(valueBindingMember)) {
|
|
103155
|
+
throw new Error(
|
|
103156
|
+
`${args.label} targets "${boundChildName}.${targetEntry.schemaKey}", which is required, but its segment plays nullable values.`
|
|
103157
|
+
);
|
|
103158
|
+
}
|
|
103159
|
+
if (animationTrackStorage(
|
|
103108
103160
|
[targetMember.id],
|
|
103161
|
+
this.memberById,
|
|
103109
103162
|
args.childStoragePath
|
|
103110
|
-
)) {
|
|
103163
|
+
) === null) {
|
|
103111
103164
|
throw new Error(
|
|
103112
103165
|
`${args.label} targets "${boundChildName}.${targetEntry.schemaKey}", which is not a writable Save, Session, or Writable override leaf.`
|
|
103113
103166
|
);
|
|
@@ -124527,7 +124580,7 @@ function lowerValueBody(context, member, expression, base, source, environment,
|
|
|
124527
124580
|
if (member.required) {
|
|
124528
124581
|
throw new Error(`Required member ${member.name} cannot store null.`);
|
|
124529
124582
|
}
|
|
124530
|
-
return
|
|
124583
|
+
return overlayLiteralValueContent(next, { value: null });
|
|
124531
124584
|
}
|
|
124532
124585
|
switch (member.kind) {
|
|
124533
124586
|
case "null":
|
|
@@ -156152,7 +156205,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
156152
156205
|
async function main() {
|
|
156153
156206
|
const args = parseArgs(process.argv.slice(2));
|
|
156154
156207
|
if (args.command === "--version") {
|
|
156155
|
-
console.log("0.
|
|
156208
|
+
console.log("0.65.0");
|
|
156156
156209
|
return;
|
|
156157
156210
|
}
|
|
156158
156211
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/dist/test-worker.mjs
CHANGED
|
@@ -2172,7 +2172,11 @@ var PROJECT_RESERVED_NAMES = /* @__PURE__ */ new Set([
|
|
|
2172
2172
|
...NEOSCRIPT_KEYWORDS,
|
|
2173
2173
|
...NEOSCRIPT_BUILTIN_NAMESPACES
|
|
2174
2174
|
]);
|
|
2175
|
-
var PROJECT_MEMBER_RESERVED_NAMES = new Set(
|
|
2175
|
+
var PROJECT_MEMBER_RESERVED_NAMES = /* @__PURE__ */ new Set([
|
|
2176
|
+
...NEOSCRIPT_KEYWORDS,
|
|
2177
|
+
// Every generated C# class declares the SDK's change subscription.
|
|
2178
|
+
"OnChanged"
|
|
2179
|
+
]);
|
|
2176
2180
|
var PROJECT_BINDING_RESERVED_NAMES = /* @__PURE__ */ new Set([
|
|
2177
2181
|
...PROJECT_RESERVED_NAMES,
|
|
2178
2182
|
"this",
|
|
@@ -2224,7 +2228,7 @@ function isValidSchemaNSFunctionBindingIdentifier(value) {
|
|
|
2224
2228
|
// ../src/models/neoscript/neoscript-compiler-revision.ts
|
|
2225
2229
|
var ACTIVE_NEOSCRIPT_COMPILER_REVISION_ROLLOUT = (
|
|
2226
2230
|
// <neoscript-compiler-revision-rollout>
|
|
2227
|
-
|
|
2231
|
+
null
|
|
2228
2232
|
);
|
|
2229
2233
|
function isAcceptedNeoScriptCompilerRevision(stamp, rollout = ACTIVE_NEOSCRIPT_COMPILER_REVISION_ROLLOUT) {
|
|
2230
2234
|
if (stamp === NEOSCRIPT_COMPILER_REVISION) return true;
|
|
@@ -6054,6 +6058,14 @@ var WORLD_SYSTEM_CLASS_DEFINITIONS = [
|
|
|
6054
6058
|
docsText: "When false, this object and its children are neither rendered nor collided with. The value stays live: member writes still apply and a running animation clip keeps playing. Disabling an object hides its whole subtree regardless of each child's own value, and re-enabling it restores exactly what was there.",
|
|
6055
6059
|
requirement: 1 /* Required */,
|
|
6056
6060
|
schemaKey: "Enabled"
|
|
6061
|
+
},
|
|
6062
|
+
{
|
|
6063
|
+
memberId: "system_a0083c92-72f7-405f-8863-ff86f995d36d",
|
|
6064
|
+
memberKind: "class",
|
|
6065
|
+
defaultValue: null,
|
|
6066
|
+
docsText: "The object's box collider, or null for none. Any world object can carry one: placed objects, nested children, and sprites alike.",
|
|
6067
|
+
schemaClassWorldKind: "objectCollider",
|
|
6068
|
+
schemaKey: "Collider"
|
|
6057
6069
|
}
|
|
6058
6070
|
],
|
|
6059
6071
|
worldKind: "objectBase"
|
|
@@ -6263,13 +6275,6 @@ var WORLD_SYSTEM_CLASS_DEFINITIONS = [
|
|
|
6263
6275
|
requirement: 1 /* Required */,
|
|
6264
6276
|
schemaKey: "Children"
|
|
6265
6277
|
},
|
|
6266
|
-
{
|
|
6267
|
-
memberId: "system_a0083c92-72f7-405f-8863-ff86f995d36d",
|
|
6268
|
-
memberKind: "class",
|
|
6269
|
-
defaultValue: null,
|
|
6270
|
-
schemaClassWorldKind: "objectCollider",
|
|
6271
|
-
schemaKey: "Collider"
|
|
6272
|
-
},
|
|
6273
6278
|
{
|
|
6274
6279
|
memberId: "system_c609fed3-53e4-5147-b493-e4aa23031d79",
|
|
6275
6280
|
memberKind: "computed",
|
|
@@ -15000,6 +15005,7 @@ function evaluateNSGetterWithEffects(getter, ctx, argumentValues = [], options =
|
|
|
15000
15005
|
getter.typeInfo
|
|
15001
15006
|
);
|
|
15002
15007
|
result.value = preserveReadOnlyReturnIdentity(result.value, runtimeCtx);
|
|
15008
|
+
options.inspectResult?.(result.value, runtimeCtx);
|
|
15003
15009
|
const createdSessionValues = exportedSessionValuesSince(
|
|
15004
15010
|
runtimeCtx,
|
|
15005
15011
|
creationCheckpoint,
|
|
@@ -18646,7 +18652,7 @@ function runtimeTypeCheck(value, checkType, ctx, seenCollections = /* @__PURE__
|
|
|
18646
18652
|
function runtimeValueMatchesType(value, typeInfo, ctx, seenCollections = /* @__PURE__ */ new Set()) {
|
|
18647
18653
|
if (typeInfo.type === NS_TYPE_UNKNOWN) return true;
|
|
18648
18654
|
if (value === null || value === void 0) {
|
|
18649
|
-
return typeInfo.type === 0 /* Null */ || !typeInfo.required;
|
|
18655
|
+
return typeInfo.type === 0 /* Null */ || typeInfo.type === 21 /* Generic */ || !typeInfo.required;
|
|
18650
18656
|
}
|
|
18651
18657
|
return runtimeTypeCheck(value, typeInfo, ctx, seenCollections);
|
|
18652
18658
|
}
|
|
@@ -19010,7 +19016,8 @@ function createUnorderedListProjectionCache() {
|
|
|
19010
19016
|
byContainerId: /* @__PURE__ */ new Map(),
|
|
19011
19017
|
containerIdByArray: /* @__PURE__ */ new WeakMap(),
|
|
19012
19018
|
scalarEntryIds: /* @__PURE__ */ new Set(),
|
|
19013
|
-
referenceEntryIndexesByArray: /* @__PURE__ */ new WeakMap()
|
|
19019
|
+
referenceEntryIndexesByArray: /* @__PURE__ */ new WeakMap(),
|
|
19020
|
+
referenceEntryKeysByRecord: /* @__PURE__ */ new WeakMap()
|
|
19014
19021
|
};
|
|
19015
19022
|
}
|
|
19016
19023
|
function createUnorderedScalarProjectionEntry(containerValueId, value, ctx, consumeEntryBudget = true) {
|
|
@@ -20556,6 +20563,7 @@ function evalFunction(fn, scope, ctx) {
|
|
|
20556
20563
|
const isList = isListCollection(c);
|
|
20557
20564
|
const out = isList ? [] : {};
|
|
20558
20565
|
const referenceEntryIndexes = /* @__PURE__ */ new Set();
|
|
20566
|
+
const referenceEntryKeys = /* @__PURE__ */ new Set();
|
|
20559
20567
|
const callback = prepareCollectionCallback(
|
|
20560
20568
|
innerFn,
|
|
20561
20569
|
scope,
|
|
@@ -20575,6 +20583,7 @@ function evalFunction(fn, scope, ctx) {
|
|
|
20575
20583
|
}
|
|
20576
20584
|
out.push(valueId ?? entry);
|
|
20577
20585
|
} else {
|
|
20586
|
+
if (valueId !== null) referenceEntryKeys.add(String(key));
|
|
20578
20587
|
out[String(key)] = valueId ?? entry;
|
|
20579
20588
|
}
|
|
20580
20589
|
return 0 /* Continue */;
|
|
@@ -20587,6 +20596,11 @@ function evalFunction(fn, scope, ctx) {
|
|
|
20587
20596
|
referenceEntryIndexes
|
|
20588
20597
|
);
|
|
20589
20598
|
}
|
|
20599
|
+
if (!isList)
|
|
20600
|
+
unorderedListProjectionCache(ctx).referenceEntryKeysByRecord.set(
|
|
20601
|
+
out,
|
|
20602
|
+
referenceEntryKeys
|
|
20603
|
+
);
|
|
20590
20604
|
return out;
|
|
20591
20605
|
}
|
|
20592
20606
|
case "first" /* first */:
|
|
@@ -24766,7 +24780,7 @@ function resolveMemberDeclaredTypeInfoInternal(member, members, seen) {
|
|
|
24766
24780
|
members,
|
|
24767
24781
|
nextSeen
|
|
24768
24782
|
);
|
|
24769
|
-
return argumentType === null ? [] : [[genericParamId,
|
|
24783
|
+
return argumentType === null ? [] : [[genericParamId, argumentType]];
|
|
24770
24784
|
}
|
|
24771
24785
|
)
|
|
24772
24786
|
);
|
|
@@ -35264,7 +35278,12 @@ var StrictNeoScriptResolver = class {
|
|
|
35264
35278
|
};
|
|
35265
35279
|
});
|
|
35266
35280
|
fields.push(
|
|
35267
|
-
...this.resolveCallSiteInitializerFields(
|
|
35281
|
+
...this.resolveCallSiteInitializerFields(
|
|
35282
|
+
schemaClass,
|
|
35283
|
+
targetType,
|
|
35284
|
+
expression,
|
|
35285
|
+
scope
|
|
35286
|
+
)
|
|
35268
35287
|
);
|
|
35269
35288
|
const schemaClassInfo = toWireType(targetType, this.project);
|
|
35270
35289
|
if (schemaClassInfo.type !== 7 /* Class */) {
|
|
@@ -35390,6 +35409,7 @@ var StrictNeoScriptResolver = class {
|
|
|
35390
35409
|
) : [];
|
|
35391
35410
|
const fields = this.resolveCallSiteInitializerFields(
|
|
35392
35411
|
schemaClass,
|
|
35412
|
+
targetType,
|
|
35393
35413
|
expression,
|
|
35394
35414
|
scope
|
|
35395
35415
|
);
|
|
@@ -35504,7 +35524,7 @@ var StrictNeoScriptResolver = class {
|
|
|
35504
35524
|
* the class's own schema exactly as a `classConstructor` field is, and
|
|
35505
35525
|
* applied after the body so an explicit assignment always wins.
|
|
35506
35526
|
*/
|
|
35507
|
-
resolveCallSiteInitializerFields(schemaClass, expression, scope) {
|
|
35527
|
+
resolveCallSiteInitializerFields(schemaClass, targetType, expression, scope) {
|
|
35508
35528
|
const entries = expression.initializer ?? [];
|
|
35509
35529
|
const seen = /* @__PURE__ */ new Set();
|
|
35510
35530
|
return entries.map((entry) => {
|
|
@@ -35549,10 +35569,15 @@ var StrictNeoScriptResolver = class {
|
|
|
35549
35569
|
entry.pos
|
|
35550
35570
|
);
|
|
35551
35571
|
}
|
|
35552
|
-
const
|
|
35553
|
-
|
|
35572
|
+
const memberType = substituteTypeParameters(
|
|
35573
|
+
member.type,
|
|
35574
|
+
targetType,
|
|
35575
|
+
schemaClass
|
|
35576
|
+
);
|
|
35577
|
+
const value = this.resolveExpression(entry.value, scope, memberType);
|
|
35578
|
+
if (!isNeoScriptTypeAssignable(value.type, memberType, this.project)) {
|
|
35554
35579
|
throw new CompileError(
|
|
35555
|
-
`Object initializer '${member.name}' expected ${this.describe(
|
|
35580
|
+
`Object initializer '${member.name}' expected ${this.describe(memberType)} but got ${this.describe(value.type)}.`,
|
|
35556
35581
|
entry.pos
|
|
35557
35582
|
);
|
|
35558
35583
|
}
|
package/package.json
CHANGED
|
@@ -388,6 +388,37 @@ frame after a watched dependency changes.
|
|
|
388
388
|
When multiple tracks write the same member in one frame, apply list order and
|
|
389
389
|
let the last write win.
|
|
390
390
|
|
|
391
|
+
A track can target a Class member. Each frame writes its whole value, and a
|
|
392
|
+
`null` frame clears the member. Every `NeoObjectBase`, sprites included,
|
|
393
|
+
declares `Collider`, so a per-frame trigger such as an attack hit box is a
|
|
394
|
+
Session `Collider` override on the child plus a track of `NeoCollider?`
|
|
395
|
+
frames:
|
|
396
|
+
|
|
397
|
+
```neo
|
|
398
|
+
class ColliderAnimationSegment : NeoAnimationSegment<NeoCollider?> {
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
@settings(target: NeoObjectBase.Collider)
|
|
402
|
+
class SwingColliderTrack(NeoDelegate<SwordSprite> selector)
|
|
403
|
+
: NeoAnimationSegmentTrack<SwordSprite, NeoCollider?>(selector: selector) {
|
|
404
|
+
public override ColliderAnimationSegment Segment = new ColliderAnimationSegment() {
|
|
405
|
+
Duration = 3,
|
|
406
|
+
Frames = [
|
|
407
|
+
new NeoAnimationSegmentFrame<NeoCollider?>(value: new NeoCollider() {
|
|
408
|
+
Size = new(1, 1),
|
|
409
|
+
Offset = new(1, 1),
|
|
410
|
+
IsTrigger = true
|
|
411
|
+
}) { Index = 1 },
|
|
412
|
+
new NeoAnimationSegmentFrame<NeoCollider?>(value: null) { Index = 2 }
|
|
413
|
+
]
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
The segment's class must fit the target member's class. Like any track target,
|
|
419
|
+
the member must be a writable Save, Session, or Writable leaf on the child, for
|
|
420
|
+
example `@storage(allowed: .Session) public override NeoCollider? Collider;`.
|
|
421
|
+
|
|
391
422
|
## NeoFlow dialogues
|
|
392
423
|
|
|
393
424
|
Lookup dialogue groups use the same collection paths as lookup members:
|
|
@@ -110,7 +110,7 @@ wrappers.
|
|
|
110
110
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
111
111
|
|
|
112
112
|
```html
|
|
113
|
-
<!-- reviewed-through-cli: 0.
|
|
113
|
+
<!-- reviewed-through-cli: 0.65.0 -->
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -48,7 +48,7 @@ keeps its meaning.
|
|
|
48
48
|
|
|
49
49
|
In a void context — a `void` function, a setter, or a void delegate — `=> expr`
|
|
50
50
|
is an expression statement rather than a return, so the expression must do
|
|
51
|
-
something: a call such as `void Ping() => this.
|
|
51
|
+
something: a call such as `void Ping() => this.OnUpdated();`, or an assignment
|
|
52
52
|
such as `set(int value) => this.Raw = value;`. An expression whose value would
|
|
53
53
|
simply be discarded is rejected with a diagnostic that names the block body as
|
|
54
54
|
the fix.
|
|
@@ -106,11 +106,11 @@ migration, and text-variable bodies against that same source transaction, so
|
|
|
106
106
|
new declarations do not depend on a prior push or a network fetch.
|
|
107
107
|
|
|
108
108
|
Inside an inline Class body, unqualified names resolve against that Class;
|
|
109
|
-
invoke delegate and action members directly with `Selector()` or `
|
|
109
|
+
invoke delegate and action members directly with `Selector()` or `OnUpdated()`.
|
|
110
110
|
Spell a zero-argument action as bare `NeoAction`; type arguments name action
|
|
111
111
|
parameters, so `NeoAction<void>` is invalid rather than a zero-argument alias.
|
|
112
112
|
Clear every subscribed listener from a stored action with
|
|
113
|
-
`this.
|
|
113
|
+
`this.OnUpdated.Clear()`. `Clear()` is a mutating statement and follows the
|
|
114
114
|
action member's effective storage and writability. Only the action's declaring
|
|
115
115
|
class and derived classes may invoke it or call `Clear()`; public external
|
|
116
116
|
callers may subscribe and unsubscribe with `+=` and `-=` but cannot raise or
|