quake2ts 0.0.43 → 0.0.45
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/apps/viewer/dist/browser/index.global.js +1 -1
- package/apps/viewer/dist/browser/index.global.js.map +1 -1
- package/apps/viewer/dist/cjs/index.cjs +3 -0
- package/apps/viewer/dist/cjs/index.cjs.map +1 -1
- package/apps/viewer/dist/esm/index.js +3 -0
- package/apps/viewer/dist/esm/index.js.map +1 -1
- package/apps/viewer/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/packages/game/dist/browser/index.global.js +1 -1
- package/packages/game/dist/browser/index.global.js.map +1 -1
- package/packages/game/dist/cjs/index.cjs +152 -0
- package/packages/game/dist/cjs/index.cjs.map +1 -1
- package/packages/game/dist/esm/index.js +148 -0
- package/packages/game/dist/esm/index.js.map +1 -1
- package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/game/dist/types/save/rerelease.d.ts +25 -0
- package/packages/game/dist/types/save/rerelease.d.ts.map +1 -1
|
@@ -2625,6 +2625,150 @@ function summarizeRereleaseSave(raw) {
|
|
|
2625
2625
|
highestEntityIndex: highestEntityIndex >= 0 ? highestEntityIndex : void 0
|
|
2626
2626
|
};
|
|
2627
2627
|
}
|
|
2628
|
+
var SERIALIZABLE_FIELD_NAMES = new Set(
|
|
2629
|
+
ENTITY_FIELD_METADATA.filter((field) => field.save).map((field) => field.name)
|
|
2630
|
+
);
|
|
2631
|
+
function toVec3(value, label) {
|
|
2632
|
+
if (!Array.isArray(value) || value.length !== 3) {
|
|
2633
|
+
throw new Error(`${label} must be a vec3 array`);
|
|
2634
|
+
}
|
|
2635
|
+
const [x, y, z] = value;
|
|
2636
|
+
return [ensureNumber2(x, `${label}[0]`), ensureNumber2(y, `${label}[1]`), ensureNumber2(z, `${label}[2]`)];
|
|
2637
|
+
}
|
|
2638
|
+
function normalizeEntityFields(raw, label) {
|
|
2639
|
+
const fields = {};
|
|
2640
|
+
for (const [rawName, value] of Object.entries(raw)) {
|
|
2641
|
+
const name = rawName;
|
|
2642
|
+
if (!SERIALIZABLE_FIELD_NAMES.has(name)) {
|
|
2643
|
+
continue;
|
|
2644
|
+
}
|
|
2645
|
+
if (value === null) {
|
|
2646
|
+
fields[name] = null;
|
|
2647
|
+
continue;
|
|
2648
|
+
}
|
|
2649
|
+
if (Array.isArray(value)) {
|
|
2650
|
+
fields[name] = toVec3(value, `${label}.${name}`);
|
|
2651
|
+
continue;
|
|
2652
|
+
}
|
|
2653
|
+
switch (typeof value) {
|
|
2654
|
+
case "number":
|
|
2655
|
+
case "string":
|
|
2656
|
+
case "boolean":
|
|
2657
|
+
fields[name] = value;
|
|
2658
|
+
break;
|
|
2659
|
+
default:
|
|
2660
|
+
throw new Error(`Unsupported field type for ${label}.${name}`);
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
return fields;
|
|
2664
|
+
}
|
|
2665
|
+
function buildEntitySnapshot(entities, levelTimeSeconds, capacityHint) {
|
|
2666
|
+
let highestIndex = 0;
|
|
2667
|
+
const active = /* @__PURE__ */ new Set();
|
|
2668
|
+
const activeOrder = [];
|
|
2669
|
+
const serialized = [];
|
|
2670
|
+
for (const [index, entry] of entities.entries()) {
|
|
2671
|
+
if (index > highestIndex) {
|
|
2672
|
+
highestIndex = index;
|
|
2673
|
+
}
|
|
2674
|
+
const inUse = entry.inuse !== false;
|
|
2675
|
+
if (!inUse) {
|
|
2676
|
+
continue;
|
|
2677
|
+
}
|
|
2678
|
+
if (!active.has(index)) {
|
|
2679
|
+
activeOrder.push(index);
|
|
2680
|
+
}
|
|
2681
|
+
active.add(index);
|
|
2682
|
+
serialized.push({ index, fields: normalizeEntityFields(entry, `entities[${index}]`) });
|
|
2683
|
+
}
|
|
2684
|
+
if (!active.has(0)) {
|
|
2685
|
+
active.add(0);
|
|
2686
|
+
activeOrder.unshift(0);
|
|
2687
|
+
serialized.unshift({ index: 0, fields: { classname: "worldspawn" } });
|
|
2688
|
+
}
|
|
2689
|
+
const capacity = Math.max(capacityHint ?? 0, highestIndex + 1, Math.max(...active) + 1);
|
|
2690
|
+
const freeList = [];
|
|
2691
|
+
for (let i = 0; i < capacity; i += 1) {
|
|
2692
|
+
if (!active.has(i)) {
|
|
2693
|
+
freeList.push(i);
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
return {
|
|
2697
|
+
timeSeconds: levelTimeSeconds,
|
|
2698
|
+
pool: { capacity, activeOrder, freeList, pendingFree: [] },
|
|
2699
|
+
entities: serialized,
|
|
2700
|
+
thinks: []
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2703
|
+
function buildLevelState(level) {
|
|
2704
|
+
const timeSeconds = typeof level.time === "number" ? level.time : 0;
|
|
2705
|
+
const frameNumber = typeof level.framenum === "number" ? level.framenum : 0;
|
|
2706
|
+
const deltaSeconds = typeof level.frametime === "number" ? level.frametime : 0;
|
|
2707
|
+
const previousTimeSeconds = timeSeconds - deltaSeconds;
|
|
2708
|
+
return { frameNumber, timeSeconds, previousTimeSeconds, deltaSeconds };
|
|
2709
|
+
}
|
|
2710
|
+
function convertRereleaseLevelToGameSave(save, options = {}) {
|
|
2711
|
+
const { timestamp = Date.now(), defaultDifficulty = 1, defaultPlaytimeSeconds, rngState, configstrings = [] } = options;
|
|
2712
|
+
const levelName = save.level.mapname ?? "unknown";
|
|
2713
|
+
const level = buildLevelState(save.level);
|
|
2714
|
+
const playtimeSeconds = defaultPlaytimeSeconds ?? level.timeSeconds;
|
|
2715
|
+
return {
|
|
2716
|
+
version: SAVE_FORMAT_VERSION,
|
|
2717
|
+
timestamp,
|
|
2718
|
+
map: levelName,
|
|
2719
|
+
difficulty: defaultDifficulty,
|
|
2720
|
+
playtimeSeconds,
|
|
2721
|
+
gameState: { ...options.gameState ?? {}, rereleaseVersion: save.saveVersion },
|
|
2722
|
+
level,
|
|
2723
|
+
rng: rngState ? { mt: { index: rngState.mt.index, state: [...rngState.mt.state] } } : new RandomGenerator().getState(),
|
|
2724
|
+
entities: buildEntitySnapshot(save.entities, level.timeSeconds, save.level.maxentities ?? void 0),
|
|
2725
|
+
cvars: [],
|
|
2726
|
+
configstrings: [...configstrings]
|
|
2727
|
+
};
|
|
2728
|
+
}
|
|
2729
|
+
function convertRereleaseSaveToGameSave(save, options = {}) {
|
|
2730
|
+
if ("game" in save) {
|
|
2731
|
+
throw new Error("Game-wide rerelease saves are not currently supported for conversion");
|
|
2732
|
+
}
|
|
2733
|
+
return convertRereleaseLevelToGameSave(save, options);
|
|
2734
|
+
}
|
|
2735
|
+
function convertGameSaveToRereleaseLevel(save) {
|
|
2736
|
+
const active = new Set(save.entities.pool.activeOrder);
|
|
2737
|
+
const entities = /* @__PURE__ */ new Map();
|
|
2738
|
+
for (const entity of save.entities.entities) {
|
|
2739
|
+
if (!active.has(entity.index)) {
|
|
2740
|
+
continue;
|
|
2741
|
+
}
|
|
2742
|
+
const fields = { inuse: true };
|
|
2743
|
+
for (const [name, value] of Object.entries(entity.fields)) {
|
|
2744
|
+
if (value === void 0) {
|
|
2745
|
+
continue;
|
|
2746
|
+
}
|
|
2747
|
+
fields[name] = value;
|
|
2748
|
+
}
|
|
2749
|
+
entities.set(entity.index, fields);
|
|
2750
|
+
}
|
|
2751
|
+
return {
|
|
2752
|
+
saveVersion: save.version,
|
|
2753
|
+
level: {
|
|
2754
|
+
mapname: save.map,
|
|
2755
|
+
time: save.level.timeSeconds,
|
|
2756
|
+
framenum: save.level.frameNumber,
|
|
2757
|
+
frametime: save.level.deltaSeconds
|
|
2758
|
+
},
|
|
2759
|
+
entities
|
|
2760
|
+
};
|
|
2761
|
+
}
|
|
2762
|
+
function serializeRereleaseSave(save) {
|
|
2763
|
+
if ("game" in save) {
|
|
2764
|
+
return { save_version: save.saveVersion, game: save.game, clients: save.clients };
|
|
2765
|
+
}
|
|
2766
|
+
const entities = {};
|
|
2767
|
+
for (const [index, entity] of save.entities.entries()) {
|
|
2768
|
+
entities[index.toString(10)] = entity;
|
|
2769
|
+
}
|
|
2770
|
+
return { save_version: save.saveVersion, level: save.level, entities };
|
|
2771
|
+
}
|
|
2628
2772
|
|
|
2629
2773
|
// src/save/storage.ts
|
|
2630
2774
|
var TEXT_ENCODER_CTOR = globalThis.TextEncoder;
|
|
@@ -3594,6 +3738,9 @@ export {
|
|
|
3594
3738
|
clampAmmoCounts,
|
|
3595
3739
|
classifyRange,
|
|
3596
3740
|
clearExpiredPowerups,
|
|
3741
|
+
convertGameSaveToRereleaseLevel,
|
|
3742
|
+
convertRereleaseLevelToGameSave,
|
|
3743
|
+
convertRereleaseSaveToGameSave,
|
|
3597
3744
|
createAmmoInventory,
|
|
3598
3745
|
createBaseAmmoCaps,
|
|
3599
3746
|
createDefaultSpawnRegistry,
|
|
@@ -3622,6 +3769,7 @@ export {
|
|
|
3622
3769
|
rangeTo,
|
|
3623
3770
|
registerDefaultSpawns,
|
|
3624
3771
|
selectWeapon,
|
|
3772
|
+
serializeRereleaseSave,
|
|
3625
3773
|
setMovedir,
|
|
3626
3774
|
spawnEntitiesFromText,
|
|
3627
3775
|
spawnEntityFromDictionary,
|