forked from phenom/healer-man
Release Healer Man 0.1.21
This commit is contained in:
1 parent
699fc858c9
commit
f6f2375145
210 files changed
+976039
-6247
No files matched your search
@@ -4,12 +4,15 @@ const PLAYER_TIMEOUT_MS = 15_000;
|
||||
const ROOM_TIMEOUT_MS = 30 * 60_000;
|
||||
const MAX_EVENTS = 256;
|
||||
const MAX_BATCH_EVENTS = 48;
|
||||
const MAX_WORLD_BYTES = 4 * 1024 * 1024;
|
||||
const ALLOWED_EVENT_KINDS = new Set([
|
||||
"damage",
|
||||
"healing",
|
||||
"resurrection",
|
||||
"loot",
|
||||
"portal",
|
||||
"interact",
|
||||
"party-teleport",
|
||||
]);
|
||||
const ALLOWED_SCHOOLS = new Set([
|
||||
"physical",
|
||||
@@ -43,6 +46,23 @@ function jsonClone(value, fallback = null) {
|
||||
}
|
||||
}
|
||||
|
||||
function boundedWorldClone(value) {
|
||||
let serialized;
|
||||
try {
|
||||
serialized = JSON.stringify(value);
|
||||
} catch {
|
||||
throw new GameDatabaseError("Shared world state must be JSON serializable.", 400, "invalid_world_state");
|
||||
}
|
||||
if (!serialized || Buffer.byteLength(serialized, "utf8") > MAX_WORLD_BYTES) {
|
||||
throw new GameDatabaseError("Shared world state exceeds the 4 MiB activity limit.", 413, "world_state_too_large");
|
||||
}
|
||||
const clone = JSON.parse(serialized);
|
||||
if (Array.isArray(clone.encounters) && clone.encounters.length > 128) {
|
||||
throw new GameDatabaseError("Shared world state has too many encounter snapshots.", 400, "invalid_world_state");
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
function requireActivity(account, snapshot) {
|
||||
const group = snapshot?.group;
|
||||
const activity = group?.activity;
|
||||
@@ -90,6 +110,7 @@ function sanitizeEvent(input, accountId, leaderAccountId) {
|
||||
if (!targetActorId && kind !== "portal") return null;
|
||||
const sourceActorId = boundedString(input?.sourceActorId);
|
||||
const localPlayerActorId = `online-player:${accountId}`;
|
||||
if (kind === "party-teleport" && accountId !== leaderAccountId) return null;
|
||||
// Non-leaders may submit only their own player actions. Enemy and AI events
|
||||
// are produced by the activity authority and cannot be forged by members.
|
||||
if (accountId !== leaderAccountId && sourceActorId !== localPlayerActorId) return null;
|
||||
@@ -105,6 +126,7 @@ function sanitizeEvent(input, accountId, leaderAccountId) {
|
||||
effectiveAmount: Math.max(0, Math.min(1_000_000_000, finite(input?.effectiveAmount))),
|
||||
critical: input?.critical === true,
|
||||
occurredAt: Math.max(0, Math.trunc(finite(input?.occurredAt, Date.now()))),
|
||||
...(kind === "party-teleport" ? { position: vector3(input?.position) } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -154,7 +176,7 @@ export function createOnlineSessionManager() {
|
||||
throw new GameDatabaseError("Shared world state must be an object.", 400, "invalid_world_state");
|
||||
}
|
||||
room.world = {
|
||||
...jsonClone(input.world, {}),
|
||||
...boundedWorldClone(input.world),
|
||||
publishedAt: now,
|
||||
publishedBy: account.id,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user