@s2script/sdk 0.10.0 → 0.10.1
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/cli.js +234 -46
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4640,9 +4640,15 @@ var ATOMIC = {
|
|
|
4640
4640
|
uint32: { k: "u32", w: true },
|
|
4641
4641
|
uint64: { k: "u64", w: false },
|
|
4642
4642
|
int64: { k: "i64", w: false },
|
|
4643
|
-
float64: { k: "f64", w: false }
|
|
4643
|
+
float64: { k: "f64", w: false },
|
|
4644
4644
|
// no narrow 64-bit writers
|
|
4645
|
+
// `Color` is a 4-byte RGBA struct, not a scalar, but it is laid out exactly as a little-endian
|
|
4646
|
+
// uint32 (R in the low byte) and every engine consumer treats it that way. Mapping it here rather
|
|
4647
|
+
// than adding a value class keeps the surface small and matches how packed colours are already
|
|
4648
|
+
// passed elsewhere in the SDK (e.g. the fade user-message).
|
|
4649
|
+
Color: { k: "u32", w: true }
|
|
4645
4650
|
};
|
|
4651
|
+
var ENUM_WIDTH = { 1: "u8", 2: "u16", 4: "u32", 8: "u64" };
|
|
4646
4652
|
var VEC = { Vector: "vector", VectorWS: "vector", QAngle: "qangle" };
|
|
4647
4653
|
var VEC_INFO = {
|
|
4648
4654
|
vector: { cls: "Vector", count: 3 },
|
|
@@ -4655,7 +4661,13 @@ function idiomaticName(raw) {
|
|
|
4655
4661
|
const core = m && KNOWN_TAGS.has(m[1]) ? m[2] : s;
|
|
4656
4662
|
return core.charAt(0).toLowerCase() + core.slice(1);
|
|
4657
4663
|
}
|
|
4658
|
-
function
|
|
4664
|
+
function transparentValue(catalog, className) {
|
|
4665
|
+
const e = catalog[className];
|
|
4666
|
+
if (!e || e.parent || e.fields.length !== 1) return null;
|
|
4667
|
+
const f = e.fields[0];
|
|
4668
|
+
return f.name === "m_Value" && f.type.kind === "atomic" ? f : null;
|
|
4669
|
+
}
|
|
4670
|
+
function classifyField(type, embeddable = /* @__PURE__ */ new Set()) {
|
|
4659
4671
|
if (type.kind === "handle") return { accessorKind: "handle", writable: false };
|
|
4660
4672
|
if (type.kind === "atomic") {
|
|
4661
4673
|
const vk = VEC[type.name ?? ""];
|
|
@@ -4669,8 +4681,16 @@ function classifyField(type) {
|
|
|
4669
4681
|
if (cm) return { accessorKind: "str", writable: false, strLen: parseInt(cm[1], 10) };
|
|
4670
4682
|
return { skip: `unmapped 'unknown' type '${type.name ?? ""}'` };
|
|
4671
4683
|
}
|
|
4672
|
-
if (type.kind === "enum")
|
|
4673
|
-
|
|
4684
|
+
if (type.kind === "enum") {
|
|
4685
|
+
const w = ENUM_WIDTH[type.size ?? 0];
|
|
4686
|
+
if (w) return { accessorKind: w, writable: WRITE[w] !== void 0 };
|
|
4687
|
+
return { skip: `enum '${type.name ?? ""}' byte width not stated by the schema` };
|
|
4688
|
+
}
|
|
4689
|
+
if (type.kind === "class") {
|
|
4690
|
+
const n3 = type.name ?? "";
|
|
4691
|
+
if (embeddable.has(n3)) return { embedded: n3 };
|
|
4692
|
+
return { skip: `embedded class '${n3}' deferred` };
|
|
4693
|
+
}
|
|
4674
4694
|
if (type.kind === "ptr") return { skip: "raw pointer" };
|
|
4675
4695
|
return { skip: `unmapped kind '${type.kind}'` };
|
|
4676
4696
|
}
|
|
@@ -4685,7 +4705,11 @@ function flattenedFields(model, className) {
|
|
|
4685
4705
|
}
|
|
4686
4706
|
return chain.flatMap((c2) => c2.ownFields);
|
|
4687
4707
|
}
|
|
4688
|
-
function buildModel(catalog, requested) {
|
|
4708
|
+
function buildModel(catalog, requested, embeddable = []) {
|
|
4709
|
+
for (const n3 of embeddable) if (!catalog[n3]) throw new Error(`gen-schema: embedded class '${n3}' is not in the catalog`);
|
|
4710
|
+
const restrict = embeddable.length > 0 ? new Set(embeddable) : null;
|
|
4711
|
+
const canEmbed = (n3) => !!catalog[n3] && transparentValue(catalog, n3) === null && (restrict === null || restrict.has(n3));
|
|
4712
|
+
const embedSet = new Set(Object.keys(catalog).filter(canEmbed));
|
|
4689
4713
|
const inClosure = /* @__PURE__ */ new Set();
|
|
4690
4714
|
for (const start of requested) {
|
|
4691
4715
|
if (!catalog[start]) throw new Error(`gen-schema: requested class '${start}' is not in the catalog`);
|
|
@@ -4704,34 +4728,98 @@ function buildModel(catalog, requested) {
|
|
|
4704
4728
|
return d;
|
|
4705
4729
|
};
|
|
4706
4730
|
const ordered = [...inClosure].sort((a2, b) => depth(a2) - depth(b) || (a2 < b ? -1 : a2 > b ? 1 : 0));
|
|
4707
|
-
const
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4731
|
+
const usedEmbeds = /* @__PURE__ */ new Set();
|
|
4732
|
+
const classify = (f) => {
|
|
4733
|
+
if (f.type.kind === "class") {
|
|
4734
|
+
const inner = transparentValue(catalog, f.type.name ?? "");
|
|
4735
|
+
if (inner) {
|
|
4736
|
+
const c2 = classifyField(inner.type);
|
|
4737
|
+
if (!("skip" in c2) && !("embedded" in c2)) return { ...c2, addOffset: inner.offset };
|
|
4738
|
+
}
|
|
4739
|
+
}
|
|
4740
|
+
return classifyField(f.type, embedSet);
|
|
4741
|
+
};
|
|
4742
|
+
const fieldsOf = (owner, out, emb, skipped) => {
|
|
4743
|
+
for (const f of catalog[owner].fields) {
|
|
4744
|
+
const c2 = classify(f);
|
|
4713
4745
|
if ("skip" in c2) {
|
|
4714
|
-
skipped.push({ className, rawName: f.name, reason: c2.skip });
|
|
4746
|
+
skipped.push({ className: owner, rawName: f.name, reason: c2.skip });
|
|
4715
4747
|
continue;
|
|
4716
4748
|
}
|
|
4717
|
-
|
|
4749
|
+
if ("embedded" in c2) {
|
|
4750
|
+
usedEmbeds.add(c2.embedded);
|
|
4751
|
+
emb.push({ propName: idiomaticName(f.name), rawName: f.name, declaringClass: owner, embeddedClass: c2.embedded });
|
|
4752
|
+
continue;
|
|
4753
|
+
}
|
|
4754
|
+
out.push({ propName: idiomaticName(f.name), rawName: f.name, declaringClass: owner, accessorKind: c2.accessorKind, writable: c2.writable, strLen: c2.strLen, addOffset: c2.addOffset });
|
|
4718
4755
|
}
|
|
4719
|
-
|
|
4756
|
+
};
|
|
4757
|
+
const classes = ordered.map((className) => {
|
|
4758
|
+
const parent = catalog[className].parent;
|
|
4759
|
+
const ownFields = [];
|
|
4760
|
+
const embeddedFields = [];
|
|
4761
|
+
const skipped = [];
|
|
4762
|
+
fieldsOf(className, ownFields, embeddedFields, skipped);
|
|
4763
|
+
return { className, parent: parent && inClosure.has(parent) ? parent : null, ownFields, embeddedFields, skipped };
|
|
4720
4764
|
});
|
|
4765
|
+
const embedded = [];
|
|
4766
|
+
const done = /* @__PURE__ */ new Set();
|
|
4767
|
+
for (; ; ) {
|
|
4768
|
+
const next = [...usedEmbeds].filter((n3) => !done.has(n3)).sort();
|
|
4769
|
+
if (next.length === 0) break;
|
|
4770
|
+
for (const className of next) {
|
|
4771
|
+
done.add(className);
|
|
4772
|
+
const fields = [];
|
|
4773
|
+
const embeddedFields = [];
|
|
4774
|
+
const skipped = [];
|
|
4775
|
+
const chain = [];
|
|
4776
|
+
for (let cur = className; cur && catalog[cur]; cur = catalog[cur].parent) chain.unshift(cur);
|
|
4777
|
+
for (const owner of chain) fieldsOf(owner, fields, embeddedFields, skipped);
|
|
4778
|
+
embedded.push({ className, fields, embeddedFields, skipped });
|
|
4779
|
+
}
|
|
4780
|
+
}
|
|
4781
|
+
embedded.sort((a2, b) => a2.className < b.className ? -1 : a2.className > b.className ? 1 : 0);
|
|
4782
|
+
const ancestors = (cls) => {
|
|
4783
|
+
const out = /* @__PURE__ */ new Set();
|
|
4784
|
+
for (let cur = catalog[cls]?.parent ?? null; cur && catalog[cur]; cur = catalog[cur].parent) out.add(cur);
|
|
4785
|
+
return out;
|
|
4786
|
+
};
|
|
4721
4787
|
const byProp = /* @__PURE__ */ new Map();
|
|
4722
|
-
for (const c2 of classes) for (const f of c2.ownFields) {
|
|
4788
|
+
for (const c2 of classes) for (const f of [...c2.ownFields, ...c2.embeddedFields]) {
|
|
4723
4789
|
(byProp.get(f.propName) ?? byProp.set(f.propName, []).get(f.propName)).push(f);
|
|
4724
4790
|
}
|
|
4725
4791
|
const collisions = [];
|
|
4726
4792
|
for (const [prop, fields] of byProp) {
|
|
4727
|
-
const
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4793
|
+
const decls = /* @__PURE__ */ new Map();
|
|
4794
|
+
for (const f of fields) (decls.get(`${f.declaringClass}.${f.rawName}`) ?? decls.set(`${f.declaringClass}.${f.rawName}`, []).get(`${f.declaringClass}.${f.rawName}`)).push(f);
|
|
4795
|
+
if (decls.size < 2) continue;
|
|
4796
|
+
const keys = [...decls.keys()].sort();
|
|
4797
|
+
const clsOf = (k) => decls.get(k)[0].declaringClass;
|
|
4798
|
+
const conflicting = /* @__PURE__ */ new Set();
|
|
4799
|
+
for (let i2 = 0; i2 < keys.length; i2++) {
|
|
4800
|
+
for (let j = i2 + 1; j < keys.length; j++) {
|
|
4801
|
+
const a2 = clsOf(keys[i2]), b = clsOf(keys[j]);
|
|
4802
|
+
if (a2 === b || ancestors(a2).has(b) || ancestors(b).has(a2)) {
|
|
4803
|
+
conflicting.add(keys[i2]);
|
|
4804
|
+
conflicting.add(keys[j]);
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
if (conflicting.size === 0) continue;
|
|
4809
|
+
const depthOf = (k) => ancestors(clsOf(k)).size;
|
|
4810
|
+
const inConflict = [...conflicting].sort((x, y) => depthOf(x) - depthOf(y) || (x < y ? -1 : 1));
|
|
4811
|
+
const winnerCls = clsOf(inConflict[0]);
|
|
4812
|
+
const soleWinner = inConflict.filter((k) => clsOf(k) === winnerCls).length === 1;
|
|
4813
|
+
const renamed = [];
|
|
4814
|
+
for (const k of inConflict) {
|
|
4815
|
+
if (soleWinner && k === inConflict[0]) continue;
|
|
4816
|
+
for (const f of decls.get(k)) f.propName = f.rawName;
|
|
4817
|
+
renamed.push(k);
|
|
4731
4818
|
}
|
|
4819
|
+
collisions.push(`${prop} <- ${renamed.sort().join(", ")}${soleWinner ? ` (kept by ${winnerCls})` : ""}`);
|
|
4732
4820
|
}
|
|
4733
4821
|
collisions.sort();
|
|
4734
|
-
return { classes, collisions };
|
|
4822
|
+
return { classes, embedded, collisions };
|
|
4735
4823
|
}
|
|
4736
4824
|
|
|
4737
4825
|
// src/schemagen/emit-dts.ts
|
|
@@ -4744,8 +4832,20 @@ function emitDts(model) {
|
|
|
4744
4832
|
const vi = VEC_INFO[f.accessorKind];
|
|
4745
4833
|
if (vi) vecClasses.add(vi.cls);
|
|
4746
4834
|
}
|
|
4835
|
+
for (const e of model.embedded) for (const f of e.fields) {
|
|
4836
|
+
const vi = VEC_INFO[f.accessorKind];
|
|
4837
|
+
if (vi) vecClasses.add(vi.cls);
|
|
4838
|
+
}
|
|
4747
4839
|
if (vecClasses.size) out.push(`import type { ${[...vecClasses].sort().join(", ")} } from "@s2script/sdk/math";`);
|
|
4748
4840
|
out.push("");
|
|
4841
|
+
for (const e of model.embedded) {
|
|
4842
|
+
out.push(`export interface ${e.className} {`);
|
|
4843
|
+
for (const f of e.fields) {
|
|
4844
|
+
out.push(` ${f.writable ? "" : "readonly "}${f.propName}: ${TSTYPE[f.accessorKind]};`);
|
|
4845
|
+
}
|
|
4846
|
+
for (const f of e.embeddedFields) out.push(` readonly ${f.propName}: ${f.embeddedClass};`);
|
|
4847
|
+
out.push("}", "");
|
|
4848
|
+
}
|
|
4749
4849
|
for (const c2 of model.classes) {
|
|
4750
4850
|
const ext = c2.parent && names.has(c2.parent) ? ` extends ${c2.parent}` : "";
|
|
4751
4851
|
out.push(`export interface ${c2.className}${ext} {`);
|
|
@@ -4753,18 +4853,66 @@ function emitDts(model) {
|
|
|
4753
4853
|
const ro = f.writable ? "" : "readonly ";
|
|
4754
4854
|
out.push(` ${ro}${f.propName}: ${TSTYPE[f.accessorKind]};`);
|
|
4755
4855
|
}
|
|
4856
|
+
for (const f of c2.embeddedFields) out.push(` readonly ${f.propName}: ${f.embeddedClass};`);
|
|
4756
4857
|
out.push("}", "");
|
|
4757
4858
|
}
|
|
4859
|
+
out.push("/** Every wrappable entity class, by schema name. */", "export interface SchemaClasses {");
|
|
4860
|
+
for (const c2 of model.classes) out.push(` ${c2.className}: ${c2.className};`);
|
|
4861
|
+
out.push("}", "");
|
|
4862
|
+
out.push(
|
|
4863
|
+
"/**",
|
|
4864
|
+
" * Apply this schema class's field accessors to an entity reference.",
|
|
4865
|
+
" *",
|
|
4866
|
+
" * `createEntity` returns a bare `EntityRef` with no schema fields on it \u2014 this is how you get",
|
|
4867
|
+
" * them. `Player.pawn` is already wrapped; this is for entities you create or resolve yourself.",
|
|
4868
|
+
" *",
|
|
4869
|
+
" * The wrapper is a view, not a copy: it holds the ref and reads through it on every access, so",
|
|
4870
|
+
" * it stays correct as the entity changes and costs nothing to keep. Field reads return null",
|
|
4871
|
+
" * once the ref goes stale, exactly as they do on a pawn.",
|
|
4872
|
+
" *",
|
|
4873
|
+
" * @example",
|
|
4874
|
+
' * const prop = createEntity("prop_dynamic");',
|
|
4875
|
+
" * prop.spawn();",
|
|
4876
|
+
' * const fields = wrapEntity("CBaseModelEntity", prop);',
|
|
4877
|
+
" * fields.glow.glowing = true;",
|
|
4878
|
+
" */",
|
|
4879
|
+
"export declare function wrapEntity<K extends keyof SchemaClasses>(className: K, ref: EntityRef): SchemaClasses[K];",
|
|
4880
|
+
""
|
|
4881
|
+
);
|
|
4758
4882
|
return out.join("\n");
|
|
4759
4883
|
}
|
|
4760
4884
|
|
|
4761
4885
|
// src/schemagen/emit-js.ts
|
|
4762
4886
|
var HEADER2 = "// GENERATED by `s2script gen-schema` from schema-catalog.json \u2014 DO NOT EDIT.";
|
|
4763
4887
|
var S = JSON.stringify;
|
|
4888
|
+
function resolveExpr(f) {
|
|
4889
|
+
const base = `off(${S(f.declaringClass)},${S(f.rawName)})`;
|
|
4890
|
+
return f.addOffset ? `${base} + ${f.addOffset}` : base;
|
|
4891
|
+
}
|
|
4892
|
+
function accessorEntry(f, resolve13, guard2) {
|
|
4893
|
+
const g = guard2 === "" ? "" : `${guard2} `;
|
|
4894
|
+
const gs = guard2 === "" ? "" : `${guard2.replace("return null;", "return;")} `;
|
|
4895
|
+
let entry;
|
|
4896
|
+
if (f.accessorKind === "str") {
|
|
4897
|
+
entry = `get: function () { ${g}return this.ref.readString(${resolve13}, ${f.strLen}); }`;
|
|
4898
|
+
} else if (f.accessorKind === "u64" || f.accessorKind === "i64") {
|
|
4899
|
+
entry = `get: function () { ${g}var v = this.ref.${READ[f.accessorKind]}(${resolve13}); return v === null ? null : v.toString(); }`;
|
|
4900
|
+
} else if (VEC_INFO[f.accessorKind]) {
|
|
4901
|
+
const vi = VEC_INFO[f.accessorKind];
|
|
4902
|
+
entry = `get: function () { ${g}var a = this.ref.readFloats(${resolve13}, ${vi.count}); return a === null ? null : new ${vi.cls}(a[0], a[1], a[2]); }`;
|
|
4903
|
+
} else {
|
|
4904
|
+
entry = `get: function () { ${g}return this.ref.${READ[f.accessorKind]}(${resolve13}); }`;
|
|
4905
|
+
}
|
|
4906
|
+
if (f.writable) {
|
|
4907
|
+
const wm = WRITE[f.accessorKind];
|
|
4908
|
+
entry += `, set: function (v) { ${gs}var o = ${resolve13}; if (this.ref.${wm}(o, v)) this.ref.notifyStateChanged(o); }`;
|
|
4909
|
+
}
|
|
4910
|
+
return entry;
|
|
4911
|
+
}
|
|
4764
4912
|
function emitJs(model) {
|
|
4765
|
-
const out = [HEADER2, "(function () {", " var off = __s2_schema_offset;", " var A = {};"];
|
|
4913
|
+
const out = [HEADER2, "(function () {", " var off = __s2_schema_offset;", " var A = {};", " var E = {};"];
|
|
4766
4914
|
const vecClasses = /* @__PURE__ */ new Set();
|
|
4767
|
-
for (const c2 of model.classes) for (const f of
|
|
4915
|
+
for (const c2 of model.classes) for (const f of c2.ownFields) {
|
|
4768
4916
|
const vi = VEC_INFO[f.accessorKind];
|
|
4769
4917
|
if (vi) vecClasses.add(vi.cls);
|
|
4770
4918
|
}
|
|
@@ -4773,36 +4921,58 @@ function emitJs(model) {
|
|
|
4773
4921
|
}
|
|
4774
4922
|
for (const c2 of model.classes) {
|
|
4775
4923
|
out.push(` A[${S(c2.className)}] = {`);
|
|
4776
|
-
for (const f of
|
|
4777
|
-
const
|
|
4778
|
-
let entry;
|
|
4779
|
-
if (f.accessorKind === "str") {
|
|
4780
|
-
entry = `get: function () { return this.ref.readString(${resolve13}, ${f.strLen}); }`;
|
|
4781
|
-
} else if (f.accessorKind === "u64" || f.accessorKind === "i64") {
|
|
4782
|
-
entry = `get: function () { var v = this.ref.${READ[f.accessorKind]}(${resolve13}); return v === null ? null : v.toString(); }`;
|
|
4783
|
-
} else if (VEC_INFO[f.accessorKind]) {
|
|
4784
|
-
const vi = VEC_INFO[f.accessorKind];
|
|
4785
|
-
entry = `get: function () { var a = this.ref.readFloats(${resolve13}, ${vi.count}); return a === null ? null : new ${vi.cls}(a[0], a[1], a[2]); }`;
|
|
4786
|
-
} else {
|
|
4787
|
-
entry = `get: function () { return this.ref.${READ[f.accessorKind]}(${resolve13}); }`;
|
|
4788
|
-
}
|
|
4789
|
-
if (f.writable) {
|
|
4790
|
-
const wm = WRITE[f.accessorKind];
|
|
4791
|
-
entry += `, set: function (v) { var o = ${resolve13}; if (this.ref.${wm}(o, v)) this.ref.notifyStateChanged(o); }`;
|
|
4792
|
-
}
|
|
4924
|
+
for (const f of c2.ownFields) {
|
|
4925
|
+
const entry = accessorEntry(f, resolveExpr(f), "");
|
|
4793
4926
|
out.push(` ${S(f.propName)}: { ${entry} },`);
|
|
4794
4927
|
}
|
|
4928
|
+
for (const f of c2.embeddedFields) {
|
|
4929
|
+
out.push(` ${S(f.propName)}: { get: function () { return embed(${S(f.embeddedClass)}, this.ref, off(${S(f.declaringClass)},${S(f.rawName)})); } },`);
|
|
4930
|
+
}
|
|
4795
4931
|
out.push(" };");
|
|
4796
4932
|
}
|
|
4933
|
+
for (const e of model.embedded) {
|
|
4934
|
+
out.push(` E[${S(e.className)}] = {`);
|
|
4935
|
+
for (const f of e.fields) {
|
|
4936
|
+
const sub = `off(${S(f.declaringClass)},${S(f.rawName)})`;
|
|
4937
|
+
const resolve13 = f.addOffset ? `this.base + ${sub} + ${f.addOffset}` : `this.base + ${sub}`;
|
|
4938
|
+
const guard2 = `if (this.base < 0 || ${sub} < 0) return null;`;
|
|
4939
|
+
out.push(` ${S(f.propName)}: { ${accessorEntry(f, resolve13, guard2)} },`);
|
|
4940
|
+
}
|
|
4941
|
+
for (const f of e.embeddedFields) {
|
|
4942
|
+
const sub = `off(${S(f.declaringClass)},${S(f.rawName)})`;
|
|
4943
|
+
out.push(` ${S(f.propName)}: { get: function () { var s = ${sub}; return embed(${S(f.embeddedClass)}, this.ref, (this.base < 0 || s < 0) ? -1 : this.base + s); } },`);
|
|
4944
|
+
}
|
|
4945
|
+
out.push(" };");
|
|
4946
|
+
}
|
|
4947
|
+
out.push(" var P = {");
|
|
4948
|
+
for (const c2 of model.classes) if (c2.parent) out.push(` ${S(c2.className)}: ${S(c2.parent)},`);
|
|
4949
|
+
out.push(" };");
|
|
4797
4950
|
out.push(
|
|
4951
|
+
" // Walk the ancestor chain rather than storing every inherited accessor per class. Flattening",
|
|
4952
|
+
" // into each table duplicated the whole chain 3.77x on the CS2 class set and grew as",
|
|
4953
|
+
" // O(classes * depth), so every class added inflated every other one; this is O(total fields).",
|
|
4954
|
+
" // Ancestors are applied FIRST so a derived class's own definition wins if a name repeats.",
|
|
4798
4955
|
" function applyAccessors(proto, className) {",
|
|
4799
|
-
" var
|
|
4800
|
-
" for (
|
|
4801
|
-
"
|
|
4956
|
+
" var chain = [], c = className;",
|
|
4957
|
+
" for (; c; c = P[c]) chain.unshift(c);",
|
|
4958
|
+
" for (var i = 0; i < chain.length; i++) {",
|
|
4959
|
+
" var defs = A[chain[i]]; if (!defs) continue;",
|
|
4960
|
+
" for (var name in defs) {",
|
|
4961
|
+
" Object.defineProperty(proto, name, { get: defs[name].get, set: defs[name].set, enumerable: true, configurable: true });",
|
|
4962
|
+
" }",
|
|
4802
4963
|
" }",
|
|
4803
4964
|
" }",
|
|
4804
4965
|
" function wrap(className, ref) { var o = { ref: ref }; applyAccessors(o, className); return o; }",
|
|
4966
|
+
" function embed(className, ref, base) {",
|
|
4967
|
+
" var o = { ref: ref, base: base }, defs = E[className];",
|
|
4968
|
+
" if (defs) for (var name in defs) {",
|
|
4969
|
+
" Object.defineProperty(o, name, { get: defs[name].get, set: defs[name].set, enumerable: true, configurable: true });",
|
|
4970
|
+
" }",
|
|
4971
|
+
" return o;",
|
|
4972
|
+
" }",
|
|
4805
4973
|
" globalThis.__s2pkg_cs2_schema = { applyAccessors: applyAccessors, wrap: wrap };",
|
|
4974
|
+
" // Merge (not overwrite): this prelude runs FIRST, and pawn.js merges onto whatever it finds.",
|
|
4975
|
+
" globalThis.__s2pkg_cs2 = Object.assign({}, globalThis.__s2pkg_cs2, { wrapEntity: wrap });",
|
|
4806
4976
|
"})();"
|
|
4807
4977
|
);
|
|
4808
4978
|
return out.join("\n");
|
|
@@ -4811,12 +4981,18 @@ function emitJs(model) {
|
|
|
4811
4981
|
// src/schemagen/gen.ts
|
|
4812
4982
|
var CATALOG_PATH = "games/cs2/gamedata/schema-catalog.json";
|
|
4813
4983
|
var LIST_PATH = "games/cs2/codegen-classes.json";
|
|
4984
|
+
var EMBED_PATH = "games/cs2/codegen-embedded.json";
|
|
4814
4985
|
var JS_OUT = "games/cs2/js/schema.generated.js";
|
|
4815
4986
|
var DTS_OUT = "packages/cs2/schema.generated.d.ts";
|
|
4816
4987
|
function runGenSchema(repoRoot2, opts) {
|
|
4817
4988
|
const catalog = JSON.parse(readFileSync13(join13(repoRoot2, CATALOG_PATH), "utf8"));
|
|
4818
4989
|
const list = JSON.parse(readFileSync13(join13(repoRoot2, LIST_PATH), "utf8"));
|
|
4819
|
-
|
|
4990
|
+
let embed = [];
|
|
4991
|
+
try {
|
|
4992
|
+
embed = JSON.parse(readFileSync13(join13(repoRoot2, EMBED_PATH), "utf8"));
|
|
4993
|
+
} catch {
|
|
4994
|
+
}
|
|
4995
|
+
const model = buildModel(catalog, list, embed);
|
|
4820
4996
|
const dts = emitDts(model);
|
|
4821
4997
|
const js = emitJs(model);
|
|
4822
4998
|
const fields = model.classes.reduce((n3, c2) => n3 + c2.ownFields.length, 0);
|
|
@@ -5004,6 +5180,7 @@ function buildNavModel(config, catalog) {
|
|
|
5004
5180
|
source: entry.source,
|
|
5005
5181
|
target: entry.target,
|
|
5006
5182
|
path: entry.path,
|
|
5183
|
+
base: entry.base ?? [],
|
|
5007
5184
|
fields,
|
|
5008
5185
|
skippedKinds
|
|
5009
5186
|
};
|
|
@@ -5042,10 +5219,12 @@ function emitNavJs(model) {
|
|
|
5042
5219
|
out.push(` var ${cls} = __s2require("@s2script/sdk/math").${cls};`);
|
|
5043
5220
|
}
|
|
5044
5221
|
for (const w of model.wrappers) {
|
|
5045
|
-
out.push(` function ${w.wrapper}(root, path) { this.root = root; this.path = path; }`);
|
|
5222
|
+
out.push(` function ${w.wrapper}(root, path, base) { this.root = root; this.path = path; this.base = base; }`);
|
|
5046
5223
|
out.push(` Object.defineProperties(${w.wrapper}.prototype, {`);
|
|
5047
5224
|
for (const f of w.fields) {
|
|
5048
|
-
const
|
|
5225
|
+
const own = `off(${S2(f.declaringClass)},${S2(f.rawName)})`;
|
|
5226
|
+
const withDelta = f.addOffset ? `${own} + ${f.addOffset}` : own;
|
|
5227
|
+
const resolve13 = `${withDelta} + this.base`;
|
|
5049
5228
|
let getter;
|
|
5050
5229
|
const kind = f.accessorKind;
|
|
5051
5230
|
if (kind === "u64") {
|
|
@@ -5084,7 +5263,16 @@ function emitNavJs(model) {
|
|
|
5084
5263
|
const h2 = w.path[i2];
|
|
5085
5264
|
out.push(` var o${i2} = off(${S2(h2.cls)},${S2(h2.field)}); if (o${i2} < 0) return null; _p.push(o${i2});`);
|
|
5086
5265
|
}
|
|
5087
|
-
|
|
5266
|
+
if (w.base.length > 0) {
|
|
5267
|
+
out.push(` var _b = 0;`);
|
|
5268
|
+
for (let i2 = 0; i2 < w.base.length; i2++) {
|
|
5269
|
+
const h2 = w.base[i2];
|
|
5270
|
+
out.push(` var b${i2} = off(${S2(h2.cls)},${S2(h2.field)}); if (b${i2} < 0) return null; _b += b${i2};`);
|
|
5271
|
+
}
|
|
5272
|
+
out.push(` return new ${w.wrapper}(this.ref, _p, _b);`);
|
|
5273
|
+
} else {
|
|
5274
|
+
out.push(` return new ${w.wrapper}(this.ref, _p, 0);`);
|
|
5275
|
+
}
|
|
5088
5276
|
out.push(` }, enumerable: true, configurable: true,`);
|
|
5089
5277
|
out.push(` });`);
|
|
5090
5278
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@s2script/sdk",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"license": "MIT OR Apache-2.0",
|
|
5
5
|
"description": "s2script SDK — the builtin capability types (imported as @s2script/sdk/entity, …) plus the `s2s` CLI for building Source 2 / CS2 plugins.",
|
|
6
6
|
"type": "module",
|