@jgengine/core 0.6.0 → 0.8.0
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/CHANGELOG.md +214 -2
- package/README.md +2 -0
- package/dist/ai/crowd.d.ts +36 -0
- package/dist/ai/crowd.js +213 -0
- package/dist/ai/jobBoard.d.ts +49 -0
- package/dist/ai/jobBoard.js +155 -0
- package/dist/ai/spawnDirector.d.ts +61 -0
- package/dist/ai/spawnDirector.js +162 -0
- package/dist/ai/threat.d.ts +25 -0
- package/dist/ai/threat.js +67 -0
- package/dist/anim/easing.d.ts +14 -0
- package/dist/anim/easing.js +55 -0
- package/dist/audio/audioFalloff.d.ts +38 -0
- package/dist/audio/audioFalloff.js +32 -0
- package/dist/behaviour/behaviour.d.ts +136 -0
- package/dist/behaviour/behaviour.js +388 -0
- package/dist/board/laneBoard.d.ts +63 -0
- package/dist/board/laneBoard.js +114 -0
- package/dist/board/timelineBoard.d.ts +36 -0
- package/dist/board/timelineBoard.js +70 -0
- package/dist/cards/cardPile.d.ts +64 -0
- package/dist/cards/cardPile.js +175 -0
- package/dist/cards/modifierPipeline.d.ts +33 -0
- package/dist/cards/modifierPipeline.js +48 -0
- package/dist/combat/abilityKit.d.ts +47 -0
- package/dist/combat/abilityKit.js +139 -0
- package/dist/combat/animationState.d.ts +47 -0
- package/dist/combat/animationState.js +101 -0
- package/dist/combat/attackTags.d.ts +14 -0
- package/dist/combat/attackTags.js +26 -0
- package/dist/combat/breakMeters.d.ts +32 -0
- package/dist/combat/breakMeters.js +51 -0
- package/dist/combat/comboString.d.ts +35 -0
- package/dist/combat/comboString.js +59 -0
- package/dist/combat/death.d.ts +8 -0
- package/dist/combat/death.js +5 -2
- package/dist/combat/defensiveWindow.d.ts +34 -0
- package/dist/combat/defensiveWindow.js +66 -0
- package/dist/combat/downed.d.ts +35 -0
- package/dist/combat/downed.js +104 -0
- package/dist/combat/effects.d.ts +12 -1
- package/dist/combat/effects.js +31 -19
- package/dist/combat/hitReaction.d.ts +23 -0
- package/dist/combat/hitReaction.js +20 -0
- package/dist/combat/projectiles.d.ts +42 -5
- package/dist/combat/projectiles.js +98 -12
- package/dist/combat/resistance.d.ts +13 -0
- package/dist/combat/resistance.js +46 -0
- package/dist/combat/telegraph.d.ts +31 -0
- package/dist/combat/telegraph.js +51 -0
- package/dist/commands/commandRegistry.d.ts +1 -1
- package/dist/commands/commandRegistry.js +2 -1
- package/dist/crafting/crop.d.ts +59 -0
- package/dist/crafting/crop.js +181 -0
- package/dist/crafting/production.d.ts +64 -0
- package/dist/crafting/production.js +130 -0
- package/dist/crafting/recipe.d.ts +62 -0
- package/dist/crafting/recipe.js +101 -0
- package/dist/data/dataSource.d.ts +26 -0
- package/dist/data/dataSource.js +93 -0
- package/dist/data/devProxy.d.ts +11 -0
- package/dist/data/devProxy.js +38 -0
- package/dist/data/fetchJson.d.ts +20 -0
- package/dist/data/fetchJson.js +43 -0
- package/dist/data/jsonDataSource.d.ts +4 -0
- package/dist/data/jsonDataSource.js +6 -0
- package/dist/devtools/devtools.d.ts +157 -0
- package/dist/devtools/devtools.js +484 -0
- package/dist/devtools/transformTunables.d.ts +14 -0
- package/dist/devtools/transformTunables.js +38 -0
- package/dist/economy/sharedWallet.d.ts +28 -0
- package/dist/economy/sharedWallet.js +62 -0
- package/dist/economy/techTree.d.ts +40 -0
- package/dist/economy/techTree.js +66 -0
- package/dist/game/chat.d.ts +66 -0
- package/dist/game/chat.js +165 -0
- package/dist/game/cosmetics.d.ts +25 -0
- package/dist/game/cosmetics.js +51 -0
- package/dist/game/defineGame.d.ts +10 -2
- package/dist/game/defineGame.js +2 -1
- package/dist/game/events.d.ts +87 -0
- package/dist/game/levelSequence.d.ts +44 -0
- package/dist/game/levelSequence.js +78 -0
- package/dist/game/lootFilter.d.ts +33 -0
- package/dist/game/lootFilter.js +48 -0
- package/dist/game/ping.d.ts +67 -0
- package/dist/game/ping.js +86 -0
- package/dist/game/playableGame.d.ts +516 -8
- package/dist/game/playableGame.js +6 -1
- package/dist/game/progression.d.ts +1 -0
- package/dist/game/progression.js +23 -2
- package/dist/game/race.d.ts +100 -0
- package/dist/game/race.js +236 -0
- package/dist/game/runDraft.d.ts +34 -0
- package/dist/game/runDraft.js +97 -0
- package/dist/game/social.d.ts +69 -0
- package/dist/game/social.js +138 -0
- package/dist/game/spawnPoints.d.ts +19 -0
- package/dist/game/spawnPoints.js +23 -0
- package/dist/game/worldItem.d.ts +95 -0
- package/dist/game/worldItem.js +138 -0
- package/dist/input/actionBindings.d.ts +10 -0
- package/dist/input/actionBindings.js +14 -0
- package/dist/input/axisInput.d.ts +43 -0
- package/dist/input/axisInput.js +70 -0
- package/dist/input/gestureSurface.d.ts +31 -0
- package/dist/input/gestureSurface.js +120 -0
- package/dist/input/pointer.d.ts +69 -0
- package/dist/input/pointer.js +65 -0
- package/dist/input/touchScheme.d.ts +83 -0
- package/dist/input/touchScheme.js +115 -0
- package/dist/interaction/contextMenu.d.ts +30 -0
- package/dist/interaction/contextMenu.js +22 -0
- package/dist/interaction/qte.d.ts +20 -0
- package/dist/interaction/qte.js +24 -0
- package/dist/interaction/skillCheck.d.ts +20 -0
- package/dist/interaction/skillCheck.js +26 -0
- package/dist/inventory/shapedGrid.d.ts +56 -0
- package/dist/inventory/shapedGrid.js +176 -0
- package/dist/inventory/storageTier.d.ts +52 -0
- package/dist/inventory/storageTier.js +77 -0
- package/dist/item/affix.d.ts +54 -0
- package/dist/item/affix.js +115 -0
- package/dist/item/durability.d.ts +51 -0
- package/dist/item/durability.js +78 -0
- package/dist/item/modularItem.d.ts +46 -0
- package/dist/item/modularItem.js +75 -0
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +71 -1
- package/dist/movement/dash.d.ts +37 -0
- package/dist/movement/dash.js +65 -0
- package/dist/movement/movementModel.d.ts +36 -3
- package/dist/movement/movementModel.js +81 -5
- package/dist/movement/voxelController.d.ts +61 -0
- package/dist/movement/voxelController.js +229 -0
- package/dist/multiplayer/chatContract.d.ts +42 -0
- package/dist/multiplayer/chatContract.js +57 -0
- package/dist/multiplayer/combatSnapshot.d.ts +45 -0
- package/dist/multiplayer/combatSnapshot.js +89 -0
- package/dist/multiplayer/identity.d.ts +13 -0
- package/dist/multiplayer/identity.js +20 -0
- package/dist/multiplayer/lagCompensation.d.ts +43 -0
- package/dist/multiplayer/lagCompensation.js +154 -0
- package/dist/multiplayer/matchmaking.d.ts +33 -0
- package/dist/multiplayer/matchmaking.js +60 -0
- package/dist/multiplayer/poseSyncGate.d.ts +1 -0
- package/dist/multiplayer/poseSyncGate.js +13 -1
- package/dist/multiplayer/presenceModel.d.ts +3 -0
- package/dist/multiplayer/presenceModel.js +15 -1
- package/dist/multiplayer/simultaneousCommit.d.ts +34 -0
- package/dist/multiplayer/simultaneousCommit.js +53 -0
- package/dist/multiplayer/voiceContract.d.ts +44 -0
- package/dist/multiplayer/voiceContract.js +108 -0
- package/dist/nav/navConstrain.d.ts +14 -0
- package/dist/nav/navConstrain.js +26 -0
- package/dist/nav/navFromEnvironment.d.ts +11 -0
- package/dist/nav/navFromEnvironment.js +16 -0
- package/dist/nav/navGrid.d.ts +56 -0
- package/dist/nav/navGrid.js +265 -0
- package/dist/nav/pathFollow.d.ts +31 -0
- package/dist/nav/pathFollow.js +69 -0
- package/dist/physics/ballisticSweep.d.ts +18 -0
- package/dist/physics/ballisticSweep.js +49 -0
- package/dist/physics/buoyancy.d.ts +49 -0
- package/dist/physics/buoyancy.js +112 -0
- package/dist/physics/carryable.d.ts +46 -0
- package/dist/physics/carryable.js +110 -0
- package/dist/physics/damageZones.d.ts +56 -0
- package/dist/physics/damageZones.js +107 -0
- package/dist/physics/forceVolume.d.ts +48 -0
- package/dist/physics/forceVolume.js +119 -0
- package/dist/physics/physicsWorld.d.ts +124 -2
- package/dist/physics/physicsWorld.js +493 -41
- package/dist/physics/ragdoll.d.ts +49 -0
- package/dist/physics/ragdoll.js +103 -0
- package/dist/physics/spatialGrid.d.ts +41 -0
- package/dist/physics/spatialGrid.js +143 -0
- package/dist/physics/structure.d.ts +83 -0
- package/dist/physics/structure.js +0 -0
- package/dist/physics/traversal.d.ts +75 -0
- package/dist/physics/traversal.js +138 -0
- package/dist/physics/vehicleBody.d.ts +99 -0
- package/dist/physics/vehicleBody.js +233 -0
- package/dist/puzzle/cellGrid.d.ts +26 -0
- package/dist/puzzle/cellGrid.js +110 -0
- package/dist/puzzle/fallingPiece.d.ts +24 -0
- package/dist/puzzle/fallingPiece.js +51 -0
- package/dist/random/nameGen.d.ts +18 -0
- package/dist/random/nameGen.js +35 -0
- package/dist/random/rng.d.ts +2 -0
- package/dist/random/rng.js +23 -0
- package/dist/runtime/adapter.d.ts +35 -0
- package/dist/runtime/adapter.js +37 -1
- package/dist/runtime/cameraDirector.d.ts +10 -0
- package/dist/runtime/cameraDirector.js +25 -0
- package/dist/runtime/gameContext.d.ts +107 -3
- package/dist/runtime/gameContext.js +253 -7
- package/dist/runtime/hostPersistence.d.ts +39 -0
- package/dist/runtime/hostPersistence.js +54 -0
- package/dist/runtime/inputSnapshot.d.ts +7 -0
- package/dist/runtime/inputSnapshot.js +12 -0
- package/dist/runtime/motionIntents.d.ts +25 -0
- package/dist/runtime/motionIntents.js +25 -0
- package/dist/runtime/persistenceScope.d.ts +32 -0
- package/dist/runtime/persistenceScope.js +64 -0
- package/dist/runtime/transport.d.ts +32 -0
- package/dist/scene/autoTarget.d.ts +15 -0
- package/dist/scene/autoTarget.js +54 -0
- package/dist/scene/behaviors.d.ts +13 -1
- package/dist/scene/behaviors.js +3 -0
- package/dist/scene/captureCheck.d.ts +7 -0
- package/dist/scene/captureCheck.js +11 -0
- package/dist/scene/entityStore.d.ts +9 -1
- package/dist/scene/entityStore.js +25 -2
- package/dist/scene/form.d.ts +40 -0
- package/dist/scene/form.js +56 -0
- package/dist/scene/mount.d.ts +62 -0
- package/dist/scene/mount.js +107 -0
- package/dist/scene/movementSpeed.d.ts +35 -0
- package/dist/scene/movementSpeed.js +20 -0
- package/dist/scene/objectQuery.d.ts +18 -0
- package/dist/scene/objectQuery.js +108 -0
- package/dist/scene/objectStore.d.ts +11 -0
- package/dist/scene/objectStore.js +109 -4
- package/dist/scene/paintLayer.d.ts +15 -0
- package/dist/scene/paintLayer.js +53 -0
- package/dist/scene/possession.d.ts +30 -0
- package/dist/scene/possession.js +51 -0
- package/dist/scene/roster.d.ts +25 -0
- package/dist/scene/roster.js +57 -0
- package/dist/scene/selection.d.ts +30 -0
- package/dist/scene/selection.js +38 -0
- package/dist/scene/spatial.d.ts +21 -0
- package/dist/scene/spatial.js +63 -1
- package/dist/scene/stationClaim.d.ts +43 -0
- package/dist/scene/stationClaim.js +109 -0
- package/dist/sensor/concealment.d.ts +21 -0
- package/dist/sensor/concealment.js +63 -0
- package/dist/sensor/freezeMonitor.d.ts +17 -0
- package/dist/sensor/freezeMonitor.js +35 -0
- package/dist/sensor/frustumSensor.d.ts +60 -0
- package/dist/sensor/frustumSensor.js +104 -0
- package/dist/sensor/hiddenStateProbe.d.ts +31 -0
- package/dist/sensor/hiddenStateProbe.js +40 -0
- package/dist/sensor/recordingBuffer.d.ts +29 -0
- package/dist/sensor/recordingBuffer.js +61 -0
- package/dist/sensor/revealQuery.d.ts +22 -0
- package/dist/sensor/revealQuery.js +36 -0
- package/dist/session/contestedChannel.d.ts +36 -0
- package/dist/session/contestedChannel.js +100 -0
- package/dist/session/extraction.d.ts +54 -0
- package/dist/session/extraction.js +108 -0
- package/dist/session/ring.d.ts +36 -0
- package/dist/session/ring.js +88 -0
- package/dist/session/roles.d.ts +6 -0
- package/dist/session/roles.js +32 -0
- package/dist/session/roundState.d.ts +79 -0
- package/dist/session/roundState.js +158 -0
- package/dist/stats/accumulatorMeter.d.ts +31 -0
- package/dist/stats/accumulatorMeter.js +81 -0
- package/dist/stats/eventMeter.d.ts +34 -0
- package/dist/stats/eventMeter.js +76 -0
- package/dist/stats/rollCheck.d.ts +15 -0
- package/dist/stats/rollCheck.js +15 -0
- package/dist/survival/decayMeter.d.ts +59 -0
- package/dist/survival/decayMeter.js +95 -0
- package/dist/survival/moodle.d.ts +48 -0
- package/dist/survival/moodle.js +91 -0
- package/dist/survival/regionHealth.d.ts +72 -0
- package/dist/survival/regionHealth.js +129 -0
- package/dist/tactics/fallingGrid.d.ts +62 -0
- package/dist/tactics/fallingGrid.js +158 -0
- package/dist/tactics/predictiveQuery.d.ts +34 -0
- package/dist/tactics/predictiveQuery.js +44 -0
- package/dist/tactics/snapshot.d.ts +18 -0
- package/dist/tactics/snapshot.js +65 -0
- package/dist/tactics/surface.d.ts +52 -0
- package/dist/tactics/surface.js +135 -0
- package/dist/tactics/tacticalGrid.d.ts +68 -0
- package/dist/tactics/tacticalGrid.js +261 -0
- package/dist/time/beatClock.d.ts +40 -0
- package/dist/time/beatClock.js +73 -0
- package/dist/time/simClock.d.ts +25 -1
- package/dist/time/simClock.js +28 -3
- package/dist/turn/commit.d.ts +27 -0
- package/dist/turn/commit.js +72 -0
- package/dist/turn/intent.d.ts +14 -0
- package/dist/turn/intent.js +29 -0
- package/dist/turn/turnLoop.d.ts +60 -0
- package/dist/turn/turnLoop.js +223 -0
- package/dist/world/buildPermissions.d.ts +47 -0
- package/dist/world/buildPermissions.js +134 -0
- package/dist/world/carve.d.ts +105 -0
- package/dist/world/carve.js +175 -0
- package/dist/world/connectors.d.ts +40 -0
- package/dist/world/connectors.js +67 -0
- package/dist/world/envField.d.ts +71 -0
- package/dist/world/envField.js +96 -0
- package/dist/world/environmentSummary.d.ts +53 -0
- package/dist/world/environmentSummary.js +129 -0
- package/dist/world/features.d.ts +87 -6
- package/dist/world/features.js +52 -2
- package/dist/world/fog.d.ts +40 -0
- package/dist/world/fog.js +137 -0
- package/dist/world/gridInstances.d.ts +13 -0
- package/dist/world/gridInstances.js +22 -0
- package/dist/world/markers.d.ts +52 -0
- package/dist/world/markers.js +96 -0
- package/dist/world/minimap.d.ts +42 -0
- package/dist/world/minimap.js +72 -0
- package/dist/world/placedStructureStore.d.ts +39 -0
- package/dist/world/placedStructureStore.js +95 -0
- package/dist/world/placementController.d.ts +69 -0
- package/dist/world/placementController.js +153 -0
- package/dist/world/realm.d.ts +61 -0
- package/dist/world/realm.js +66 -0
- package/dist/world/support.d.ts +27 -0
- package/dist/world/support.js +75 -0
- package/dist/world/terraform.d.ts +54 -0
- package/dist/world/terraform.js +186 -0
- package/dist/world/terrain.d.ts +23 -1
- package/dist/world/terrain.js +64 -1
- package/dist/world/voxelField.d.ts +54 -0
- package/dist/world/voxelField.js +241 -0
- package/dist/world/walls.d.ts +61 -0
- package/dist/world/walls.js +221 -0
- package/dist/world/weather.d.ts +92 -0
- package/dist/world/weather.js +169 -0
- package/llms.txt +4102 -0
- package/package.json +3 -2
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
export interface Checkpoint {
|
|
2
|
+
id: string;
|
|
3
|
+
center: readonly [number, number, number];
|
|
4
|
+
half: readonly [number, number, number];
|
|
5
|
+
}
|
|
6
|
+
export interface RaceTrackConfig {
|
|
7
|
+
checkpoints: readonly Checkpoint[];
|
|
8
|
+
laps?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface RaceTrack {
|
|
11
|
+
readonly checkpoints: readonly Checkpoint[];
|
|
12
|
+
readonly laps: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A race track is an ordered ring of checkpoint trigger volumes plus a lap count. The final checkpoint
|
|
16
|
+
* is the lap/finish line: a racer completes a lap by passing all checkpoints in order and hitting the
|
|
17
|
+
* last one.
|
|
18
|
+
*/
|
|
19
|
+
export declare function raceTrack(config: RaceTrackConfig): RaceTrack;
|
|
20
|
+
export interface RacerProgress {
|
|
21
|
+
racerId: string;
|
|
22
|
+
lap: number;
|
|
23
|
+
nextCheckpoint: number;
|
|
24
|
+
lastCheckpoint: number;
|
|
25
|
+
progress: number;
|
|
26
|
+
position: number;
|
|
27
|
+
finished: boolean;
|
|
28
|
+
finishTime: number | null;
|
|
29
|
+
eliminated: boolean;
|
|
30
|
+
splits: readonly number[];
|
|
31
|
+
}
|
|
32
|
+
export type RaceEvent = {
|
|
33
|
+
type: "checkpoint.hit";
|
|
34
|
+
racerId: string;
|
|
35
|
+
checkpoint: number;
|
|
36
|
+
lap: number;
|
|
37
|
+
time: number;
|
|
38
|
+
} | {
|
|
39
|
+
type: "lap.completed";
|
|
40
|
+
racerId: string;
|
|
41
|
+
lap: number;
|
|
42
|
+
time: number;
|
|
43
|
+
} | {
|
|
44
|
+
type: "position.changed";
|
|
45
|
+
racerId: string;
|
|
46
|
+
position: number;
|
|
47
|
+
previous: number;
|
|
48
|
+
} | {
|
|
49
|
+
type: "race.finished";
|
|
50
|
+
ranking: readonly string[];
|
|
51
|
+
time: number;
|
|
52
|
+
};
|
|
53
|
+
export type RaceWinCondition = (standings: readonly RacerProgress[], track: RaceTrack) => readonly string[] | null;
|
|
54
|
+
/** Race ends when `count` racers have crossed the finish; ranking is the current standings order. */
|
|
55
|
+
export declare function firstPastPost(count?: number): RaceWinCondition;
|
|
56
|
+
/** Round-cut (Fall Guys): the first `k` finishers qualify; race resolves the moment `k` cross. */
|
|
57
|
+
export declare function topK(k: number): RaceWinCondition;
|
|
58
|
+
/** Every non-eliminated racer must finish. */
|
|
59
|
+
export declare function everyoneFinishes(): RaceWinCondition;
|
|
60
|
+
/** Destruction-derby last-man-standing: ends when at most one racer is left un-eliminated. */
|
|
61
|
+
export declare function lastStanding(): RaceWinCondition;
|
|
62
|
+
export interface RaceStateConfig {
|
|
63
|
+
track: RaceTrack;
|
|
64
|
+
win?: RaceWinCondition;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Race state machine (issue #87). Drive it each tick with `update(now, positions)` — `now` is game time
|
|
68
|
+
* (`ctx.time`), `positions` maps each racer to a world point tested against the ordered checkpoint
|
|
69
|
+
* volumes. It emits `checkpoint.hit` / `lap.completed` / `position.changed` / `race.finished`, keeps
|
|
70
|
+
* cumulative split times for PB deltas, resolves a pluggable win condition (first-past-post, round-cut,
|
|
71
|
+
* derby last-standing), and `resetToCheckpoint` hands back a respawn pose at the racer's last checkpoint.
|
|
72
|
+
* `removeRacer` drops a racer mid-race and `reset` returns the whole instance to its pre-race state for reuse.
|
|
73
|
+
*/
|
|
74
|
+
export declare class RaceState {
|
|
75
|
+
private readonly track;
|
|
76
|
+
private readonly win;
|
|
77
|
+
private readonly racers;
|
|
78
|
+
private readonly order;
|
|
79
|
+
private raceFinished;
|
|
80
|
+
private finalRanking;
|
|
81
|
+
constructor(config: RaceStateConfig);
|
|
82
|
+
addRacer(racerId: string, startTime?: number): void;
|
|
83
|
+
/** Removes a racer's progress/standing and renumbers the remaining field's positions; a no-op for an unknown id. */
|
|
84
|
+
removeRacer(racerId: string): void;
|
|
85
|
+
/** Clears all racer progress and finish state back to construction time; `track` and `win` are untouched, so the same instance can run another race. */
|
|
86
|
+
reset(): void;
|
|
87
|
+
eliminate(racerId: string): void;
|
|
88
|
+
get finished(): boolean;
|
|
89
|
+
get ranking(): readonly string[];
|
|
90
|
+
progressOf(racerId: string): RacerProgress | null;
|
|
91
|
+
private snapshot;
|
|
92
|
+
standings(): readonly RacerProgress[];
|
|
93
|
+
resetToCheckpoint(racerId: string): {
|
|
94
|
+
position: [number, number, number];
|
|
95
|
+
heading: number;
|
|
96
|
+
} | null;
|
|
97
|
+
private compare;
|
|
98
|
+
update(now: number, positions: Record<string, readonly [number, number, number]> | Map<string, readonly [number, number, number]>): readonly RaceEvent[];
|
|
99
|
+
}
|
|
100
|
+
export declare function createRaceState(config: RaceStateConfig): RaceState;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A race track is an ordered ring of checkpoint trigger volumes plus a lap count. The final checkpoint
|
|
3
|
+
* is the lap/finish line: a racer completes a lap by passing all checkpoints in order and hitting the
|
|
4
|
+
* last one.
|
|
5
|
+
*/
|
|
6
|
+
export function raceTrack(config) {
|
|
7
|
+
return { checkpoints: config.checkpoints, laps: Math.max(1, Math.floor(config.laps ?? 1)) };
|
|
8
|
+
}
|
|
9
|
+
function rankIds(standings) {
|
|
10
|
+
return standings.map((s) => s.racerId);
|
|
11
|
+
}
|
|
12
|
+
/** Race ends when `count` racers have crossed the finish; ranking is the current standings order. */
|
|
13
|
+
export function firstPastPost(count = 1) {
|
|
14
|
+
return (standings) => {
|
|
15
|
+
const finished = standings.filter((s) => s.finished).length;
|
|
16
|
+
return finished >= count ? rankIds(standings) : null;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** Round-cut (Fall Guys): the first `k` finishers qualify; race resolves the moment `k` cross. */
|
|
20
|
+
export function topK(k) {
|
|
21
|
+
return firstPastPost(k);
|
|
22
|
+
}
|
|
23
|
+
/** Every non-eliminated racer must finish. */
|
|
24
|
+
export function everyoneFinishes() {
|
|
25
|
+
return (standings) => {
|
|
26
|
+
const active = standings.filter((s) => !s.eliminated);
|
|
27
|
+
return active.length > 0 && active.every((s) => s.finished) ? rankIds(standings) : null;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Destruction-derby last-man-standing: ends when at most one racer is left un-eliminated. */
|
|
31
|
+
export function lastStanding() {
|
|
32
|
+
return (standings) => {
|
|
33
|
+
const alive = standings.filter((s) => !s.eliminated);
|
|
34
|
+
return alive.length <= 1 && standings.length > 1 ? rankIds(standings) : null;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function insideAabb(point, cp) {
|
|
38
|
+
return (Math.abs(point[0] - cp.center[0]) <= cp.half[0] &&
|
|
39
|
+
Math.abs(point[1] - cp.center[1]) <= cp.half[1] &&
|
|
40
|
+
Math.abs(point[2] - cp.center[2]) <= cp.half[2]);
|
|
41
|
+
}
|
|
42
|
+
function distanceToNext(point, cp) {
|
|
43
|
+
const dx = point[0] - cp.center[0];
|
|
44
|
+
const dz = point[2] - cp.center[2];
|
|
45
|
+
return Math.sqrt(dx * dx + dz * dz);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Race state machine (issue #87). Drive it each tick with `update(now, positions)` — `now` is game time
|
|
49
|
+
* (`ctx.time`), `positions` maps each racer to a world point tested against the ordered checkpoint
|
|
50
|
+
* volumes. It emits `checkpoint.hit` / `lap.completed` / `position.changed` / `race.finished`, keeps
|
|
51
|
+
* cumulative split times for PB deltas, resolves a pluggable win condition (first-past-post, round-cut,
|
|
52
|
+
* derby last-standing), and `resetToCheckpoint` hands back a respawn pose at the racer's last checkpoint.
|
|
53
|
+
* `removeRacer` drops a racer mid-race and `reset` returns the whole instance to its pre-race state for reuse.
|
|
54
|
+
*/
|
|
55
|
+
export class RaceState {
|
|
56
|
+
track;
|
|
57
|
+
win;
|
|
58
|
+
racers = new Map();
|
|
59
|
+
order = [];
|
|
60
|
+
raceFinished = false;
|
|
61
|
+
finalRanking = [];
|
|
62
|
+
constructor(config) {
|
|
63
|
+
this.track = config.track;
|
|
64
|
+
this.win = config.win ?? firstPastPost(1);
|
|
65
|
+
}
|
|
66
|
+
addRacer(racerId, startTime = 0) {
|
|
67
|
+
if (this.racers.has(racerId))
|
|
68
|
+
return;
|
|
69
|
+
this.racers.set(racerId, {
|
|
70
|
+
racerId,
|
|
71
|
+
lap: 1,
|
|
72
|
+
nextCheckpoint: 0,
|
|
73
|
+
lastCheckpoint: -1,
|
|
74
|
+
progress: 0,
|
|
75
|
+
position: this.order.length + 1,
|
|
76
|
+
finished: false,
|
|
77
|
+
finishTime: null,
|
|
78
|
+
eliminated: false,
|
|
79
|
+
startTime,
|
|
80
|
+
splits: [],
|
|
81
|
+
});
|
|
82
|
+
this.order.push(racerId);
|
|
83
|
+
}
|
|
84
|
+
/** Removes a racer's progress/standing and renumbers the remaining field's positions; a no-op for an unknown id. */
|
|
85
|
+
removeRacer(racerId) {
|
|
86
|
+
if (!this.racers.delete(racerId))
|
|
87
|
+
return;
|
|
88
|
+
const idx = this.order.indexOf(racerId);
|
|
89
|
+
if (idx >= 0)
|
|
90
|
+
this.order.splice(idx, 1);
|
|
91
|
+
const remaining = this.order.map((id) => this.racers.get(id)).sort((a, b) => this.compare(a, b, null));
|
|
92
|
+
remaining.forEach((r, i) => {
|
|
93
|
+
r.position = i + 1;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/** Clears all racer progress and finish state back to construction time; `track` and `win` are untouched, so the same instance can run another race. */
|
|
97
|
+
reset() {
|
|
98
|
+
this.racers.clear();
|
|
99
|
+
this.order.length = 0;
|
|
100
|
+
this.raceFinished = false;
|
|
101
|
+
this.finalRanking = [];
|
|
102
|
+
}
|
|
103
|
+
eliminate(racerId) {
|
|
104
|
+
const r = this.racers.get(racerId);
|
|
105
|
+
if (r !== undefined)
|
|
106
|
+
r.eliminated = true;
|
|
107
|
+
}
|
|
108
|
+
get finished() {
|
|
109
|
+
return this.raceFinished;
|
|
110
|
+
}
|
|
111
|
+
get ranking() {
|
|
112
|
+
return this.finalRanking;
|
|
113
|
+
}
|
|
114
|
+
progressOf(racerId) {
|
|
115
|
+
const r = this.racers.get(racerId);
|
|
116
|
+
return r === null || r === undefined ? null : this.snapshot(r);
|
|
117
|
+
}
|
|
118
|
+
snapshot(r) {
|
|
119
|
+
return {
|
|
120
|
+
racerId: r.racerId,
|
|
121
|
+
lap: r.lap,
|
|
122
|
+
nextCheckpoint: r.nextCheckpoint,
|
|
123
|
+
lastCheckpoint: r.lastCheckpoint,
|
|
124
|
+
progress: r.progress,
|
|
125
|
+
position: r.position,
|
|
126
|
+
finished: r.finished,
|
|
127
|
+
finishTime: r.finishTime,
|
|
128
|
+
eliminated: r.eliminated,
|
|
129
|
+
splits: [...r.splits],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
standings() {
|
|
133
|
+
return this.order
|
|
134
|
+
.map((id) => this.racers.get(id))
|
|
135
|
+
.slice()
|
|
136
|
+
.sort((a, b) => this.compare(a, b, null))
|
|
137
|
+
.map((r) => this.snapshot(r));
|
|
138
|
+
}
|
|
139
|
+
resetToCheckpoint(racerId) {
|
|
140
|
+
const r = this.racers.get(racerId);
|
|
141
|
+
if (r === undefined)
|
|
142
|
+
return null;
|
|
143
|
+
const cps = this.track.checkpoints;
|
|
144
|
+
const idx = r.lastCheckpoint >= 0 ? r.lastCheckpoint : 0;
|
|
145
|
+
const cp = cps[idx];
|
|
146
|
+
if (cp === undefined)
|
|
147
|
+
return null;
|
|
148
|
+
const next = cps[(idx + 1) % cps.length];
|
|
149
|
+
const heading = Math.atan2(next.center[0] - cp.center[0], next.center[2] - cp.center[2]);
|
|
150
|
+
return { position: [cp.center[0], cp.center[1], cp.center[2]], heading };
|
|
151
|
+
}
|
|
152
|
+
compare(a, b, positions) {
|
|
153
|
+
if (a.finished !== b.finished)
|
|
154
|
+
return a.finished ? -1 : 1;
|
|
155
|
+
if (a.finished && b.finished)
|
|
156
|
+
return (a.finishTime ?? 0) - (b.finishTime ?? 0);
|
|
157
|
+
if (a.eliminated !== b.eliminated)
|
|
158
|
+
return a.eliminated ? 1 : -1;
|
|
159
|
+
if (a.progress !== b.progress)
|
|
160
|
+
return b.progress - a.progress;
|
|
161
|
+
if (positions !== null) {
|
|
162
|
+
const pa = positions.get(a.racerId);
|
|
163
|
+
const pb = positions.get(b.racerId);
|
|
164
|
+
const cps = this.track.checkpoints;
|
|
165
|
+
if (pa !== undefined && pb !== undefined && cps.length > 0) {
|
|
166
|
+
const da = distanceToNext(pa, cps[a.nextCheckpoint]);
|
|
167
|
+
const db = distanceToNext(pb, cps[b.nextCheckpoint]);
|
|
168
|
+
if (da !== db)
|
|
169
|
+
return da - db;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return this.order.indexOf(a.racerId) - this.order.indexOf(b.racerId);
|
|
173
|
+
}
|
|
174
|
+
update(now, positions) {
|
|
175
|
+
const posMap = positions instanceof Map ? positions : new Map(Object.entries(positions));
|
|
176
|
+
const events = [];
|
|
177
|
+
const cps = this.track.checkpoints;
|
|
178
|
+
const count = cps.length;
|
|
179
|
+
if (count > 0) {
|
|
180
|
+
for (const id of this.order) {
|
|
181
|
+
const r = this.racers.get(id);
|
|
182
|
+
if (r.finished || r.eliminated)
|
|
183
|
+
continue;
|
|
184
|
+
const pos = posMap.get(id);
|
|
185
|
+
if (pos === undefined)
|
|
186
|
+
continue;
|
|
187
|
+
let guard = 0;
|
|
188
|
+
while (guard < count && insideAabb(pos, cps[r.nextCheckpoint])) {
|
|
189
|
+
guard += 1;
|
|
190
|
+
const hit = r.nextCheckpoint;
|
|
191
|
+
r.lastCheckpoint = hit;
|
|
192
|
+
r.progress += 1;
|
|
193
|
+
r.splits.push(now - r.startTime);
|
|
194
|
+
events.push({ type: "checkpoint.hit", racerId: id, checkpoint: hit, lap: r.lap, time: now });
|
|
195
|
+
if (hit === count - 1) {
|
|
196
|
+
events.push({ type: "lap.completed", racerId: id, lap: r.lap, time: now });
|
|
197
|
+
if (r.lap >= this.track.laps) {
|
|
198
|
+
r.finished = true;
|
|
199
|
+
r.finishTime = now;
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
r.lap += 1;
|
|
203
|
+
r.nextCheckpoint = 0;
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
r.nextCheckpoint = hit + 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const sorted = this.order
|
|
212
|
+
.map((id) => this.racers.get(id))
|
|
213
|
+
.slice()
|
|
214
|
+
.sort((a, b) => this.compare(a, b, posMap));
|
|
215
|
+
for (let i = 0; i < sorted.length; i += 1) {
|
|
216
|
+
const r = sorted[i];
|
|
217
|
+
const newPos = i + 1;
|
|
218
|
+
if (r.position !== newPos) {
|
|
219
|
+
events.push({ type: "position.changed", racerId: r.racerId, position: newPos, previous: r.position });
|
|
220
|
+
r.position = newPos;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (!this.raceFinished) {
|
|
224
|
+
const ranking = this.win(sorted.map((r) => this.snapshot(r)), this.track);
|
|
225
|
+
if (ranking !== null) {
|
|
226
|
+
this.raceFinished = true;
|
|
227
|
+
this.finalRanking = ranking;
|
|
228
|
+
events.push({ type: "race.finished", ranking, time: now });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return events;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
export function createRaceState(config) {
|
|
235
|
+
return new RaceState(config);
|
|
236
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { StatModifier, StatModifierSet, Stats } from "../stats/statModifiers.js";
|
|
2
|
+
export interface RunModifierOffer<TStat extends string = string, TData = unknown> {
|
|
3
|
+
id: string;
|
|
4
|
+
weight: number;
|
|
5
|
+
maxStacks?: number;
|
|
6
|
+
label?: string;
|
|
7
|
+
stats?: StatModifierSet<TStat>;
|
|
8
|
+
data?: TData;
|
|
9
|
+
}
|
|
10
|
+
export interface RunModifierPick {
|
|
11
|
+
id: string;
|
|
12
|
+
stacks: number;
|
|
13
|
+
}
|
|
14
|
+
export interface RunModifierStack<TStat extends string = string, TData = unknown> {
|
|
15
|
+
add(offerId: string): boolean;
|
|
16
|
+
count(offerId: string): number;
|
|
17
|
+
atMax(offerId: string): boolean;
|
|
18
|
+
picks(): RunModifierPick[];
|
|
19
|
+
offer(offerId: string): RunModifierOffer<TStat, TData> | null;
|
|
20
|
+
total(stat: TStat): StatModifier;
|
|
21
|
+
apply(stats: Stats<TStat>, sourceId?: string): void;
|
|
22
|
+
clear(): void;
|
|
23
|
+
}
|
|
24
|
+
export declare function createRunModifierStack<TStat extends string = string, TData = unknown>(offers: readonly RunModifierOffer<TStat, TData>[]): RunModifierStack<TStat, TData>;
|
|
25
|
+
export interface RunDraftConfig<TStat extends string = string, TData = unknown> {
|
|
26
|
+
offers: readonly RunModifierOffer<TStat, TData>[];
|
|
27
|
+
rng?: () => number;
|
|
28
|
+
}
|
|
29
|
+
export interface RunDraft<TStat extends string = string, TData = unknown> {
|
|
30
|
+
present(count: number, rng?: () => number): RunModifierOffer<TStat, TData>[];
|
|
31
|
+
choose(offerId: string): boolean;
|
|
32
|
+
stack(): RunModifierStack<TStat, TData>;
|
|
33
|
+
}
|
|
34
|
+
export declare function createRunDraft<TStat extends string = string, TData = unknown>(config: RunDraftConfig<TStat, TData>): RunDraft<TStat, TData>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { pickWeighted } from "../world/scatterItems.js";
|
|
2
|
+
export function createRunModifierStack(offers) {
|
|
3
|
+
const byId = new Map();
|
|
4
|
+
for (const offer of offers) {
|
|
5
|
+
if (byId.has(offer.id))
|
|
6
|
+
throw new Error(`duplicate run modifier offer: ${offer.id}`);
|
|
7
|
+
byId.set(offer.id, offer);
|
|
8
|
+
}
|
|
9
|
+
const stacks = new Map();
|
|
10
|
+
function count(offerId) {
|
|
11
|
+
return stacks.get(offerId) ?? 0;
|
|
12
|
+
}
|
|
13
|
+
function atMax(offerId) {
|
|
14
|
+
const offer = byId.get(offerId);
|
|
15
|
+
if (offer === undefined)
|
|
16
|
+
return true;
|
|
17
|
+
return offer.maxStacks !== undefined && count(offerId) >= offer.maxStacks;
|
|
18
|
+
}
|
|
19
|
+
function total(stat) {
|
|
20
|
+
let add = 0;
|
|
21
|
+
let multiply = 1;
|
|
22
|
+
for (const [offerId, n] of stacks) {
|
|
23
|
+
const modifier = byId.get(offerId)?.stats?.[stat];
|
|
24
|
+
if (modifier === undefined)
|
|
25
|
+
continue;
|
|
26
|
+
if (modifier.add !== undefined)
|
|
27
|
+
add += modifier.add * n;
|
|
28
|
+
if (modifier.multiply !== undefined)
|
|
29
|
+
multiply *= Math.pow(modifier.multiply, n);
|
|
30
|
+
}
|
|
31
|
+
return { add, multiply };
|
|
32
|
+
}
|
|
33
|
+
function statKeys() {
|
|
34
|
+
const keys = new Set();
|
|
35
|
+
for (const offerId of stacks.keys()) {
|
|
36
|
+
const stat = byId.get(offerId)?.stats;
|
|
37
|
+
if (stat === undefined)
|
|
38
|
+
continue;
|
|
39
|
+
for (const key of Object.keys(stat))
|
|
40
|
+
keys.add(key);
|
|
41
|
+
}
|
|
42
|
+
return [...keys];
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
add(offerId) {
|
|
46
|
+
if (!byId.has(offerId) || atMax(offerId))
|
|
47
|
+
return false;
|
|
48
|
+
stacks.set(offerId, count(offerId) + 1);
|
|
49
|
+
return true;
|
|
50
|
+
},
|
|
51
|
+
count,
|
|
52
|
+
atMax,
|
|
53
|
+
picks() {
|
|
54
|
+
return [...stacks.entries()].map(([id, s]) => ({ id, stacks: s }));
|
|
55
|
+
},
|
|
56
|
+
offer(offerId) {
|
|
57
|
+
return byId.get(offerId) ?? null;
|
|
58
|
+
},
|
|
59
|
+
total,
|
|
60
|
+
apply(stats, sourceId = "run-modifiers") {
|
|
61
|
+
const set = {};
|
|
62
|
+
for (const key of statKeys())
|
|
63
|
+
set[key] = total(key);
|
|
64
|
+
stats.addSource(sourceId, set);
|
|
65
|
+
},
|
|
66
|
+
clear() {
|
|
67
|
+
stacks.clear();
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function createRunDraft(config) {
|
|
72
|
+
const stack = createRunModifierStack(config.offers);
|
|
73
|
+
const defaultRng = config.rng ?? Math.random;
|
|
74
|
+
return {
|
|
75
|
+
present(count, rng = defaultRng) {
|
|
76
|
+
const pool = config.offers.filter((offer) => !stack.atMax(offer.id));
|
|
77
|
+
const remaining = pool.map((offer) => ({ value: offer, weight: offer.weight }));
|
|
78
|
+
const drawn = [];
|
|
79
|
+
while (drawn.length < count && remaining.length > 0) {
|
|
80
|
+
const picked = pickWeighted(remaining, rng());
|
|
81
|
+
if (picked === null)
|
|
82
|
+
break;
|
|
83
|
+
drawn.push(picked);
|
|
84
|
+
const index = remaining.findIndex((entry) => entry.value.id === picked.id);
|
|
85
|
+
if (index >= 0)
|
|
86
|
+
remaining.splice(index, 1);
|
|
87
|
+
}
|
|
88
|
+
return drawn;
|
|
89
|
+
},
|
|
90
|
+
choose(offerId) {
|
|
91
|
+
return stack.add(offerId);
|
|
92
|
+
},
|
|
93
|
+
stack() {
|
|
94
|
+
return stack;
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
package/dist/game/social.d.ts
CHANGED
|
@@ -5,10 +5,25 @@ export interface PresenceInfo {
|
|
|
5
5
|
zoneId?: string;
|
|
6
6
|
instanceId?: string;
|
|
7
7
|
}
|
|
8
|
+
export interface EmoteEntityLookup {
|
|
9
|
+
get(id: string): {
|
|
10
|
+
position: readonly [number, number, number];
|
|
11
|
+
role: string;
|
|
12
|
+
} | null;
|
|
13
|
+
}
|
|
14
|
+
export interface EmoteSpatialLookup {
|
|
15
|
+
inRadius(center: readonly [number, number, number], radius: number, filter?: (id: string) => boolean): readonly string[];
|
|
16
|
+
}
|
|
17
|
+
export interface EmotesDeps {
|
|
18
|
+
entities: EmoteEntityLookup;
|
|
19
|
+
spatial: EmoteSpatialLookup;
|
|
20
|
+
}
|
|
8
21
|
export interface SocialDeps {
|
|
9
22
|
events: GameEvents;
|
|
10
23
|
presence?: (userId: string) => PresenceInfo;
|
|
11
24
|
now?: () => number;
|
|
25
|
+
emotes?: EmotesDeps;
|
|
26
|
+
worldInviteTtlMs?: number;
|
|
12
27
|
}
|
|
13
28
|
export interface FriendEntry {
|
|
14
29
|
userId: string;
|
|
@@ -18,6 +33,10 @@ export interface FriendsSnapshot {
|
|
|
18
33
|
friends: string[];
|
|
19
34
|
blocked: string[];
|
|
20
35
|
}
|
|
36
|
+
export interface FriendRequestEntry {
|
|
37
|
+
requestId: string;
|
|
38
|
+
fromUserId: string;
|
|
39
|
+
}
|
|
21
40
|
export interface Friends {
|
|
22
41
|
canRequest(fromUserId: string, toUserId: string): {
|
|
23
42
|
reason: string;
|
|
@@ -30,9 +49,11 @@ export interface Friends {
|
|
|
30
49
|
accept(userId: string, requestId: string): {
|
|
31
50
|
reason: string;
|
|
32
51
|
} | null;
|
|
52
|
+
decline(userId: string, requestId: string): void;
|
|
33
53
|
remove(userId: string, friendUserId: string): void;
|
|
34
54
|
block(userId: string, targetUserId: string): void;
|
|
35
55
|
list(userId: string): FriendEntry[];
|
|
56
|
+
requestsFor(userId: string): FriendRequestEntry[];
|
|
36
57
|
snapshot(userId: string): FriendsSnapshot;
|
|
37
58
|
hydrate(userId: string, data: FriendsSnapshot): void;
|
|
38
59
|
}
|
|
@@ -45,6 +66,11 @@ export interface PartyConfig {
|
|
|
45
66
|
maxMembers: number;
|
|
46
67
|
inviteTtlMs?: number;
|
|
47
68
|
}
|
|
69
|
+
export interface PartyInviteEntry {
|
|
70
|
+
inviteId: string;
|
|
71
|
+
fromUserId: string;
|
|
72
|
+
createdAt: number;
|
|
73
|
+
}
|
|
48
74
|
export interface Party {
|
|
49
75
|
register(config: PartyConfig): void;
|
|
50
76
|
canInvite(fromUserId: string, toUserId: string): {
|
|
@@ -58,6 +84,7 @@ export interface Party {
|
|
|
58
84
|
accept(userId: string, inviteId: string): {
|
|
59
85
|
reason: string;
|
|
60
86
|
} | null;
|
|
87
|
+
decline(userId: string, inviteId: string): void;
|
|
61
88
|
kick(leaderUserId: string, memberUserId: string): {
|
|
62
89
|
reason: string;
|
|
63
90
|
} | null;
|
|
@@ -67,6 +94,46 @@ export interface Party {
|
|
|
67
94
|
} | null;
|
|
68
95
|
list(userId: string): PartyMemberEntry[];
|
|
69
96
|
membersOf(userId: string): string[];
|
|
97
|
+
invitesFor(userId: string): PartyInviteEntry[];
|
|
98
|
+
}
|
|
99
|
+
export declare const DEFAULT_EMOTE_RADIUS = 20;
|
|
100
|
+
export interface EmoteBroadcastResult {
|
|
101
|
+
from: string;
|
|
102
|
+
emoteId: string;
|
|
103
|
+
at: readonly [number, number, number];
|
|
104
|
+
recipients: readonly string[];
|
|
105
|
+
}
|
|
106
|
+
export interface Emotes {
|
|
107
|
+
play(fromUserId: string, emoteId: string, radius?: number): EmoteBroadcastResult | {
|
|
108
|
+
reason: string;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export interface WorldInviteTarget {
|
|
112
|
+
serverId: string;
|
|
113
|
+
joinCode?: string;
|
|
114
|
+
}
|
|
115
|
+
export interface WorldInvite extends WorldInviteTarget {
|
|
116
|
+
id: string;
|
|
117
|
+
fromUserId: string;
|
|
118
|
+
toUserId: string;
|
|
119
|
+
createdAt: number;
|
|
120
|
+
}
|
|
121
|
+
export interface WorldInvites {
|
|
122
|
+
canInvite(fromUserId: string, toUserId: string): {
|
|
123
|
+
reason: string;
|
|
124
|
+
} | null;
|
|
125
|
+
invite(fromUserId: string, toUserId: string, target: WorldInviteTarget): {
|
|
126
|
+
inviteId: string;
|
|
127
|
+
} | {
|
|
128
|
+
reason: string;
|
|
129
|
+
};
|
|
130
|
+
accept(userId: string, inviteId: string): {
|
|
131
|
+
target: WorldInviteTarget;
|
|
132
|
+
} | {
|
|
133
|
+
reason: string;
|
|
134
|
+
};
|
|
135
|
+
decline(userId: string, inviteId: string): void;
|
|
136
|
+
listFor(userId: string): WorldInvite[];
|
|
70
137
|
}
|
|
71
138
|
export interface Social {
|
|
72
139
|
friends: Friends;
|
|
@@ -74,5 +141,7 @@ export interface Social {
|
|
|
74
141
|
presence: {
|
|
75
142
|
get(userId: string): PresenceInfo;
|
|
76
143
|
};
|
|
144
|
+
emotes: Emotes;
|
|
145
|
+
worldInvites: WorldInvites;
|
|
77
146
|
}
|
|
78
147
|
export declare function createSocial(deps: SocialDeps): Social;
|