mirror of
https://github.com/sortedcord/omnia.git
synced 2026-07-22 03:52:48 +05:30
refactor: Serializers include available location attributes
This commit is contained in:
@@ -72,6 +72,7 @@ export class ScenarioLoader {
|
||||
}
|
||||
|
||||
// Save location record linked to the world instance
|
||||
world.addLocation(location);
|
||||
this.coreRepo.saveLocation(location, world.id);
|
||||
}
|
||||
}
|
||||
@@ -102,6 +103,7 @@ export class ScenarioLoader {
|
||||
}
|
||||
|
||||
// Save entity record linked to the world instance
|
||||
world.addEntity(entity);
|
||||
this.coreRepo.saveEntity(entity, world.id);
|
||||
|
||||
// Seed initial memory buffer history
|
||||
|
||||
@@ -84,6 +84,21 @@ describe("Talking Room Demo Scenario Test (Tier 1)", () => {
|
||||
expect(beta!.locationId).toBe("white-room");
|
||||
expect(beta!.aliases.get(alphaId)).toBe("the person in the Alpha jumpsuit");
|
||||
|
||||
// Verify subjective world state serializes the location attributes (epistemic inclusion)
|
||||
const { serializeSubjectiveWorldState } = await import("@omnia/core");
|
||||
const subjectiveState = serializeSubjectiveWorldState(world!, alphaId);
|
||||
expect(subjectiveState).toContain("You are at location: white-room");
|
||||
expect(subjectiveState).toContain("Location attributes:");
|
||||
expect(subjectiveState).toContain("description: A pristine, featureless room");
|
||||
expect(subjectiveState).toContain("lighting: Bright, uniform illumination");
|
||||
|
||||
// Verify objective world state serializes locations (physics awareness)
|
||||
const { serializeObjectiveWorldState } = await import("@omnia/core");
|
||||
const objectiveState = serializeObjectiveWorldState(world!);
|
||||
expect(objectiveState).toContain("Locations:");
|
||||
expect(objectiveState).toContain("- Location [ID: white-room]:");
|
||||
expect(objectiveState).toContain("description: A pristine, featureless room");
|
||||
|
||||
// 7. Assert initial pre-seeded memories
|
||||
const alphaMemories = bufferRepo.listForOwner(alphaId);
|
||||
expect(alphaMemories).toHaveLength(1);
|
||||
|
||||
@@ -4,6 +4,8 @@ import { AttributableObject, AttributeVisibility } from "./attribute.js";
|
||||
import { Entity } from "./entity.js";
|
||||
import { WorldState } from "./world.js";
|
||||
|
||||
class GenericObject extends AttributableObject {}
|
||||
|
||||
export class SQLiteRepository {
|
||||
private db: Database.Database;
|
||||
|
||||
@@ -195,6 +197,9 @@ export class SQLiteRepository {
|
||||
for (const entity of worldState.entities.values()) {
|
||||
this.saveEntity(entity, worldState.id);
|
||||
}
|
||||
for (const location of worldState.locations.values()) {
|
||||
this.saveLocation(location, worldState.id);
|
||||
}
|
||||
});
|
||||
saveWorldTx();
|
||||
}
|
||||
@@ -288,6 +293,25 @@ export class SQLiteRepository {
|
||||
const worldState = new WorldState(id, startTime);
|
||||
this.reconstituteAttributes(worldState);
|
||||
|
||||
// Reconstitute all locations belonging to this world
|
||||
const locationRows = this.db
|
||||
.prepare(
|
||||
`
|
||||
SELECT id, location_id, connections_json FROM objects WHERE type = 'location' AND world_id = ?
|
||||
`,
|
||||
)
|
||||
.all(id) as { id: string; location_id: string | null; connections_json: string | null }[];
|
||||
|
||||
for (const row of locationRows) {
|
||||
const loc = new GenericObject(row.id);
|
||||
(loc as { parentId?: string | null }).parentId = row.location_id;
|
||||
if (row.connections_json) {
|
||||
(loc as { connections?: unknown[] }).connections = JSON.parse(row.connections_json);
|
||||
}
|
||||
this.reconstituteAttributes(loc);
|
||||
worldState.addLocation(loc);
|
||||
}
|
||||
|
||||
// Reconstitute all entities belonging to this world
|
||||
const entityRows = this.db
|
||||
.prepare(
|
||||
|
||||
@@ -8,6 +8,7 @@ export class WorldState extends AttributableObject {
|
||||
* Universe's current state (distinct from how it started)
|
||||
*/
|
||||
readonly entities: Map<string, Entity> = new Map();
|
||||
readonly locations: Map<string, AttributableObject> = new Map();
|
||||
readonly clock: WorldClock;
|
||||
|
||||
constructor(id?: string, startTime?: Date) {
|
||||
@@ -27,6 +28,19 @@ export class WorldState extends AttributableObject {
|
||||
getEntity(id: string): Entity | undefined {
|
||||
return this.entities.get(id);
|
||||
}
|
||||
|
||||
addLocation(location: AttributableObject): void {
|
||||
if (this.locations.has(location.id)) {
|
||||
throw new Error(
|
||||
`Location with ID ${location.id} already exists in the world`,
|
||||
);
|
||||
}
|
||||
this.locations.set(location.id, location);
|
||||
}
|
||||
|
||||
getLocation(id: string): AttributableObject | undefined {
|
||||
return this.locations.get(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,6 +57,45 @@ export function serializeObjectiveWorldState(worldState: WorldState): string {
|
||||
lines.push(worldAttrsStr.split("\n").map(l => " " + l).join("\n"));
|
||||
}
|
||||
|
||||
// Serialize locations and their attributes/portals
|
||||
lines.push("Locations:");
|
||||
if (worldState.locations.size > 0) {
|
||||
for (const loc of worldState.locations.values()) {
|
||||
lines.push(` - Location [ID: ${loc.id}]:`);
|
||||
|
||||
const parentId = (loc as { parentId?: string | null }).parentId;
|
||||
if (parentId) {
|
||||
lines.push(` * Parent Location ID: ${parentId}`);
|
||||
}
|
||||
|
||||
if (loc.attributes.size > 0) {
|
||||
const locAttrsStr = serializeAttributes(Array.from(loc.attributes.values()));
|
||||
lines.push(locAttrsStr.split("\n").map(l => " " + l).join("\n"));
|
||||
} else {
|
||||
lines.push(" * (No attributes)");
|
||||
}
|
||||
|
||||
const connections = (loc as { connections?: unknown[] }).connections as {
|
||||
targetId: string;
|
||||
portalName?: string;
|
||||
portalStateDescriptor?: string;
|
||||
visionProp: number;
|
||||
soundProp: number;
|
||||
bidirectional: boolean;
|
||||
}[] | undefined;
|
||||
|
||||
if (connections && connections.length > 0) {
|
||||
lines.push(" * Connections:");
|
||||
for (const conn of connections) {
|
||||
const portalStr = conn.portalName ? ` via ${conn.portalName} (${conn.portalStateDescriptor || "normal"})` : "";
|
||||
lines.push(` -> To: ${conn.targetId}${portalStr} (Vision: ${conn.visionProp}, Sound: ${conn.soundProp})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lines.push(" (No locations)");
|
||||
}
|
||||
|
||||
// Serialize entities and their attributes
|
||||
lines.push("Entities:");
|
||||
if (worldState.entities.size > 0) {
|
||||
@@ -129,6 +182,14 @@ export function serializeSubjectiveWorldState(
|
||||
lines.push("What you perceive around you:");
|
||||
if (viewer.locationId) {
|
||||
lines.push(` You are at location: ${viewer.locationId}`);
|
||||
const location = worldState.getLocation(viewer.locationId);
|
||||
if (location) {
|
||||
const locVisible = location.getVisibleAttributesFor(viewerId);
|
||||
if (locVisible.length > 0) {
|
||||
lines.push(" Location attributes:");
|
||||
lines.push(serializeVisibleAttributes(locVisible).split("\n").map((l) => " " + l).join("\n"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lines.push(" You are not located anywhere in particular.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user