@gmvjs/xray-v1 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +77 -2
- package/dist/db.d.ts +12 -0
- package/dist/db.js +134 -0
- package/dist/db.js.map +1 -0
- package/dist/details.d.ts +42 -0
- package/dist/details.js +210 -0
- package/dist/details.js.map +1 -0
- package/dist/export.d.ts +38 -0
- package/dist/export.js +241 -0
- package/dist/export.js.map +1 -0
- package/dist/games/cop.d.ts +7 -0
- package/dist/games/cop.js +11 -0
- package/dist/games/cop.js.map +1 -0
- package/dist/games/cs.d.ts +7 -0
- package/dist/games/cs.js +11 -0
- package/dist/games/cs.js.map +1 -0
- package/dist/games/sdk.d.ts +7 -0
- package/dist/games/sdk.js +10 -0
- package/dist/games/sdk.js.map +1 -0
- package/dist/games/soc.d.ts +9 -0
- package/dist/games/soc.js +13 -0
- package/dist/games/soc.js.map +1 -0
- package/dist/i18n.d.ts +2 -0
- package/dist/i18n.js +48 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +131 -0
- package/dist/index.js.map +1 -0
- package/dist/level.d.ts +39 -0
- package/dist/level.js +234 -0
- package/dist/level.js.map +1 -0
- package/dist/load.d.ts +5 -0
- package/dist/load.js +126 -0
- package/dist/load.js.map +1 -0
- package/dist/lzhuf.d.ts +2 -0
- package/dist/lzhuf.js +136 -0
- package/dist/lzhuf.js.map +1 -0
- package/dist/motion.d.ts +28 -0
- package/dist/motion.js +20 -0
- package/dist/motion.js.map +1 -0
- package/dist/object.d.ts +138 -0
- package/dist/object.js +361 -0
- package/dist/object.js.map +1 -0
- package/dist/ogf.d.ts +93 -0
- package/dist/ogf.js +418 -0
- package/dist/ogf.js.map +1 -0
- package/dist/scene.d.ts +28 -0
- package/dist/scene.js +141 -0
- package/dist/scene.js.map +1 -0
- package/dist/skeleton.d.ts +34 -0
- package/dist/skeleton.js +252 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/smotion.d.ts +44 -0
- package/dist/smotion.js +283 -0
- package/dist/smotion.js.map +1 -0
- package/dist/soc-key.d.ts +18 -0
- package/dist/soc-key.js +125 -0
- package/dist/soc-key.js.map +1 -0
- package/dist/thm.d.ts +26 -0
- package/dist/thm.js +69 -0
- package/dist/thm.js.map +1 -0
- package/dist/write-object.d.ts +31 -0
- package/dist/write-object.js +228 -0
- package/dist/write-object.js.map +1 -0
- package/dist/write-omf.d.ts +47 -0
- package/dist/write-scene.d.ts +26 -0
- package/dist/write-scene.js +114 -0
- package/dist/write-scene.js.map +1 -0
- package/package.json +70 -4
package/dist/export.js
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { hasAlpha, encodeDdsRgba } from "@gmvjs/core/writers/dds";
|
|
2
|
+
import { visibleIndices } from "@gmvjs/core/scene";
|
|
3
|
+
import { writeThm } from "./thm.js";
|
|
4
|
+
import { writeObject } from "./write-object.js";
|
|
5
|
+
import { writeScene } from "./write-scene.js";
|
|
6
|
+
const clean = (s) => s.toLowerCase().replace(/\.[a-z0-9]+$/, "").replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "tex";
|
|
7
|
+
function toXray(model, mi, scale) {
|
|
8
|
+
const m = model.meshes[mi], n = m.vertexCount, sk = model.skeleton, pos = new Float32Array(n * 3), nor = new Float32Array(n * 3);
|
|
9
|
+
if (sk) sk.pose(null, 0, false);
|
|
10
|
+
for (let v = 0; v < n; v++) {
|
|
11
|
+
let x = m.pos[v * 3], y = m.pos[v * 3 + 1], z = m.pos[v * 3 + 2], a = m.nor[v * 3], b = m.nor[v * 3 + 1], c = m.nor[v * 3 + 2];
|
|
12
|
+
if (sk && m.skinned) {
|
|
13
|
+
let px = 0, py = 0, pz = 0, na = 0, nb = 0, nc = 0, ws = 0;
|
|
14
|
+
for (let k = 0; k < 4; k++) {
|
|
15
|
+
const w = m.weight[v * 4 + k];
|
|
16
|
+
if (!w) continue;
|
|
17
|
+
const M = sk.skinV[m.bone[v * 4 + k]];
|
|
18
|
+
ws += w;
|
|
19
|
+
px += w * (x * M[0] + y * M[4] + z * M[8] + M[12]);
|
|
20
|
+
py += w * (x * M[1] + y * M[5] + z * M[9] + M[13]);
|
|
21
|
+
pz += w * (x * M[2] + y * M[6] + z * M[10] + M[14]);
|
|
22
|
+
na += w * (a * M[0] + b * M[4] + c * M[8]);
|
|
23
|
+
nb += w * (a * M[1] + b * M[5] + c * M[9]);
|
|
24
|
+
nc += w * (a * M[2] + b * M[6] + c * M[10]);
|
|
25
|
+
}
|
|
26
|
+
if (ws) {
|
|
27
|
+
x = px;
|
|
28
|
+
y = py;
|
|
29
|
+
z = pz;
|
|
30
|
+
a = na;
|
|
31
|
+
b = nb;
|
|
32
|
+
c = nc;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (model.defaultZUp) {
|
|
36
|
+
[y, z] = [z, -y];
|
|
37
|
+
[b, c] = [c, -b];
|
|
38
|
+
}
|
|
39
|
+
if (!model.flipZ) {
|
|
40
|
+
z = -z;
|
|
41
|
+
c = -c;
|
|
42
|
+
}
|
|
43
|
+
const l = Math.hypot(a, b, c) || 1;
|
|
44
|
+
pos[v * 3] = x * scale;
|
|
45
|
+
pos[v * 3 + 1] = y * scale;
|
|
46
|
+
pos[v * 3 + 2] = z * scale;
|
|
47
|
+
nor[v * 3] = a / l;
|
|
48
|
+
nor[v * 3 + 1] = b / l;
|
|
49
|
+
nor[v * 3 + 2] = c / l;
|
|
50
|
+
}
|
|
51
|
+
const indices = visibleIndices(model, mi);
|
|
52
|
+
if (!model.flipZ) for (let t = 0; t + 2 < indices.length; t += 3) {
|
|
53
|
+
const q = indices[t + 1];
|
|
54
|
+
indices[t + 1] = indices[t + 2];
|
|
55
|
+
indices[t + 2] = q;
|
|
56
|
+
}
|
|
57
|
+
return { pos, nor, indices };
|
|
58
|
+
}
|
|
59
|
+
async function exportXraySdk(model, o) {
|
|
60
|
+
const name = clean(o.name), prefix = (o.prefix ?? `gmv\\${name}`).replace(/\//g, "\\").replace(/\\+$/, ""), scale = o.scale ?? 1;
|
|
61
|
+
const files = /* @__PURE__ */ new Map(), report = [];
|
|
62
|
+
const inst = o.instances !== false && model.instances && model.flipZ && !model.defaultZUp ? model.instances : null;
|
|
63
|
+
const instMeshes = new Set(inst?.meshes ?? []);
|
|
64
|
+
const meshIdx = model.meshes.map((_, i) => i).filter((i) => !o.hidden?.has(i) && model.meshes[i].indices.length >= 3);
|
|
65
|
+
const geo = new Map(meshIdx.filter((i) => !instMeshes.has(i)).map((i) => [i, toXray(model, i, scale)]));
|
|
66
|
+
const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
|
|
67
|
+
for (const g of geo.values()) for (let i = 0; i < g.pos.length; i++) {
|
|
68
|
+
lo[i % 3] = Math.min(lo[i % 3], g.pos[i]);
|
|
69
|
+
hi[i % 3] = Math.max(hi[i % 3], g.pos[i]);
|
|
70
|
+
}
|
|
71
|
+
const extent = Math.max(hi[0] - lo[0], hi[2] - lo[2]);
|
|
72
|
+
const triCount = [...geo.values()].reduce((a, g) => a + g.indices.length / 3, 0);
|
|
73
|
+
const cell = o.cell ?? (extent > 400 ? 64 : extent > 100 || triCount > 6e4 ? 32 : 0);
|
|
74
|
+
const surfaces = [], surfOfMesh = /* @__PURE__ */ new Map(), texOut = /* @__PURE__ */ new Map();
|
|
75
|
+
let copied = 0, encoded = 0, missingTex = 0;
|
|
76
|
+
for (const i of meshIdx) {
|
|
77
|
+
const m = model.meshes[i], key = m.texture || `mesh_${i}`;
|
|
78
|
+
if (o.xraySource) {
|
|
79
|
+
const sk = `${m.texture}|${m.shader ?? ""}|${m.material ?? ""}`;
|
|
80
|
+
let si = surfaces.findIndex((x) => `${x.texture}|${x.eshader}|${x.gamemtl}` === sk);
|
|
81
|
+
if (si < 0) si = surfaces.push({ name: `${clean(m.texture.split("\\").pop() ?? "s")}_${surfaces.length}`, texture: m.texture, eshader: m.shader || "default", gamemtl: m.material || "default" }) - 1;
|
|
82
|
+
surfOfMesh.set(i, si);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
let xname = texOut.get(key);
|
|
86
|
+
if (!xname) {
|
|
87
|
+
const base = clean(key.split(/[\\/]/).pop() ?? key);
|
|
88
|
+
let cand = base, k = 1;
|
|
89
|
+
while ([...texOut.values()].includes(`${prefix}\\${cand}`)) cand = `${base}_${k++}`;
|
|
90
|
+
xname = `${prefix}\\${cand}`;
|
|
91
|
+
texOut.set(key, xname);
|
|
92
|
+
const t = o.texture ? await o.texture(i).catch(() => null) : null;
|
|
93
|
+
const path = `gamedata/textures/${xname.replace(/\\/g, "/")}`;
|
|
94
|
+
if (t?.dds && t.dds.length > 128) {
|
|
95
|
+
files.set(`${path}.dds`, t.dds);
|
|
96
|
+
const dv = new DataView(t.dds.buffer, t.dds.byteOffset), fourcc = String.fromCharCode(t.dds[84], t.dds[85], t.dds[86], t.dds[87]);
|
|
97
|
+
files.set(`${path}.thm`, writeThm({ width: dv.getUint32(16, true), height: dv.getUint32(12, true), alpha: fourcc !== "DXT1" }));
|
|
98
|
+
copied++;
|
|
99
|
+
} else if (t?.image?.rgba) {
|
|
100
|
+
const a = hasAlpha(t.image);
|
|
101
|
+
files.set(`${path}.dds`, encodeDdsRgba({ width: t.image.width, height: t.image.height, rgba: t.image.rgba }));
|
|
102
|
+
files.set(`${path}.thm`, writeThm({ width: t.image.width, height: t.image.height, alpha: a }));
|
|
103
|
+
encoded++;
|
|
104
|
+
} else missingTex++;
|
|
105
|
+
surfaces.push({ name: cand, texture: xname });
|
|
106
|
+
}
|
|
107
|
+
surfOfMesh.set(i, surfaces.findIndex((s) => s.texture === xname));
|
|
108
|
+
}
|
|
109
|
+
const cells = /* @__PURE__ */ new Map();
|
|
110
|
+
for (const [i, g] of geo) {
|
|
111
|
+
for (let t = 0; t + 2 < g.indices.length; t += 3) {
|
|
112
|
+
let key = "all";
|
|
113
|
+
if (cell > 0) {
|
|
114
|
+
const a = g.indices[t] * 3, b = g.indices[t + 1] * 3, c = g.indices[t + 2] * 3;
|
|
115
|
+
const cx = (g.pos[a] + g.pos[b] + g.pos[c]) / 3, cz = (g.pos[a + 2] + g.pos[b + 2] + g.pos[c + 2]) / 3;
|
|
116
|
+
key = `${Math.floor((cx - lo[0]) / cell)}_${Math.floor((cz - lo[2]) / cell)}`;
|
|
117
|
+
}
|
|
118
|
+
const byMesh = cells.get(key) ?? cells.set(key, /* @__PURE__ */ new Map()).get(key);
|
|
119
|
+
(byMesh.get(i) ?? byMesh.set(i, []).get(i)).push(t);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const objects = [];
|
|
123
|
+
let tris = 0;
|
|
124
|
+
for (const [key, byMesh] of cells) {
|
|
125
|
+
const meshes = [];
|
|
126
|
+
for (const [i, list] of byMesh) {
|
|
127
|
+
const g = geo.get(i), src = model.meshes[i], remap = /* @__PURE__ */ new Map(), pos = [], nor = [], uv = [], idx = [];
|
|
128
|
+
for (const t of list) for (let k = 0; k < 3; k++) {
|
|
129
|
+
const v = g.indices[t + k];
|
|
130
|
+
let r = remap.get(v);
|
|
131
|
+
if (r === void 0) {
|
|
132
|
+
r = pos.length / 3;
|
|
133
|
+
remap.set(v, r);
|
|
134
|
+
pos.push(g.pos[v * 3], g.pos[v * 3 + 1], g.pos[v * 3 + 2]);
|
|
135
|
+
nor.push(g.nor[v * 3], g.nor[v * 3 + 1], g.nor[v * 3 + 2]);
|
|
136
|
+
uv.push(src.uv[v * 2], src.uv[v * 2 + 1]);
|
|
137
|
+
}
|
|
138
|
+
idx.push(r);
|
|
139
|
+
}
|
|
140
|
+
tris += list.length;
|
|
141
|
+
meshes.push({ name: clean(src.name || `mesh_${i}`), pos, nor, uv, indices: idx, surface: surfOfMesh.get(i) });
|
|
142
|
+
}
|
|
143
|
+
const oname = cell > 0 ? `${name}_${key}` : name, reference = `${prefix}\\${oname}`;
|
|
144
|
+
const used = [...new Set(meshes.map((m) => m.surface))], local = new Map(used.map((s, k) => [s, k]));
|
|
145
|
+
for (const m of meshes) m.surface = local.get(m.surface);
|
|
146
|
+
files.set(`rawdata/objects/${reference.replace(/\\/g, "/")}.object`, writeObject({ meshes, surfaces: used.map((s) => surfaces[s]) }));
|
|
147
|
+
objects.push({ name: oname, reference });
|
|
148
|
+
}
|
|
149
|
+
const scene = objects.map((x) => ({ ...x, position: [0, 0, 0] }));
|
|
150
|
+
let instTris = 0, protoCount = 0, mirrored = 0;
|
|
151
|
+
if (inst) {
|
|
152
|
+
const protoRef = /* @__PURE__ */ new Map(), used = new Set(inst.placements.map((p) => p.proto)), mirrorMeshes = [];
|
|
153
|
+
const names = /* @__PURE__ */ new Set();
|
|
154
|
+
const meshesOf = (pi, M) => inst.protos[pi].parts.filter((pt) => !o.hidden?.has(pt.mesh) && surfOfMesh.has(pt.mesh) && pt.indices.length >= 3).map((pt, k) => {
|
|
155
|
+
const n = pt.pos.length / 3, pos = [], nor = [];
|
|
156
|
+
for (let v = 0; v < n; v++) {
|
|
157
|
+
let x = pt.pos[v * 3], y = pt.pos[v * 3 + 1], z = pt.pos[v * 3 + 2], a = pt.nor[v * 3], b = pt.nor[v * 3 + 1], c = pt.nor[v * 3 + 2];
|
|
158
|
+
if (M) {
|
|
159
|
+
[x, y, z] = [x * M[0] + y * M[4] + z * M[8] + M[12], x * M[1] + y * M[5] + z * M[9] + M[13], x * M[2] + y * M[6] + z * M[10] + M[14]];
|
|
160
|
+
[a, b, c] = [a * M[0] + b * M[4] + c * M[8], a * M[1] + b * M[5] + c * M[9], a * M[2] + b * M[6] + c * M[10]];
|
|
161
|
+
const l = Math.hypot(a, b, c) || 1;
|
|
162
|
+
a /= l;
|
|
163
|
+
b /= l;
|
|
164
|
+
c /= l;
|
|
165
|
+
}
|
|
166
|
+
pos.push(x * scale, y * scale, z * scale);
|
|
167
|
+
nor.push(a, b, c);
|
|
168
|
+
}
|
|
169
|
+
const indices = Array.from(pt.indices);
|
|
170
|
+
if (M) for (let t = 0; t + 2 < indices.length; t += 3) {
|
|
171
|
+
const q = indices[t + 1];
|
|
172
|
+
indices[t + 1] = indices[t + 2];
|
|
173
|
+
indices[t + 2] = q;
|
|
174
|
+
}
|
|
175
|
+
return { name: `part_${k}`, pos, nor, uv: pt.uv, indices, surface: surfOfMesh.get(pt.mesh) };
|
|
176
|
+
});
|
|
177
|
+
const writeWith = (reference, meshes) => {
|
|
178
|
+
const usedS = [...new Set(meshes.map((m) => m.surface))], local = new Map(usedS.map((x, k) => [x, k]));
|
|
179
|
+
for (const m of meshes) m.surface = local.get(m.surface);
|
|
180
|
+
files.set(`rawdata/objects/${reference.replace(/\\/g, "/")}.object`, writeObject({ meshes, surfaces: usedS.map((x) => surfaces[x]) }));
|
|
181
|
+
};
|
|
182
|
+
for (const pl of inst.placements) {
|
|
183
|
+
if (!used.has(pl.proto) || pl.hidden) continue;
|
|
184
|
+
const M = pl.pose, R = [M[0], M[1], M[2], M[4], M[5], M[6], M[8], M[9], M[10]];
|
|
185
|
+
const sc = [Math.hypot(R[0], R[1], R[2]), Math.hypot(R[3], R[4], R[5]), Math.hypot(R[6], R[7], R[8])];
|
|
186
|
+
const det = R[0] * (R[4] * R[8] - R[5] * R[7]) - R[1] * (R[3] * R[8] - R[5] * R[6]) + R[2] * (R[3] * R[7] - R[4] * R[6]);
|
|
187
|
+
if (det < 0) {
|
|
188
|
+
const ms = meshesOf(pl.proto, M);
|
|
189
|
+
mirrorMeshes.push(...ms);
|
|
190
|
+
mirrored++;
|
|
191
|
+
for (const m of ms) instTris += m.indices.length / 3;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
let ref = protoRef.get(pl.proto);
|
|
195
|
+
if (ref === void 0) {
|
|
196
|
+
const ms = meshesOf(pl.proto, null);
|
|
197
|
+
if (!ms.length) {
|
|
198
|
+
protoRef.set(pl.proto, "");
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
let base = clean(inst.protos[pl.proto].name.split(/[\\/]/).pop() ?? "obj"), cand = base, k = 1;
|
|
202
|
+
while (names.has(cand)) cand = `${base}_${k++}`;
|
|
203
|
+
names.add(cand);
|
|
204
|
+
ref = `${prefix}\\props\\${cand}`;
|
|
205
|
+
writeWith(ref, ms);
|
|
206
|
+
protoRef.set(pl.proto, ref);
|
|
207
|
+
protoCount++;
|
|
208
|
+
}
|
|
209
|
+
if (!ref) continue;
|
|
210
|
+
for (const pt of inst.protos[pl.proto].parts) instTris += pt.indices.length / 3;
|
|
211
|
+
let nm = clean(pl.name), j = 1;
|
|
212
|
+
while (names.has(nm)) nm = `${clean(pl.name)}_${j++}`;
|
|
213
|
+
names.add(nm);
|
|
214
|
+
scene.push({ name: nm, reference: ref, position: [M[12] * scale, M[13] * scale, M[14] * scale], matrix: R.map((v, i) => v / sc[Math.floor(i / 3)]), scale: sc });
|
|
215
|
+
}
|
|
216
|
+
if (mirrorMeshes.length) {
|
|
217
|
+
const ref = `${prefix}\\${name}_mirrored`;
|
|
218
|
+
writeWith(ref, mirrorMeshes);
|
|
219
|
+
scene.push({ name: `${name}_mirrored`, reference: ref, position: [0, 0, 0] });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
for (const [path, data] of writeScene({ name, objects: scene })) files.set(`rawdata/levels/${path}`, data);
|
|
223
|
+
report.push(
|
|
224
|
+
`Объектов .object: ${objects.length}${cell > 0 ? ` (ячейки ${cell} м)` : ""}, треугольников: ${tris}, размер сцены: ${(hi[0] - lo[0]).toFixed(1)} × ${(hi[1] - lo[1]).toFixed(1)} × ${(hi[2] - lo[2]).toFixed(1)} м`,
|
|
225
|
+
...inst ? [`Объекты уровня: ${inst.placements.length} экземпляров, ${protoCount} моделей в ${prefix}\\props (треугольников ${instTris})${mirrored ? `; зеркальных ${mirrored} — влиты в ${name}_mirrored` : ""}`] : [],
|
|
226
|
+
o.xraySource ? `Текстуры, шейдеры и материалы — игровые (${surfaces.length} поверхностей), файлы текстур не копируются` : `Текстуры: ${copied} DDS скопировано, ${encoded} перекодировано в DDS без сжатия${missingTex ? `, ${missingTex} не найдено (объект ссылается на имя, файл положите сами)` : ""}`,
|
|
227
|
+
`Сцена: rawdata/levels/${name}.level — откройте в LevelEditor, добавьте свет, секторы/порталы и спавн, затем соберите xrLC.`
|
|
228
|
+
);
|
|
229
|
+
if (!o.xraySource) {
|
|
230
|
+
report.push("Шейдеры поверхностей — «default», материал — «default»: настройте в редакторе (стекло, листва, двусторонние грани).");
|
|
231
|
+
const mats = [...new Set(meshIdx.map((i) => model.meshes[i].material).filter((x) => !!x))];
|
|
232
|
+
if (mats.length) report.push(`Материалы исходника (для настройки game material): ${mats.slice(0, 30).join(", ")}${mats.length > 30 ? "…" : ""}`);
|
|
233
|
+
}
|
|
234
|
+
if (model.skeleton) report.push("Скелетная модель выгружена в bind-позе как статика (кости и анимации в .object пока не пишутся).");
|
|
235
|
+
if (!model.flipZ) report.push("Координаты переведены в левостороннюю систему X-Ray (Z отражён, обход граней развёрнут).");
|
|
236
|
+
return { files, report };
|
|
237
|
+
}
|
|
238
|
+
export {
|
|
239
|
+
exportXraySdk
|
|
240
|
+
};
|
|
241
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sources":["../src/export.ts"],"sourcesContent":["// Export of any loaded model or level into X-Ray SDK sources (CoP, SDK 0.7):\n// rawdata/objects/<prefix>/<name>_<cell>.object = geometry split into grid cells (for large maps);\n// rawdata/levels/<name>.level + <name>/scene_object.part = a scene with those objects;\n// gamedata/textures/<prefix>/<texture>.dds + .thm = textures (a DDS is copied as is, the rest is written uncompressed).\n// Next: LevelEditor → lights, sectors/portals, spawn → build with xrLC/xrAI/xrDO.\nimport { encodeDdsRgba, hasAlpha } from '@gmvjs/core/writers/dds';\nimport type { DecodedImage, Model } from '@gmvjs/core/types';\nimport { visibleIndices } from '@gmvjs/core/scene';\nimport { writeThm } from './thm';\nimport { writeObject, type ObjectMeshIn, type ObjectSurfaceIn } from './write-object';\nimport { writeScene, type SceneObjectOut } from './write-scene';\n\nexport interface TextureForExport {\n /** Source texture name (for the file name). */\n name: string;\n /** A source DDS is copied without re-encoding. */\n dds?: Uint8Array;\n /** Otherwise a decoded image. */\n image?: DecodedImage | null;\n}\n\nexport interface XrayExportOptions {\n /** Level/object name: Latin letters, digits, \"_\". */\n name: string;\n /** Folder inside rawdata/objects and gamedata/textures. Default: \"gmv\\\\<name>\". */\n prefix?: string;\n /** Unit-to-metre multiplier (X-Ray: 1 = 1 m). */\n scale?: number;\n /** Split cell size, m; 0 = one object. Default: 0 for models, 32 m for scenes larger than 100 m or 60 thousand triangles, 64 m above 400 m. */\n cell?: number;\n /** Mesh texture by number (from the viewing session). */\n texture?: (meshIndex: number) => Promise<TextureForExport | null>;\n /** Hidden meshes are not exported. */\n hidden?: ReadonlySet<number>;\n /**\n * Level objects (model.instances): true (default) = each model as one .object in \"<prefix>\\\\props\", the scene holds references with poses;\n * false = objects are merged into the cell geometry.\n */\n instances?: boolean;\n /**\n * The source is X-Ray itself (a compiled level, OGF, .object): texture names, shaders and materials stay as in the game,\n * textures are not copied (they are already in gamedata).\n */\n xraySource?: boolean;\n}\n\nexport interface XrayExportResult { files: Map<string, Uint8Array>; report: string[] }\n\nconst clean = (s: string) => s.toLowerCase().replace(/\\.[a-z0-9]+$/, '').replace(/[^a-z0-9_]+/g, '_').replace(/^_+|_+$/g, '') || 'tex';\n\n/** Mesh vertices in X-Ray coordinates: bind pose, Z-up -> Y-up, right-handed -> left-handed (with reversed winding), scale. */\nfunction toXray(model: Model, mi: number, scale: number): { pos: Float32Array; nor: Float32Array; indices: Uint32Array } {\n const m = model.meshes[mi]!, n = m.vertexCount, sk = model.skeleton, pos = new Float32Array(n * 3), nor = new Float32Array(n * 3);\n if (sk) sk.pose(null, 0, false);\n for (let v = 0; v < n; v++) {\n let x = m.pos[v * 3]!, y = m.pos[v * 3 + 1]!, z = m.pos[v * 3 + 2]!, a = m.nor[v * 3]!, b = m.nor[v * 3 + 1]!, c = m.nor[v * 3 + 2]!;\n if (sk && m.skinned) {\n let px = 0, py = 0, pz = 0, na = 0, nb = 0, nc = 0, ws = 0;\n for (let k = 0; k < 4; k++) {\n const w = m.weight[v * 4 + k]!;\n if (!w) continue;\n const M = sk.skinV[m.bone[v * 4 + k]!]!;\n ws += w;\n px += w * (x * M[0]! + y * M[4]! + z * M[8]! + M[12]!); py += w * (x * M[1]! + y * M[5]! + z * M[9]! + M[13]!); pz += w * (x * M[2]! + y * M[6]! + z * M[10]! + M[14]!);\n na += w * (a * M[0]! + b * M[4]! + c * M[8]!); nb += w * (a * M[1]! + b * M[5]! + c * M[9]!); nc += w * (a * M[2]! + b * M[6]! + c * M[10]!);\n }\n if (ws) { x = px; y = py; z = pz; a = na; b = nb; c = nc; }\n }\n if (model.defaultZUp) { [y, z] = [z, -y]; [b, c] = [c, -b]; }\n if (!model.flipZ) { z = -z; c = -c; }\n const l = Math.hypot(a, b, c) || 1;\n pos[v * 3] = x * scale; pos[v * 3 + 1] = y * scale; pos[v * 3 + 2] = z * scale;\n nor[v * 3] = a / l; nor[v * 3 + 1] = b / l; nor[v * 3 + 2] = c / l;\n }\n const indices = visibleIndices(model, mi);\n // mirroring flips the winding: the X-Ray outward normal = (b − a) × (c − a)\n if (!model.flipZ) for (let t = 0; t + 2 < indices.length; t += 3) { const q = indices[t + 1]!; indices[t + 1] = indices[t + 2]!; indices[t + 2] = q; }\n return { pos, nor, indices };\n}\n\nexport async function exportXraySdk(model: Model, o: XrayExportOptions): Promise<XrayExportResult> {\n const name = clean(o.name), prefix = (o.prefix ?? `gmv\\\\${name}`).replace(/\\//g, '\\\\').replace(/\\\\+$/, ''), scale = o.scale ?? 1;\n const files = new Map<string, Uint8Array>(), report: string[] = [];\n const inst = o.instances !== false && model.instances && model.flipZ && !model.defaultZUp ? model.instances : null;\n const instMeshes = new Set(inst?.meshes ?? []);\n const meshIdx = model.meshes.map((_, i) => i).filter((i) => !o.hidden?.has(i) && model.meshes[i]!.indices.length >= 3);\n const geo = new Map(meshIdx.filter((i) => !instMeshes.has(i)).map((i) => [i, toXray(model, i, scale)]));\n // scene size -> cell\n const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];\n for (const g of geo.values()) for (let i = 0; i < g.pos.length; i++) { lo[i % 3] = Math.min(lo[i % 3]!, g.pos[i]!); hi[i % 3] = Math.max(hi[i % 3]!, g.pos[i]!); }\n const extent = Math.max(hi[0]! - lo[0]!, hi[2]! - lo[2]!);\n // auto: large scenes are cut into cells so that objects stay manageable in LevelEditor\n const triCount = [...geo.values()].reduce((a, g) => a + g.indices.length / 3, 0);\n const cell = o.cell ?? (extent > 400 ? 64 : extent > 100 || triCount > 60000 ? 32 : 0);\n\n // textures and surfaces: one surface per texture (+ we do not guess double-sidedness from the shader name)\n const surfaces: ObjectSurfaceIn[] = [], surfOfMesh = new Map<number, number>(), texOut = new Map<string, string>();\n let copied = 0, encoded = 0, missingTex = 0;\n for (const i of meshIdx) {\n const m = model.meshes[i]!, key = m.texture || `mesh_${i}`;\n if (o.xraySource) {\n // game names: a surface per combination of texture, shader and material\n const sk = `${m.texture}|${m.shader ?? ''}|${m.material ?? ''}`;\n let si = surfaces.findIndex((x) => `${x.texture}|${x.eshader}|${x.gamemtl}` === sk);\n if (si < 0) si = surfaces.push({ name: `${clean(m.texture.split('\\\\').pop() ?? 's')}_${surfaces.length}`, texture: m.texture, eshader: m.shader || 'default', gamemtl: m.material || 'default' }) - 1;\n surfOfMesh.set(i, si);\n continue;\n }\n let xname = texOut.get(key);\n if (!xname) {\n const base = clean(key.split(/[\\\\/]/).pop() ?? key);\n let cand = base, k = 1;\n while ([...texOut.values()].includes(`${prefix}\\\\${cand}`)) cand = `${base}_${k++}`;\n xname = `${prefix}\\\\${cand}`;\n texOut.set(key, xname);\n const t = o.texture ? await o.texture(i).catch(() => null) : null;\n const path = `gamedata/textures/${xname.replace(/\\\\/g, '/')}`;\n if (t?.dds && t.dds.length > 128) {\n files.set(`${path}.dds`, t.dds);\n const dv = new DataView(t.dds.buffer, t.dds.byteOffset), fourcc = String.fromCharCode(t.dds[84]!, t.dds[85]!, t.dds[86]!, t.dds[87]!);\n files.set(`${path}.thm`, writeThm({ width: dv.getUint32(16, true), height: dv.getUint32(12, true), alpha: fourcc !== 'DXT1' }));\n copied++;\n } else if (t?.image?.rgba) {\n const a = hasAlpha(t.image);\n files.set(`${path}.dds`, encodeDdsRgba({ width: t.image.width, height: t.image.height, rgba: t.image.rgba }));\n files.set(`${path}.thm`, writeThm({ width: t.image.width, height: t.image.height, alpha: a }));\n encoded++;\n } else missingTex++;\n surfaces.push({ name: cand, texture: xname });\n }\n surfOfMesh.set(i, surfaces.findIndex((s) => s.texture === xname));\n }\n\n // cells: a triangle belongs to the cell of its centre\n const cells = new Map<string, Map<number, number[]>>();\n for (const [i, g] of geo) {\n for (let t = 0; t + 2 < g.indices.length; t += 3) {\n let key = 'all';\n if (cell > 0) {\n const a = g.indices[t]! * 3, b = g.indices[t + 1]! * 3, c = g.indices[t + 2]! * 3;\n const cx = (g.pos[a]! + g.pos[b]! + g.pos[c]!) / 3, cz = (g.pos[a + 2]! + g.pos[b + 2]! + g.pos[c + 2]!) / 3;\n key = `${Math.floor((cx - lo[0]!) / cell)}_${Math.floor((cz - lo[2]!) / cell)}`;\n }\n const byMesh = cells.get(key) ?? cells.set(key, new Map()).get(key)!;\n (byMesh.get(i) ?? byMesh.set(i, []).get(i)!).push(t);\n }\n }\n const objects: Array<{ name: string; reference: string }> = [];\n let tris = 0;\n for (const [key, byMesh] of cells) {\n const meshes: ObjectMeshIn[] = [];\n for (const [i, list] of byMesh) {\n const g = geo.get(i)!, src = model.meshes[i]!, remap = new Map<number, number>(), pos: number[] = [], nor: number[] = [], uv: number[] = [], idx: number[] = [];\n for (const t of list) for (let k = 0; k < 3; k++) {\n const v = g.indices[t + k]!;\n let r = remap.get(v);\n if (r === undefined) {\n r = pos.length / 3; remap.set(v, r);\n pos.push(g.pos[v * 3]!, g.pos[v * 3 + 1]!, g.pos[v * 3 + 2]!); nor.push(g.nor[v * 3]!, g.nor[v * 3 + 1]!, g.nor[v * 3 + 2]!); uv.push(src.uv[v * 2]!, src.uv[v * 2 + 1]!);\n }\n idx.push(r);\n }\n tris += list.length;\n meshes.push({ name: clean(src.name || `mesh_${i}`), pos, nor, uv, indices: idx, surface: surfOfMesh.get(i)! });\n }\n const oname = cell > 0 ? `${name}_${key}` : name, reference = `${prefix}\\\\${oname}`;\n // object surfaces: only the ones it uses, renumbered\n const used = [...new Set(meshes.map((m) => m.surface as number))], local = new Map(used.map((s, k) => [s, k]));\n for (const m of meshes) m.surface = local.get(m.surface as number)!;\n files.set(`rawdata/objects/${reference.replace(/\\\\/g, '/')}.object`, writeObject({ meshes, surfaces: used.map((s) => surfaces[s]!) }));\n objects.push({ name: oname, reference });\n }\n const scene: SceneObjectOut[] = objects.map((x) => ({ ...x, position: [0, 0, 0] }));\n let instTris = 0, protoCount = 0, mirrored = 0;\n if (inst) {\n // prototypes: one .object per model; mirrored poses (det < 0) cannot be expressed as a rotation, so their geometry goes into a separate object\n const protoRef = new Map<number, string>(), used = new Set(inst.placements.map((p) => p.proto)), mirrorMeshes: ObjectMeshIn[] = [];\n const names = new Set<string>();\n const meshesOf = (pi: number, M: number[] | null): ObjectMeshIn[] => inst.protos[pi]!.parts.filter((pt) => !o.hidden?.has(pt.mesh) && surfOfMesh.has(pt.mesh) && pt.indices.length >= 3).map((pt, k) => {\n const n = pt.pos.length / 3, pos: number[] = [], nor: number[] = [];\n for (let v = 0; v < n; v++) {\n let x = pt.pos[v * 3]!, y = pt.pos[v * 3 + 1]!, z = pt.pos[v * 3 + 2]!, a = pt.nor[v * 3]!, b = pt.nor[v * 3 + 1]!, c = pt.nor[v * 3 + 2]!;\n if (M) {\n [x, y, z] = [x * M[0]! + y * M[4]! + z * M[8]! + M[12]!, x * M[1]! + y * M[5]! + z * M[9]! + M[13]!, x * M[2]! + y * M[6]! + z * M[10]! + M[14]!];\n [a, b, c] = [a * M[0]! + b * M[4]! + c * M[8]!, a * M[1]! + b * M[5]! + c * M[9]!, a * M[2]! + b * M[6]! + c * M[10]!];\n const l = Math.hypot(a, b, c) || 1; a /= l; b /= l; c /= l;\n }\n pos.push(x * scale, y * scale, z * scale); nor.push(a, b, c);\n }\n const indices = Array.from(pt.indices);\n if (M) for (let t = 0; t + 2 < indices.length; t += 3) { const q = indices[t + 1]!; indices[t + 1] = indices[t + 2]!; indices[t + 2] = q; }\n return { name: `part_${k}`, pos, nor, uv: pt.uv, indices, surface: surfOfMesh.get(pt.mesh)! };\n });\n const writeWith = (reference: string, meshes: ObjectMeshIn[]) => {\n const usedS = [...new Set(meshes.map((m) => m.surface as number))], local = new Map(usedS.map((x, k) => [x, k]));\n for (const m of meshes) m.surface = local.get(m.surface as number)!;\n files.set(`rawdata/objects/${reference.replace(/\\\\/g, '/')}.object`, writeObject({ meshes, surfaces: usedS.map((x) => surfaces[x]!) }));\n };\n for (const pl of inst.placements) {\n if (!used.has(pl.proto) || pl.hidden) continue;\n const M = pl.pose, R = [M[0]!, M[1]!, M[2]!, M[4]!, M[5]!, M[6]!, M[8]!, M[9]!, M[10]!];\n const sc = [Math.hypot(R[0]!, R[1]!, R[2]!), Math.hypot(R[3]!, R[4]!, R[5]!), Math.hypot(R[6]!, R[7]!, R[8]!)];\n const det = R[0]! * (R[4]! * R[8]! - R[5]! * R[7]!) - R[1]! * (R[3]! * R[8]! - R[5]! * R[6]!) + R[2]! * (R[3]! * R[7]! - R[4]! * R[6]!);\n if (det < 0) { const ms = meshesOf(pl.proto, M); mirrorMeshes.push(...ms); mirrored++; for (const m of ms) instTris += m.indices.length / 3; continue; }\n let ref = protoRef.get(pl.proto);\n if (ref === undefined) {\n const ms = meshesOf(pl.proto, null);\n if (!ms.length) { protoRef.set(pl.proto, ''); continue; }\n let base = clean(inst.protos[pl.proto]!.name.split(/[\\\\/]/).pop() ?? 'obj'), cand = base, k = 1;\n while (names.has(cand)) cand = `${base}_${k++}`;\n names.add(cand);\n ref = `${prefix}\\\\props\\\\${cand}`;\n writeWith(ref, ms);\n protoRef.set(pl.proto, ref);\n protoCount++;\n }\n if (!ref) continue;\n for (const pt of inst.protos[pl.proto]!.parts) instTris += pt.indices.length / 3;\n let nm = clean(pl.name), j = 1;\n while (names.has(nm)) nm = `${clean(pl.name)}_${j++}`;\n names.add(nm);\n scene.push({ name: nm, reference: ref, position: [M[12]! * scale, M[13]! * scale, M[14]! * scale], matrix: R.map((v, i) => v / sc[Math.floor(i / 3)]!), scale: sc });\n }\n if (mirrorMeshes.length) {\n const ref = `${prefix}\\\\${name}_mirrored`;\n writeWith(ref, mirrorMeshes);\n scene.push({ name: `${name}_mirrored`, reference: ref, position: [0, 0, 0] });\n }\n }\n for (const [path, data] of writeScene({ name, objects: scene })) files.set(`rawdata/levels/${path}`, data);\n\n report.push(\n `Объектов .object: ${objects.length}${cell > 0 ? ` (ячейки ${cell} м)` : ''}, треугольников: ${tris}, размер сцены: ${(hi[0]! - lo[0]!).toFixed(1)} × ${(hi[1]! - lo[1]!).toFixed(1)} × ${(hi[2]! - lo[2]!).toFixed(1)} м`,\n ...(inst ? [`Объекты уровня: ${inst.placements.length} экземпляров, ${protoCount} моделей в ${prefix}\\\\props (треугольников ${instTris})${mirrored ? `; зеркальных ${mirrored} — влиты в ${name}_mirrored` : ''}`] : []),\n o.xraySource ? `Текстуры, шейдеры и материалы — игровые (${surfaces.length} поверхностей), файлы текстур не копируются` : `Текстуры: ${copied} DDS скопировано, ${encoded} перекодировано в DDS без сжатия${missingTex ? `, ${missingTex} не найдено (объект ссылается на имя, файл положите сами)` : ''}`,\n `Сцена: rawdata/levels/${name}.level — откройте в LevelEditor, добавьте свет, секторы/порталы и спавн, затем соберите xrLC.`,\n );\n if (!o.xraySource) {\n report.push('Шейдеры поверхностей — «default», материал — «default»: настройте в редакторе (стекло, листва, двусторонние грани).');\n const mats = [...new Set(meshIdx.map((i) => model.meshes[i]!.material).filter((x): x is string => !!x))];\n if (mats.length) report.push(`Материалы исходника (для настройки game material): ${mats.slice(0, 30).join(', ')}${mats.length > 30 ? '…' : ''}`);\n }\n if (model.skeleton) report.push('Скелетная модель выгружена в bind-позе как статика (кости и анимации в .object пока не пишутся).');\n if (!model.flipZ) report.push('Координаты переведены в левостороннюю систему X-Ray (Z отражён, обход граней развёрнут).');\n return { files, report };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const engine: import("@gmvjs/core/plugin").EnginePlugin;
|
|
2
|
+
export declare const preset: import("@gmvjs/core/plugin").GamePreset;
|
|
3
|
+
declare const _default: {
|
|
4
|
+
engine: import("@gmvjs/core/plugin").EnginePlugin;
|
|
5
|
+
preset: import("@gmvjs/core/plugin").GamePreset;
|
|
6
|
+
};
|
|
7
|
+
export default _default;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { pickGames } from "@gmvjs/core/plugin";
|
|
2
|
+
import { xrayV1Engine } from "../index.js";
|
|
3
|
+
const engine = pickGames(xrayV1Engine, "stalker-cop");
|
|
4
|
+
const preset = engine.games[0];
|
|
5
|
+
const cop = { engine, preset };
|
|
6
|
+
export {
|
|
7
|
+
cop as default,
|
|
8
|
+
engine,
|
|
9
|
+
preset
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=cop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cop.js","sources":["../../src/games/cop.ts"],"sourcesContent":["// S.T.A.L.K.E.R.: Call of Pripyat — subpath `@gmvjs/xray-v1/cop`: the game preset and an engine limited to it.\nimport { pickGames } from '@gmvjs/core/plugin';\nimport { xrayV1Engine } from '../index';\n\nexport const engine = pickGames(xrayV1Engine, 'stalker-cop');\nexport const preset = engine.games![0]!;\nexport default { engine, preset };\n"],"names":[],"mappings":";;AAIO,MAAM,SAAS,UAAU,cAAc,aAAa;AACpD,MAAM,SAAS,OAAO,MAAO,CAAC;AACrC,MAAA,MAAe,EAAE,QAAQ,OAAA;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const engine: import("@gmvjs/core/plugin").EnginePlugin;
|
|
2
|
+
export declare const preset: import("@gmvjs/core/plugin").GamePreset;
|
|
3
|
+
declare const _default: {
|
|
4
|
+
engine: import("@gmvjs/core/plugin").EnginePlugin;
|
|
5
|
+
preset: import("@gmvjs/core/plugin").GamePreset;
|
|
6
|
+
};
|
|
7
|
+
export default _default;
|
package/dist/games/cs.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { pickGames } from "@gmvjs/core/plugin";
|
|
2
|
+
import { xrayV1Engine } from "../index.js";
|
|
3
|
+
const engine = pickGames(xrayV1Engine, "stalker-cs");
|
|
4
|
+
const preset = engine.games[0];
|
|
5
|
+
const cs = { engine, preset };
|
|
6
|
+
export {
|
|
7
|
+
cs as default,
|
|
8
|
+
engine,
|
|
9
|
+
preset
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=cs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cs.js","sources":["../../src/games/cs.ts"],"sourcesContent":["// S.T.A.L.K.E.R.: Clear Sky — subpath `@gmvjs/xray-v1/cs`: the game preset and an engine limited to it.\nimport { pickGames } from '@gmvjs/core/plugin';\nimport { xrayV1Engine } from '../index';\n\nexport const engine = pickGames(xrayV1Engine, 'stalker-cs');\nexport const preset = engine.games![0]!;\nexport default { engine, preset };\n"],"names":[],"mappings":";;AAIO,MAAM,SAAS,UAAU,cAAc,YAAY;AACnD,MAAM,SAAS,OAAO,MAAO,CAAC;AACrC,MAAA,KAAe,EAAE,QAAQ,OAAA;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { exportXraySdk, type XrayExportOptions, type XrayExportResult, type TextureForExport } from '../index';
|
|
2
|
+
/** The "X-Ray SDK 0.7 sources" export option (ExporterPlugin). */
|
|
3
|
+
export declare const exporter: import("@gmvjs/core/plugin").ExporterPlugin;
|
|
4
|
+
declare const _default: {
|
|
5
|
+
exporter: import("@gmvjs/core/plugin").ExporterPlugin;
|
|
6
|
+
};
|
|
7
|
+
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { xrayV1Engine } from "../index.js";
|
|
2
|
+
import { exportXraySdk } from "../index.js";
|
|
3
|
+
const exporter = xrayV1Engine.exporters.find((x) => x.id === "xray-sdk");
|
|
4
|
+
const sdk = { exporter };
|
|
5
|
+
export {
|
|
6
|
+
sdk as default,
|
|
7
|
+
exportXraySdk,
|
|
8
|
+
exporter
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=sdk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../src/games/sdk.ts"],"sourcesContent":["// Export to X-Ray SDK 0.7 — subpath `@gmvjs/xray-v1/sdk`.\nimport { xrayV1Engine } from '../index';\n\nexport { exportXraySdk, type XrayExportOptions, type XrayExportResult, type TextureForExport } from '../index';\n/** The \"X-Ray SDK 0.7 sources\" export option (ExporterPlugin). */\nexport const exporter = xrayV1Engine.exporters!.find((x) => x.id === 'xray-sdk')!;\nexport default { exporter };\n"],"names":[],"mappings":";;AAKO,MAAM,WAAW,aAAa,UAAW,KAAK,CAAC,MAAM,EAAE,OAAO,UAAU;AAC/E,MAAA,MAAe,EAAE,SAAA;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const engine: import("@gmvjs/core/plugin").EnginePlugin;
|
|
2
|
+
export declare const preset: import("@gmvjs/core/plugin").GamePreset;
|
|
3
|
+
declare const _default: {
|
|
4
|
+
engine: import("@gmvjs/core/plugin").EnginePlugin;
|
|
5
|
+
preset: import("@gmvjs/core/plugin").GamePreset;
|
|
6
|
+
};
|
|
7
|
+
export default _default;
|
|
8
|
+
/** Encryption of the gamedata.db* file table (for tests and building archives). */
|
|
9
|
+
export { socEncode } from '../soc-key';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { pickGames } from "@gmvjs/core/plugin";
|
|
2
|
+
import { xrayV1Engine } from "../index.js";
|
|
3
|
+
import { socEncode } from "../soc-key.js";
|
|
4
|
+
const engine = pickGames(xrayV1Engine, "stalker-soc");
|
|
5
|
+
const preset = engine.games[0];
|
|
6
|
+
const soc = { engine, preset };
|
|
7
|
+
export {
|
|
8
|
+
soc as default,
|
|
9
|
+
engine,
|
|
10
|
+
preset,
|
|
11
|
+
socEncode
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=soc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"soc.js","sources":["../../src/games/soc.ts"],"sourcesContent":["// S.T.A.L.K.E.R.: Shadow of Chernobyl — subpath `@gmvjs/xray-v1/soc`: the game preset and an engine limited to it.\nimport { pickGames } from '@gmvjs/core/plugin';\nimport { xrayV1Engine } from '../index';\n\nexport const engine = pickGames(xrayV1Engine, 'stalker-soc');\nexport const preset = engine.games![0]!;\nexport default { engine, preset };\n/** Encryption of the gamedata.db* file table (for tests and building archives). */\nexport { socEncode } from '../soc-key';\n"],"names":[],"mappings":";;;AAIO,MAAM,SAAS,UAAU,cAAc,aAAa;AACpD,MAAM,SAAS,OAAO,MAAO,CAAC;AACrC,MAAA,MAAe,EAAE,QAAQ,OAAA;"}
|
package/dist/i18n.d.ts
ADDED
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const EN = {
|
|
2
|
+
"presets": {
|
|
3
|
+
"stalker-soc": {
|
|
4
|
+
"title": "S.T.A.L.K.E.R.: Shadow of Chernobyl",
|
|
5
|
+
"hint": "OGF v4. Animations are inside the model or in an external .omf. gamedata.db* archives open through “Game folder” (the file-table key is taken from your game’s bin/XR_3DA.exe) or with “Open .db…” together with XR_3DA.exe; mod .xdb archives and an unpacked gamedata folder open too. External .omf files referenced by a model are attached automatically when the gamedata folder or archives are open; torso animations play together with legs (choose in “Other body parts”). Levels include grass from level.details; SDK sources: .object with skeleton and animations, .skl/.skls.",
|
|
6
|
+
"archiveLabel": "Open .db…"
|
|
7
|
+
},
|
|
8
|
+
"stalker-cs": {
|
|
9
|
+
"title": "S.T.A.L.K.E.R.: Clear Sky",
|
|
10
|
+
"hint": "OGF v4. Open resources.db0–db2 (models and textures) and patches/xpatch_*.db, or a gamedata folder. External .omf files referenced by a model are attached automatically when the gamedata folder or archives are open; torso animations play together with legs (choose in “Other body parts”). Levels include grass from level.details; SDK sources: .object with skeleton and animations, .skl/.skls.",
|
|
11
|
+
"archiveLabel": "Open .db…"
|
|
12
|
+
},
|
|
13
|
+
"stalker-cop": {
|
|
14
|
+
"title": "S.T.A.L.K.E.R.: Call of Pripyat",
|
|
15
|
+
"hint": "OGF v4, including 3- and 4-weight vertices. .db archives as in Clear Sky. External .omf files referenced by a model are attached automatically when the gamedata folder or archives are open; torso animations play together with legs (choose in “Other body parts”). Levels include grass from level.details; SDK sources: .object with skeleton and animations, .skl/.skls.",
|
|
16
|
+
"archiveLabel": "Open .db…"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"exporters": {
|
|
20
|
+
"xray-sdk": {
|
|
21
|
+
"title": "S.T.A.L.K.E.R.: X-Ray SDK 0.7 sources",
|
|
22
|
+
"description": "For LevelEditor and ActorEditor (Call of Pripyat, SDK 0.7): .object geometry (large maps are split into cells), a .level + scene_object.part scene, DDS + .thm textures — one ZIP. Lights, sectors, the AI grid and the xrLC build are done in the SDK.",
|
|
23
|
+
"fields": {
|
|
24
|
+
"name": {
|
|
25
|
+
"label": "Level name",
|
|
26
|
+
"hint": 'Latin letters, digits, "_": rawdata/objects/gmv/<name>, rawdata/levels/<name>.level'
|
|
27
|
+
},
|
|
28
|
+
"cell": {
|
|
29
|
+
"label": "Cell, m",
|
|
30
|
+
"placeholder": "auto",
|
|
31
|
+
"hint": "Split the geometry into objects (0 — a single object; 32–64 suits maps)"
|
|
32
|
+
},
|
|
33
|
+
"scale": {
|
|
34
|
+
"label": "Scale",
|
|
35
|
+
"hint": "Metres per model unit (X-Ray: 1 unit = 1 m)"
|
|
36
|
+
},
|
|
37
|
+
"instances": {
|
|
38
|
+
"label": "Level objects as references",
|
|
39
|
+
"hint": "Each object model becomes one .object in props, the scene holds references with poses. Uncheck to merge objects into the cell geometry"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export {
|
|
46
|
+
EN
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=i18n.js.map
|
package/dist/i18n.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.js","sources":["../src/i18n.ts"],"sourcesContent":["// English texts of the xray-v1 engine (Russian ones live in the plugins themselves).\nimport type { EngineTexts } from '@gmvjs/core/plugin';\n\nexport const EN: EngineTexts = {\n \"presets\": {\n \"stalker-soc\": {\n \"title\": \"S.T.A.L.K.E.R.: Shadow of Chernobyl\",\n \"hint\": \"OGF v4. Animations are inside the model or in an external .omf. gamedata.db* archives open through “Game folder” (the file-table key is taken from your game’s bin/XR_3DA.exe) or with “Open .db…” together with XR_3DA.exe; mod .xdb archives and an unpacked gamedata folder open too. External .omf files referenced by a model are attached automatically when the gamedata folder or archives are open; torso animations play together with legs (choose in “Other body parts”). Levels include grass from level.details; SDK sources: .object with skeleton and animations, .skl/.skls.\",\n \"archiveLabel\": \"Open .db…\"\n },\n \"stalker-cs\": {\n \"title\": \"S.T.A.L.K.E.R.: Clear Sky\",\n \"hint\": \"OGF v4. Open resources.db0–db2 (models and textures) and patches/xpatch_*.db, or a gamedata folder. External .omf files referenced by a model are attached automatically when the gamedata folder or archives are open; torso animations play together with legs (choose in “Other body parts”). Levels include grass from level.details; SDK sources: .object with skeleton and animations, .skl/.skls.\",\n \"archiveLabel\": \"Open .db…\"\n },\n \"stalker-cop\": {\n \"title\": \"S.T.A.L.K.E.R.: Call of Pripyat\",\n \"hint\": \"OGF v4, including 3- and 4-weight vertices. .db archives as in Clear Sky. External .omf files referenced by a model are attached automatically when the gamedata folder or archives are open; torso animations play together with legs (choose in “Other body parts”). Levels include grass from level.details; SDK sources: .object with skeleton and animations, .skl/.skls.\",\n \"archiveLabel\": \"Open .db…\"\n }\n },\n \"exporters\": {\n \"xray-sdk\": {\n \"title\": \"S.T.A.L.K.E.R.: X-Ray SDK 0.7 sources\",\n \"description\": \"For LevelEditor and ActorEditor (Call of Pripyat, SDK 0.7): .object geometry (large maps are split into cells), a .level + scene_object.part scene, DDS + .thm textures — one ZIP. Lights, sectors, the AI grid and the xrLC build are done in the SDK.\",\n \"fields\": {\n \"name\": {\n \"label\": \"Level name\",\n \"hint\": \"Latin letters, digits, \\\"_\\\": rawdata/objects/gmv/<name>, rawdata/levels/<name>.level\"\n },\n \"cell\": {\n \"label\": \"Cell, m\",\n \"placeholder\": \"auto\",\n \"hint\": \"Split the geometry into objects (0 — a single object; 32–64 suits maps)\"\n },\n \"scale\": {\n \"label\": \"Scale\",\n \"hint\": \"Metres per model unit (X-Ray: 1 unit = 1 m)\"\n },\n \"instances\": {\n \"label\": \"Level objects as references\",\n \"hint\": \"Each object model becomes one .object in props, the scene holds references with poses. Uncheck to merge objects into the cell geometry\"\n }\n }\n }\n }\n};\n"],"names":[],"mappings":"AAGO,MAAM,KAAkB;AAAA,EAC7B,WAAW;AAAA,IACT,eAAe;AAAA,MACb,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAAA;AAAA,IAElB,cAAc;AAAA,MACZ,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAAA;AAAA,IAElB,eAAe;AAAA,MACb,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAAA;AAAA,EAClB;AAAA,EAEF,aAAa;AAAA,IACX,YAAY;AAAA,MACV,SAAS;AAAA,MACT,eAAe;AAAA,MACf,UAAU;AAAA,QACR,QAAQ;AAAA,UACN,SAAS;AAAA,UACT,QAAQ;AAAA,QAAA;AAAA,QAEV,QAAQ;AAAA,UACN,SAAS;AAAA,UACT,eAAe;AAAA,UACf,QAAQ;AAAA,QAAA;AAAA,QAEV,SAAS;AAAA,UACP,SAAS;AAAA,UACT,QAAQ;AAAA,QAAA;AAAA,QAEV,aAAa;AAAA,UACX,SAAS;AAAA,UACT,QAAQ;AAAA,QAAA;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEJ;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const xrayV1Engine: import("@gmvjs/core/plugin").EnginePlugin;
|
|
2
|
+
/** Export of a model/level into X-Ray SDK sources (.object, .level, textures); the module is loaded on demand. */
|
|
3
|
+
export declare function exportXraySdk(...args: Parameters<typeof import('./export').exportXraySdk>): ReturnType<typeof import('./export').exportXraySdk>;
|
|
4
|
+
export type { XrayExportOptions, XrayExportResult, TextureForExport } from './export';
|
|
5
|
+
export { autoLayers, XRAY_FX_PART, type XrayMotion, type XrayTrack } from './motion';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { u32le, ascii } from "@gmvjs/core/binary";
|
|
2
|
+
import { defineEngine } from "@gmvjs/core/plugin";
|
|
3
|
+
import { EN } from "./i18n.js";
|
|
4
|
+
import { XRAY_FX_PART, autoLayers } from "./motion.js";
|
|
5
|
+
const DB_EXTS = ["db", "xdb", ..."0123456789".split("").flatMap((d) => ["db" + d, "xdb" + d]), "dba", "dbb", "dbc", "dbd"];
|
|
6
|
+
const ui = { motionLabel: "+ .omf", invertQuat: true, archives: true, archiveExts: [...DB_EXTS, "exe"], archiveLabel: "Открыть .db…" };
|
|
7
|
+
const game = (id, title, hint) => ({ id, group: "Игры", title, engine: "xray-v1", formats: ["xray-ogf", "xray-object", "xray-level", "xray-dm", "xray-scene"], hint, ui, status: "beta", markers: ["gamedata", "fsgame.ltx"] });
|
|
8
|
+
const xrayV1Engine = defineEngine({
|
|
9
|
+
id: "xray-v1",
|
|
10
|
+
title: "X-Ray Engine 1.x",
|
|
11
|
+
i18n: { en: EN },
|
|
12
|
+
formats: [
|
|
13
|
+
{
|
|
14
|
+
id: "xray-ogf",
|
|
15
|
+
title: "X-Ray OGF",
|
|
16
|
+
engine: "xray-v1",
|
|
17
|
+
extensions: ["ogf"],
|
|
18
|
+
motionExtensions: ["omf", "skl", "skls"],
|
|
19
|
+
status: "beta",
|
|
20
|
+
// the first chunk is OGF_HEADER (id 1), then a version byte; otherwise not certain, but not excluded either
|
|
21
|
+
sniff: (h) => u32le(h, 0) === 1 ? h[8] === 4 ? 1 : 0.6 : 0.2,
|
|
22
|
+
load: async (main, ctx) => (await import("./load.js")).loadOgf(main, ctx)
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "xray-object",
|
|
26
|
+
title: "X-Ray SDK .object",
|
|
27
|
+
engine: "xray-v1",
|
|
28
|
+
extensions: ["object"],
|
|
29
|
+
motionExtensions: ["omf", "skl", "skls"],
|
|
30
|
+
status: "beta",
|
|
31
|
+
sniff: (h) => u32le(h, 0) === 30583 ? 1 : 0,
|
|
32
|
+
load: async (main, ctx) => (await import("./load.js")).loadObject(main, ctx)
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "xray-level",
|
|
36
|
+
title: "X-Ray: скомпилированный уровень (level + level.geom)",
|
|
37
|
+
engine: "xray-v1",
|
|
38
|
+
extensions: [],
|
|
39
|
+
pathPattern: /(^|\/)levels\/[^/]+\/level$/,
|
|
40
|
+
status: "beta",
|
|
41
|
+
// the first chunk is the level header (id 1, 4 bytes: version and quality)
|
|
42
|
+
sniff: (h) => u32le(h, 0) === 1 && u32le(h, 4) === 4 && u32le(h, 8) !== 16 ? 0.9 : 0,
|
|
43
|
+
// 16 is the Metro 2033 (4A) level version
|
|
44
|
+
load: async (main, ctx) => (await import("./level.js")).loadLevel(main, ctx)
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "xray-dm",
|
|
48
|
+
title: "X-Ray: деталь (.dm — трава, кусты)",
|
|
49
|
+
engine: "xray-v1",
|
|
50
|
+
extensions: ["dm"],
|
|
51
|
+
status: "beta",
|
|
52
|
+
// starts with a shader name (Latin letters, "\\", "_")
|
|
53
|
+
sniff: (h) => /^[\w\\.-]{2,}\0/.test(ascii(h, 0, Math.min(h.length, 64))) ? 0.8 : 0,
|
|
54
|
+
load: async (main) => {
|
|
55
|
+
const { parseDM, dmMesh } = await import("./details.js");
|
|
56
|
+
const { boundsOf } = await import("@gmvjs/core/geometry");
|
|
57
|
+
const m = parseDM(new Uint8Array(await main.arrayBuffer())), mesh = dmMesh(m, m.texture);
|
|
58
|
+
return { meshes: [mesh], skeleton: null, motions: [], bounds: boundsOf([mesh]), flipZ: true, info: [`Деталь X-Ray: ${m.shader} · ${m.texture}`, `Вершин ${mesh.vertexCount}, треугольников ${m.indices.length / 3}, масштаб ${m.minScale}…${m.maxScale}`] };
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "xray-scene",
|
|
63
|
+
title: "X-Ray SDK: уровень (.level + scene_object.part)",
|
|
64
|
+
engine: "xray-v1",
|
|
65
|
+
extensions: ["level"],
|
|
66
|
+
status: "beta",
|
|
67
|
+
// SDK 0.7 (CoP) saves the scene as ini; binary .level files of older SDKs are not read yet
|
|
68
|
+
sniff: (h) => /^\s*\[(build_params|camera|guid|level_options|level_tag|version)\]/.test(ascii(h, 0, Math.min(h.length, 64))) ? 1 : 0,
|
|
69
|
+
load: async (main, ctx) => (await import("./scene.js")).loadSceneLevel(main, ctx)
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
archives: [
|
|
73
|
+
{
|
|
74
|
+
id: "xray-db",
|
|
75
|
+
title: "X-Ray .db / .xdb (Чистое небо, Зов Припяти)",
|
|
76
|
+
engine: "xray-v1",
|
|
77
|
+
extensions: DB_EXTS,
|
|
78
|
+
// SoC: the game executable is an archive companion (the file table key is taken from it)
|
|
79
|
+
companionExtensions: ["exe"],
|
|
80
|
+
// in the "Game folder" archives open by themselves (only the file table is read): CS/CoP with a header, SoC gamedata.db*
|
|
81
|
+
openFromFolder: (h, name) => u32le(h, 0) === 666 || u32le(h, 0) === 0 && /^gamedata\.db[0-9a-z]$/i.test(name),
|
|
82
|
+
// CS/CoP start with the text [header] chunk (id 0x29A), SoC and mods with the data chunk (id 0)
|
|
83
|
+
sniff: (h) => u32le(h, 0) === 666 ? 1 : u32le(h, 0) === 0 ? 0.5 : 0,
|
|
84
|
+
open: async (file, siblings) => (await import("./db.js")).openXrayDb(file, siblings)
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
exporters: [
|
|
88
|
+
{
|
|
89
|
+
id: "xray-sdk",
|
|
90
|
+
title: "S.T.A.L.K.E.R.: исходники X-Ray SDK 0.7",
|
|
91
|
+
target: "xray",
|
|
92
|
+
description: "Для LevelEditor и ActorEditor (Зов Припяти, SDK 0.7): геометрия .object (большие карты режутся на ячейки), сцена .level + scene_object.part, текстуры DDS + .thm — одним ZIP. Свет, секторы, AI-сетку и сборку xrLC делаете в SDK.",
|
|
93
|
+
from: ["4a", "xray-v1"],
|
|
94
|
+
fields: [
|
|
95
|
+
{ id: "name", label: "Имя уровня", type: "text", hint: "Латиница, цифры, «_»: rawdata/objects/gmv/<имя>, rawdata/levels/<имя>.level", default: (_m, base) => base.toLowerCase().replace(/[^a-z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "level" },
|
|
96
|
+
{ id: "cell", label: "Ячейка, м", type: "number", min: 0, step: 8, placeholder: "авто", hint: "Разбиение геометрии на объекты (0 — одним объектом; для карт удобно 32–64)" },
|
|
97
|
+
{ id: "scale", label: "Масштаб", type: "number", min: 0, step: 0.01, default: 1, hint: "Сколько метров в одной единице модели (X-Ray: 1 единица = 1 м)" },
|
|
98
|
+
{ id: "instances", label: "Объекты уровня — ссылками", type: "checkbox", default: true, hint: "Каждая модель объекта одним .object в props, в сцене — ссылки с позами. Снимите, чтобы влить объекты в геометрию ячеек", when: (m) => !!m.instances }
|
|
99
|
+
],
|
|
100
|
+
run: async (model, v, ctx) => {
|
|
101
|
+
const { exportXraySdk: exportXraySdk2 } = await import("./export.js");
|
|
102
|
+
const name = String(v.name || ctx.baseName);
|
|
103
|
+
const r = await exportXraySdk2(model, {
|
|
104
|
+
name,
|
|
105
|
+
cell: v.cell === "" || v.cell === void 0 ? void 0 : +v.cell,
|
|
106
|
+
scale: +v.scale || 1,
|
|
107
|
+
hidden: ctx.hidden,
|
|
108
|
+
texture: (i) => ctx.texture(i),
|
|
109
|
+
xraySource: ctx.sourceEngine === "xray-v1",
|
|
110
|
+
instances: v.instances !== false
|
|
111
|
+
});
|
|
112
|
+
return { ...r, name: `${name}_xray_sdk` };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
games: [
|
|
117
|
+
game("stalker-soc", "S.T.A.L.K.E.R.: Тень Чернобыля", "OGF v4. Анимации — внутри модели или во внешнем .omf. Архивы gamedata.db* открываются через «Папку игры» (ключ таблиц файлов берётся из bin/XR_3DA.exe вашей игры) или кнопкой «Открыть .db…» вместе с XR_3DA.exe; .xdb модов и распакованная gamedata тоже открываются. Внешние .omf из ссылок модели подключаются сами, если открыта папка gamedata или архивы; анимации торса играют вместе с ногами (выбор — «Другие части тела»). Уровни — с травой из level.details; исходники SDK: .object со скелетом и анимациями, .skl/.skls."),
|
|
118
|
+
game("stalker-cs", "S.T.A.L.K.E.R.: Чистое небо", "OGF v4. Откройте resources.db0–db2 (модели и текстуры) и patches/xpatch_*.db или папку gamedata. Внешние .omf из ссылок модели подключаются сами, если открыта папка gamedata или архивы; анимации торса играют вместе с ногами (выбор — «Другие части тела»). Уровни — с травой из level.details; исходники SDK: .object со скелетом и анимациями, .skl/.skls."),
|
|
119
|
+
game("stalker-cop", "S.T.A.L.K.E.R.: Зов Припяти", "OGF v4, в том числе 3/4-весовые вершины. Архивы .db — как у Чистого неба. Внешние .omf из ссылок модели подключаются сами, если открыта папка gamedata или архивы; анимации торса играют вместе с ногами (выбор — «Другие части тела»). Уровни — с травой из level.details; исходники SDK: .object со скелетом и анимациями, .skl/.skls.")
|
|
120
|
+
]
|
|
121
|
+
});
|
|
122
|
+
async function exportXraySdk(...args) {
|
|
123
|
+
return (await import("./export.js")).exportXraySdk(...args);
|
|
124
|
+
}
|
|
125
|
+
export {
|
|
126
|
+
XRAY_FX_PART,
|
|
127
|
+
autoLayers,
|
|
128
|
+
exportXraySdk,
|
|
129
|
+
xrayV1Engine
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=index.js.map
|