babylonjs-toolkit 9.34.100 → 9.35.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/lib/index.d.ts CHANGED
@@ -7,7 +7,7 @@ declare namespace TOOLKIT {
7
7
  * @class SceneManager - All rights reserved (c) 2024 Mackey Kinard
8
8
  */
9
9
  class SceneManager {
10
- /** Gets the toolkit framework version string (9.34.100 - R1) */
10
+ /** Gets the toolkit framework version string (9.35.0 - R1) */
11
11
  static get Version(): string;
12
12
  /** Gets the toolkit framework copyright notice */
13
13
  static get Copyright(): string;
@@ -17391,6 +17391,8 @@ declare namespace TOOLKIT {
17391
17391
  transports: TOOLKIT.GameServerTransports;
17392
17392
  /** True when joins need an auth token. */
17393
17393
  authRequired: boolean;
17394
+ /** True when players can sign in with Discord (Babylon Game Server discordSignIn). */
17395
+ discordSignIn?: boolean;
17394
17396
  }
17395
17397
  /** The connections a game server accepts. */
17396
17398
  interface GameServerTransports {
@@ -23894,6 +23896,629 @@ declare namespace TOOLKIT {
23894
23896
  restoreSceneObjects(token: HostMigrationToken): void;
23895
23897
  }
23896
23898
  }
23899
+ declare namespace TOOLKIT {
23900
+ /** Which scores rank first: "lowerIsBetter" for times, "higherIsBetter" for points and counters. */
23901
+ type LeaderboardSortOrder = "higherIsBetter" | "lowerIsBetter";
23902
+ /** How a score is shown: a plain integer, milliseconds shown as a time, or points. Scores are integers (D12). */
23903
+ type LeaderboardScoreFormat = "integer" | "timeMilliseconds" | "points";
23904
+ /** What a new score does to a player's entry: keep the best, keep the latest, or add to a running total (D14). */
23905
+ type LeaderboardKeepPolicy = "best" | "latest" | "sum";
23906
+ /** How far a submission can be trusted (D9): signed by the game client, confirmed by session presence, or sent by a server API key. */
23907
+ type LeaderboardTrustLevel = "client" | "session" | "server";
23908
+ /** Why a request or one score was refused. */
23909
+ type LeaderboardRefusalReason = "invalidRequest" | "authRequired" | "authRefused" | "banned" | "invalidPlayer" | "rateLimited" | "tooManyScores" | "unknownBoard" | "variantNotAllowed" | "scoreNotInteger" | "scoreOutOfRange" | "trustLevelNotAccepted" | "implausibleDuration" | "metadataTooLarge" | "nameInvalid" | "nameBlocked" | "nameManaged";
23910
+ /** What a write did to the player's stored entry (D14). */
23911
+ type LeaderboardWriteOutcome = "created" | "improved" | "replaced" | "added" | "kept";
23912
+ /** A JSON value allowed in entry metadata (display-only details next to a score). */
23913
+ type LeaderboardMetadataValue = string | number | boolean | null | LeaderboardMetadataValue[] | {
23914
+ [key: string]: LeaderboardMetadataValue;
23915
+ };
23916
+ /** Free-form, size-capped details stored with an entry; never ranked or queried. */
23917
+ type LeaderboardMetadata = {
23918
+ [key: string]: LeaderboardMetadataValue;
23919
+ };
23920
+ /** One way a board's rankings are split (a "map", a "difficulty"), with the values a submission may use (D16). */
23921
+ interface LeaderboardVariantDimension {
23922
+ /** Key in a submission's variant object. */
23923
+ name: string;
23924
+ /** Label shown in the console and in games. */
23925
+ label: string;
23926
+ /** Allowed values, in display order. */
23927
+ values: string[];
23928
+ }
23929
+ /** A board as game clients see it. */
23930
+ interface LeaderboardPublicBoardView {
23931
+ boardId: string;
23932
+ displayName: string;
23933
+ description: string;
23934
+ sortOrder: LeaderboardSortOrder;
23935
+ scoreFormat: LeaderboardScoreFormat;
23936
+ keepPolicy: LeaderboardKeepPolicy;
23937
+ dimensions: LeaderboardVariantDimension[];
23938
+ currentSeasonId: number;
23939
+ currentSeasonStartedAt: string;
23940
+ /** ISO time of the next scheduled reset, or null. */
23941
+ nextResetAt: string | null;
23942
+ }
23943
+ /** One season of a board. */
23944
+ interface LeaderboardSeasonView {
23945
+ /** 1, 2, 3 … */
23946
+ seasonId: number;
23947
+ /** ISO start. */
23948
+ startedAt: string;
23949
+ /** ISO end, or null for the current season. */
23950
+ endedAt: string | null;
23951
+ isCurrent: boolean;
23952
+ }
23953
+ /** One ranked entry. */
23954
+ interface LeaderboardEntryView {
23955
+ /** 1-based rank in its ranking. */
23956
+ rank: number;
23957
+ playerId: string;
23958
+ /** The name the player had when the entry was written (console renames update it). */
23959
+ displayName: string;
23960
+ /** The player's avatar claim (a Discord avatar hash for user:discord: players), or null. */
23961
+ avatar?: string | null;
23962
+ score: number;
23963
+ metadata: LeaderboardMetadata | null;
23964
+ trustLevel: LeaderboardTrustLevel;
23965
+ /** ISO time of the last accepted submission. */
23966
+ submittedAt: string;
23967
+ /** ISO time the stored score was reached (tie-break, D13). */
23968
+ achievedAt: string;
23969
+ }
23970
+ /** A page of one ranking. */
23971
+ interface LeaderboardEntriesPage {
23972
+ boardId: string;
23973
+ seasonId: number;
23974
+ variantKey: string;
23975
+ /** Entries in the ranking. */
23976
+ total: number;
23977
+ /** Zero-based index of the first entry. */
23978
+ offset: number;
23979
+ entries: LeaderboardEntryView[];
23980
+ }
23981
+ /** A window around one player; `playerRank` is null when the player has no entry. */
23982
+ interface LeaderboardAroundPage extends LeaderboardEntriesPage {
23983
+ playerRank: number | null;
23984
+ }
23985
+ /** A player as games see them. */
23986
+ interface LeaderboardPlayerView {
23987
+ playerId: string;
23988
+ displayName: string;
23989
+ kind: "anonymous" | "user" | "manual";
23990
+ createdAt: string;
23991
+ }
23992
+ /** The answer to POST players: the player and, only when it was just created anonymously, its one-time key. */
23993
+ interface LeaderboardPlayerSession {
23994
+ player: LeaderboardPlayerView;
23995
+ playerKey: string | null;
23996
+ }
23997
+ /** One score in a submission. */
23998
+ interface LeaderboardScoreSubmission {
23999
+ boardId: string;
24000
+ /** Dimension values; null or {} for a board without dimensions. */
24001
+ variant: Record<string, string> | null;
24002
+ score: number;
24003
+ metadata: LeaderboardMetadata | null;
24004
+ }
24005
+ /** POST submissions: the envelope every game sends at a key stage (spec D13). */
24006
+ interface LeaderboardSubmissionRequest {
24007
+ /** The anonymous player's key, or omitted for an auth user. */
24008
+ playerKey?: string;
24009
+ /** Client-made unique id, 8–64 of `[A-Za-z0-9-]` (exactly-once, D15). */
24010
+ submissionId: string;
24011
+ /** The game's mode name, at most 64 characters, or null. */
24012
+ gameMode: string | null;
24013
+ /** The game's build version, at most 64 characters, or null. */
24014
+ buildVersion: string | null;
24015
+ /** The network session name when the scores come from a network game, or null. */
24016
+ sessionName: string | null;
24017
+ /** How long the run lasted, in milliseconds, or null. */
24018
+ durationMs: number | null;
24019
+ /** The client's ISO clock (informational only; the server stamps its own time). */
24020
+ clientTime: string | null;
24021
+ /** 1–maximumScoresPerSubmission scores. */
24022
+ scores: LeaderboardScoreSubmission[];
24023
+ }
24024
+ /** What happened to one score. */
24025
+ interface LeaderboardScoreResult {
24026
+ boardId: string;
24027
+ variantKey: string | null;
24028
+ status: "accepted" | "duplicate" | "refused";
24029
+ outcome: LeaderboardWriteOutcome | null;
24030
+ /** The stored score after the keep policy, or null when refused. */
24031
+ score: number | null;
24032
+ previousScore: number | null;
24033
+ /** True when this submission created or improved the player's entry (or changed a latest/sum entry). */
24034
+ isPersonalBest: boolean;
24035
+ rank: number | null;
24036
+ total: number | null;
24037
+ seasonId: number | null;
24038
+ trustLevel: LeaderboardTrustLevel | null;
24039
+ refusal: LeaderboardRefusalReason | null;
24040
+ }
24041
+ /** The answer to POST submissions. */
24042
+ interface LeaderboardSubmissionResponse {
24043
+ submissionId: string;
24044
+ playerId: string;
24045
+ results: LeaderboardScoreResult[];
24046
+ }
24047
+ /** One ranking a player asks about. */
24048
+ interface LeaderboardTarget {
24049
+ boardId: string;
24050
+ variant: Record<string, string> | null;
24051
+ /** A season, or omitted for the current one. */
24052
+ seasonId?: number;
24053
+ }
24054
+ /** A player's entry in one ranking (null when they have none). */
24055
+ interface LeaderboardTargetEntry {
24056
+ boardId: string;
24057
+ variantKey: string;
24058
+ seasonId: number;
24059
+ total: number;
24060
+ entry: LeaderboardEntryView | null;
24061
+ }
24062
+ /** The error body of a refused public request. */
24063
+ interface LeaderboardErrorBody {
24064
+ error: string;
24065
+ reason: LeaderboardRefusalReason;
24066
+ }
24067
+ /** The part of the Web Storage API the client keeps its player key and unsent scores in (window.localStorage fits). */
24068
+ interface LeaderboardStorage {
24069
+ getItem(key: string): string | null;
24070
+ setItem(key: string, value: string): void;
24071
+ removeItem(key: string): void;
24072
+ }
24073
+ /** A fetch function (globalThis.fetch fits; tests pass a stub). */
24074
+ type LeaderboardFetch = (url: string, init: RequestInit) => Promise<Response>;
24075
+ /** Options of a LeaderboardClient. */
24076
+ interface LeaderboardClientOptions {
24077
+ /** The game's session server URL (ws://, wss://, http:// or https://), the same URL its network sessions use. */
24078
+ serverUrl: string;
24079
+ /** The server's auth token (the one startGame takes), or omitted when the server's auth is off. */
24080
+ authToken?: string;
24081
+ /** The game's build version, sent with every submission. */
24082
+ buildVersion?: string;
24083
+ /** Where the key and unsent scores are kept; default window.localStorage, null keeps nothing. */
24084
+ storage?: LeaderboardStorage | null;
24085
+ /** The fetch to use; default globalThis.fetch. */
24086
+ fetchFunction?: LeaderboardFetch;
24087
+ /** Milliseconds before a request counts as not sent; default 8000. */
24088
+ requestTimeoutMs?: number;
24089
+ /** Most unsent submissions kept on the device; default 50 (the oldest is dropped). */
24090
+ maximumPendingSubmissions?: number;
24091
+ }
24092
+ /** What a game passes at a key stage: its scores and the run's facts; the client adds the rest of the envelope. */
24093
+ interface LeaderboardSubmission {
24094
+ scores: TOOLKIT.LeaderboardScoreSubmission[];
24095
+ /** The game's mode name. */
24096
+ gameMode?: string;
24097
+ /** The network session name, when the scores come from a network game. */
24098
+ sessionName?: string;
24099
+ /** How long the run lasted, in milliseconds. */
24100
+ durationMs?: number;
24101
+ }
24102
+ /** The result of a read or profile call: the value, a refusal, or not sent (offline, timeout, server error). */
24103
+ type LeaderboardCallResult<Value> = {
24104
+ status: "ok";
24105
+ value: Value;
24106
+ } | {
24107
+ status: "refused";
24108
+ reason: TOOLKIT.LeaderboardRefusalReason;
24109
+ message: string;
24110
+ } | {
24111
+ status: "notSent";
24112
+ message: string;
24113
+ };
24114
+ /** The result of a submission: sent, queued for later (offline), or refused. Never thrown. */
24115
+ type LeaderboardSubmitResult = {
24116
+ status: "sent";
24117
+ response: TOOLKIT.LeaderboardSubmissionResponse;
24118
+ } | {
24119
+ status: "queued";
24120
+ submissionId: string;
24121
+ message: string;
24122
+ } | {
24123
+ status: "refused";
24124
+ reason: TOOLKIT.LeaderboardRefusalReason;
24125
+ message: string;
24126
+ };
24127
+ /** A read of one ranking. */
24128
+ interface LeaderboardRangeQuery {
24129
+ variant?: Record<string, string> | null;
24130
+ seasonId?: number;
24131
+ offset?: number;
24132
+ limit?: number;
24133
+ }
24134
+ /**
24135
+ * Talks to the Babylon Game Server's leaderboard service over HTTP (game-server-leaderboards D7, D8). It needs no
24136
+ * network session, so single-player screens use it too, and it never loads the Colyseus client. Submit at key
24137
+ * stages only (a match, round or level finish; the end of a multi-part run), one call per stage with every board that
24138
+ * stage updates. Failed submissions wait on the device and are sent, once, on a later call.
24139
+ * @example
24140
+ * const client: TOOLKIT.LeaderboardClient = new TOOLKIT.LeaderboardClient({ serverUrl: "wss://game.example.com", authToken: token });
24141
+ * const result: TOOLKIT.LeaderboardSubmitResult = await client.submit({ gameMode: "arena", durationMs: 92500, scores: [
24142
+ * { boardId: "arena-high-score", variant: { map: "harbor" }, score: 1840, metadata: { hero: "knight" } }
24143
+ * ] });
24144
+ */
24145
+ class LeaderboardClient {
24146
+ /** Milliseconds before a request counts as not sent, when the options name none. */
24147
+ static readonly DEFAULT_REQUEST_TIMEOUT_MS: number;
24148
+ /** Most unsent submissions kept on the device, when the options name none. */
24149
+ static readonly DEFAULT_MAXIMUM_PENDING_SUBMISSIONS: number;
24150
+ /** The server path every leaderboard route sits under. */
24151
+ static readonly API_PATH: string;
24152
+ /** Prefix of every storage key the client writes. */
24153
+ static readonly STORAGE_PREFIX: string;
24154
+ /** Storage key suffix of the anonymous identity. */
24155
+ private static readonly PLAYER_STORAGE_SUFFIX;
24156
+ /** Storage key suffix of the unsent submissions. */
24157
+ private static readonly PENDING_STORAGE_SUFFIX;
24158
+ /** Bytes of randomness in a submission id made from crypto.getRandomValues. */
24159
+ private static readonly SUBMISSION_ID_RANDOM_BYTES;
24160
+ /** Shortest submission id the server accepts. */
24161
+ private static readonly MINIMUM_SUBMISSION_ID_LENGTH;
24162
+ /** Random decimal digits appended to the clock in the last-resort submission id. */
24163
+ private static readonly FALLBACK_RANDOM_DIGITS;
24164
+ /** First HTTP status that is not a success. */
24165
+ private static readonly HTTP_FIRST_FAILURE_STATUS;
24166
+ /** HTTP status of a rate-limited request: sent again later, never refused. */
24167
+ private static readonly HTTP_TOO_MANY_REQUESTS;
24168
+ /** First HTTP status of a server error: sent again later, never refused. */
24169
+ private static readonly HTTP_FIRST_SERVER_ERROR;
24170
+ /** Message of a call made where no fetch exists. */
24171
+ private static readonly NO_FETCH_MESSAGE;
24172
+ /** Message of a queued submission. */
24173
+ private static readonly QUEUED_MESSAGE;
24174
+ /** The server's HTTP(S) address. */
24175
+ private readonly endpoint;
24176
+ /** The server's auth token, or an empty string to send none (setAuthToken changes it). */
24177
+ private authToken;
24178
+ /** The game's build version, or null. */
24179
+ private readonly buildVersion;
24180
+ /** Where the identity and unsent submissions are kept, or null for memory only. */
24181
+ private readonly storage;
24182
+ /** The fetch from the options, or null for globalThis.fetch at call time. */
24183
+ private readonly fetchFunction;
24184
+ /** Milliseconds before a request counts as not sent. */
24185
+ private readonly requestTimeoutMs;
24186
+ /** Most unsent submissions kept. */
24187
+ private readonly maximumPendingSubmissions;
24188
+ /** The identity as last written, used when the storage is missing or throws. */
24189
+ private memoryPlayer;
24190
+ /** The unsent submissions as last written, used when the storage is missing or throws. */
24191
+ private memoryPending;
24192
+ /** True once a storage call has thrown: from then on the identity and the waiting list live in memory only. */
24193
+ private storageFailed;
24194
+ /** The flush running now, shared by calls that overlap it, or null. */
24195
+ private flushInFlight;
24196
+ /**
24197
+ * Creates a client for one game server. Nothing is sent until a method is called.
24198
+ * @param options The server URL, auth token, build version, storage, fetch and limits.
24199
+ */
24200
+ constructor(options: TOOLKIT.LeaderboardClientOptions);
24201
+ /** The server's HTTP(S) address (ws:// → http://, wss:// → https://). */
24202
+ get httpEndpoint(): string;
24203
+ /** Unsent submissions waiting on this device. */
24204
+ get pendingCount(): number;
24205
+ /**
24206
+ * This device's anonymous player key for this server, or null before the first identity call or when nothing
24207
+ * is stored. Send it only to the game's own server (for example so a sign-in can move the anonymous history);
24208
+ * never show or log it.
24209
+ */
24210
+ get playerKey(): string | null;
24211
+ /**
24212
+ * The HTTP(S) address of a session server URL: ws:// maps to http://, wss:// to https://, anything else is kept.
24213
+ * @param serverUrl The game's session server URL.
24214
+ * @returns The HTTP(S) address.
24215
+ */
24216
+ static toHttpEndpoint(serverUrl: string): string;
24217
+ /**
24218
+ * Changes the token every later request sends, for a game whose player signs in or out without a reload.
24219
+ * Waiting submissions stay queued and are sent with the new token.
24220
+ * @param token The new token; null or an empty string sends none.
24221
+ */
24222
+ setAuthToken(token: string | null): void;
24223
+ /**
24224
+ * Forgets this device's anonymous player key for this server, in memory and in the storage, for a game whose
24225
+ * anonymous player was moved into a signed-in player (the server erased it, so the key would only be refused).
24226
+ * The next identity call makes a new anonymous player. Never throws.
24227
+ */
24228
+ forgetPlayerKey(): void;
24229
+ /**
24230
+ * Reads this device's player (POST players), creating an anonymous identity the first time. A new key is stored;
24231
+ * a stored key the server no longer knows is forgotten and a new identity is made, once.
24232
+ * @returns The player, a refusal, or not sent. Never throws.
24233
+ */
24234
+ getPlayer(): Promise<TOOLKIT.LeaderboardCallResult<TOOLKIT.LeaderboardPlayerView>>;
24235
+ /**
24236
+ * Changes the player's display name (POST players/me/name), creating the identity first when there is none.
24237
+ * @param displayName The new name; the server checks its length and blocked words.
24238
+ * @returns The renamed player, a refusal (nameInvalid, nameBlocked …), or not sent. Never throws.
24239
+ */
24240
+ setDisplayName(displayName: string): Promise<TOOLKIT.LeaderboardCallResult<TOOLKIT.LeaderboardPlayerView>>;
24241
+ /**
24242
+ * Submits the scores of one key stage. Waiting submissions are flushed first, then the identity is ensured, then
24243
+ * this one is posted. Offline, timed out, rate limited or a server error: it is queued and sent once on a later call.
24244
+ * An auth refusal keeps the submission queued, so it is sent once the game has a token the server accepts.
24245
+ * @param submission The scores and the run's facts.
24246
+ * @returns Sent with the server's per-score results, queued, or refused. Never throws.
24247
+ */
24248
+ submit(submission: TOOLKIT.LeaderboardSubmission): Promise<TOOLKIT.LeaderboardSubmitResult>;
24249
+ /**
24250
+ * Sends the waiting submissions, oldest first, with the current identity. It stops at the first one that is not
24251
+ * sent or that the server refuses for its token (keeping it and the rest) and drops other refused ones. Overlapping
24252
+ * calls share one flush.
24253
+ * @returns How many were sent. Never throws.
24254
+ */
24255
+ flushPending(): Promise<number>;
24256
+ /**
24257
+ * Lists the public boards (GET boards).
24258
+ * @returns The boards, a refusal, or not sent. Never throws.
24259
+ */
24260
+ listBoards(): Promise<TOOLKIT.LeaderboardCallResult<TOOLKIT.LeaderboardPublicBoardView[]>>;
24261
+ /**
24262
+ * Lists a board's seasons (GET boards/:boardId/seasons).
24263
+ * @param boardId The board.
24264
+ * @returns The seasons, a refusal, or not sent. Never throws.
24265
+ */
24266
+ listSeasons(boardId: string): Promise<TOOLKIT.LeaderboardCallResult<TOOLKIT.LeaderboardSeasonView[]>>;
24267
+ /**
24268
+ * Reads a page of one ranking from the top (GET boards/:boardId/entries).
24269
+ * @param boardId The board.
24270
+ * @param query The variant, season (default current), offset (default 0) and page size (the server's default).
24271
+ * @returns The page, a refusal, or not sent. Never throws.
24272
+ */
24273
+ getTop(boardId: string, query?: TOOLKIT.LeaderboardRangeQuery): Promise<TOOLKIT.LeaderboardCallResult<TOOLKIT.LeaderboardEntriesPage>>;
24274
+ /**
24275
+ * Reads the entries around this device's player in one ranking (POST boards/:boardId/around).
24276
+ * @param boardId The board.
24277
+ * @param variant The ranking's dimension values, or null for a board without dimensions.
24278
+ * @param window Entries above and below the player (the server's default when omitted).
24279
+ * @param seasonId A season, or omitted for the current one.
24280
+ * @returns The page with the player's rank (null without an entry), a refusal, or not sent. Never throws.
24281
+ */
24282
+ getAroundMe(boardId: string, variant: Record<string, string> | null, window?: number, seasonId?: number): Promise<TOOLKIT.LeaderboardCallResult<TOOLKIT.LeaderboardAroundPage>>;
24283
+ /**
24284
+ * Reads this device's player's entry in several rankings at once (POST entries/mine).
24285
+ * @param targets The rankings.
24286
+ * @returns One answer per target (entry null where the player has none), a refusal, or not sent. Never throws.
24287
+ */
24288
+ getMyEntries(targets: TOOLKIT.LeaderboardTarget[]): Promise<TOOLKIT.LeaderboardCallResult<TOOLKIT.LeaderboardTargetEntry[]>>;
24289
+ /**
24290
+ * Reads the entries of chosen players in one ranking (POST boards/:boardId/players), e.g. the players of a session.
24291
+ * @param boardId The board.
24292
+ * @param playerIds The players (at most 50).
24293
+ * @param variant The ranking's dimension values, or null for a board without dimensions.
24294
+ * @param seasonId A season, or omitted for the current one.
24295
+ * @returns The players' entries (players without one are absent), a refusal, or not sent. Never throws.
24296
+ */
24297
+ getPlayersEntries(boardId: string, playerIds: string[], variant?: Record<string, string> | null, seasonId?: number): Promise<TOOLKIT.LeaderboardCallResult<TOOLKIT.LeaderboardEntryView[]>>;
24298
+ /**
24299
+ * Erases this device's player and every entry of theirs on the server (POST players/me/delete). On success the
24300
+ * stored identity and the waiting submissions are forgotten too.
24301
+ * @returns How many entries were erased, a refusal, or not sent. Never throws.
24302
+ */
24303
+ deleteMyData(): Promise<TOOLKIT.LeaderboardCallResult<number>>;
24304
+ /**
24305
+ * Posts a JSON body.
24306
+ * @param path The route after API_PATH.
24307
+ * @param body The body.
24308
+ * @returns The answer.
24309
+ */
24310
+ private postJson;
24311
+ /**
24312
+ * Reads a route.
24313
+ * @param path The route after API_PATH, with its query string.
24314
+ * @returns The answer.
24315
+ */
24316
+ private getJson;
24317
+ /**
24318
+ * Sends one request and sorts its answer: 2xx is ok, 429 and 5xx are not sent, any other 4xx is refused with the
24319
+ * body's reason (invalidRequest when it has none). A network failure or timeout is not sent.
24320
+ * @param method The HTTP method.
24321
+ * @param path The route after API_PATH.
24322
+ * @param body The JSON body, or null for none.
24323
+ * @returns The answer. Never throws.
24324
+ */
24325
+ private send;
24326
+ /**
24327
+ * The full URL of a route.
24328
+ * @param path The route after API_PATH.
24329
+ * @returns The URL.
24330
+ */
24331
+ private routeUrl;
24332
+ /**
24333
+ * The fetch options of a request: plain-object headers (JSON content type on bodies, the bearer token when auth
24334
+ * is on) and a timeout signal when the environment has one.
24335
+ * @param method The HTTP method.
24336
+ * @param body The JSON body, or null for none.
24337
+ * @returns The options.
24338
+ */
24339
+ private requestInit;
24340
+ /**
24341
+ * Posts a route that names a player, with the stored key when there is one. A key the server no longer knows is
24342
+ * forgotten.
24343
+ * @param path The route after API_PATH.
24344
+ * @param fields The body without the key.
24345
+ * @returns The answer.
24346
+ */
24347
+ private postAsStoredPlayer;
24348
+ /**
24349
+ * Posts a route that names a player after making sure the device has an identity. A key the server no longer
24350
+ * knows is forgotten, a new identity is made and the post is repeated once.
24351
+ * @param path The route after API_PATH.
24352
+ * @param fields The body without the key.
24353
+ * @returns The answer.
24354
+ */
24355
+ private postAsIdentifiedPlayer;
24356
+ /**
24357
+ * Ensures the identity, then posts with its key.
24358
+ * @param path The route after API_PATH.
24359
+ * @param fields The body without the key.
24360
+ * @returns The answer and whether a key was sent.
24361
+ */
24362
+ private postWithIdentity;
24363
+ /**
24364
+ * Makes sure the device can name its player: a stored key is enough; otherwise POST players (an auth user, or a
24365
+ * new anonymous identity).
24366
+ * @returns Ok, or why there is no identity.
24367
+ */
24368
+ private ensureIdentity;
24369
+ /**
24370
+ * POST players with a key or without one; a key in the answer is stored.
24371
+ * @param storedPlayer The identity whose key is sent, or null to send none.
24372
+ * @returns The player.
24373
+ */
24374
+ private requestPlayerSession;
24375
+ /**
24376
+ * Posts one submission envelope as the device's player.
24377
+ * @param request The envelope, without a key.
24378
+ * @returns The server's per-score results, a refusal, or not sent.
24379
+ */
24380
+ private postSubmission;
24381
+ /**
24382
+ * Builds the full envelope of a submission.
24383
+ * @param submission What the game passed.
24384
+ * @returns The envelope, without a key.
24385
+ */
24386
+ private buildSubmissionRequest;
24387
+ /**
24388
+ * Sends the waiting submissions (flushPending's work).
24389
+ * @returns How many were sent. Never throws.
24390
+ */
24391
+ private flushQueue;
24392
+ /**
24393
+ * Puts a submission at the end of the waiting list, dropping the oldest beyond the limit.
24394
+ * @param request The envelope, without a key.
24395
+ * @returns The queued result.
24396
+ */
24397
+ private queueSubmission;
24398
+ /**
24399
+ * Takes one submission off the waiting list.
24400
+ * @param submissionId Its id.
24401
+ */
24402
+ private removePending;
24403
+ /**
24404
+ * The stored anonymous identity.
24405
+ * @returns The identity, or null when there is none (memory's copy when the storage is missing or has thrown).
24406
+ */
24407
+ private readStoredPlayer;
24408
+ /**
24409
+ * Keeps the anonymous identity, in memory and in the storage.
24410
+ * @param player The identity.
24411
+ */
24412
+ private storePlayer;
24413
+ /** Forgets the anonymous identity, in memory and in the storage. */
24414
+ private forgetPlayer;
24415
+ /**
24416
+ * The waiting submissions, oldest first.
24417
+ * @returns The envelopes, without keys.
24418
+ */
24419
+ private readPending;
24420
+ /**
24421
+ * Replaces the waiting submissions, in memory and in the storage (an empty list removes the storage item).
24422
+ * @param pending The envelopes, without keys, oldest first.
24423
+ */
24424
+ private writePending;
24425
+ /**
24426
+ * A storage key of this server.
24427
+ * @param suffix The item's suffix.
24428
+ * @returns The key.
24429
+ */
24430
+ private storageKey;
24431
+ /**
24432
+ * Reads a storage item.
24433
+ * @param key The key.
24434
+ * @returns The text, null when the item is absent, or undefined when there is no usable storage (read memory).
24435
+ */
24436
+ private readStorageItem;
24437
+ /**
24438
+ * Writes a storage item; a missing or throwing storage keeps nothing (memory keeps it).
24439
+ * @param key The key.
24440
+ * @param value The text.
24441
+ */
24442
+ private writeStorageItem;
24443
+ /**
24444
+ * Removes a storage item; a missing or throwing storage keeps nothing (memory keeps it).
24445
+ * @param key The key.
24446
+ */
24447
+ private removeStorageItem;
24448
+ /**
24449
+ * A new submission id of 8–64 characters from `[A-Za-z0-9-]`: crypto.randomUUID(), else 16 random bytes in hex
24450
+ * from crypto.getRandomValues, else the clock and Math.random digits.
24451
+ * @returns The id.
24452
+ */
24453
+ private static newSubmissionId;
24454
+ /**
24455
+ * A signal that aborts the request after requestTimeoutMs, when the environment has AbortSignal.timeout.
24456
+ * @returns The signal, or null.
24457
+ */
24458
+ private timeoutSignal;
24459
+ /**
24460
+ * A query string built with encodeURIComponent; parameters without a value are left out.
24461
+ * @param parameters Names and values.
24462
+ * @returns "?name=value&…", or an empty string.
24463
+ */
24464
+ private static queryString;
24465
+ /**
24466
+ * window.localStorage when the page has one and it can be reached.
24467
+ * @returns The storage, or null.
24468
+ */
24469
+ private static defaultStorage;
24470
+ /**
24471
+ * globalThis.fetch, bound to the global object.
24472
+ * @returns The fetch, or null when the environment has none.
24473
+ */
24474
+ private static globalFetch;
24475
+ /**
24476
+ * A body with the identity's key added (never in a header or the URL, D6).
24477
+ * @param fields The body without the key.
24478
+ * @param storedPlayer The identity, or null to add no key.
24479
+ * @returns A new body.
24480
+ */
24481
+ private static withPlayerKey;
24482
+ /**
24483
+ * Reads a response's JSON body.
24484
+ * @param response The response.
24485
+ * @returns The parsed body, or null when it is empty or not JSON.
24486
+ */
24487
+ private static readBody;
24488
+ /**
24489
+ * Sorts an HTTP answer into ok, refused or not sent.
24490
+ * @param status The HTTP status.
24491
+ * @param body The parsed body.
24492
+ * @returns The call result.
24493
+ */
24494
+ private static sortAnswer;
24495
+ /**
24496
+ * Whether an answer says the sent player key is unknown.
24497
+ * @param answer The answer.
24498
+ * @returns True for a refusal with reason invalidPlayer.
24499
+ */
24500
+ private static isInvalidPlayer;
24501
+ /**
24502
+ * Whether an answer is the server refusing the token itself (the player's session ended or changed), which must
24503
+ * never cost a waiting score.
24504
+ * @param answer The answer.
24505
+ * @returns True for a refusal with reason authRequired or authRefused.
24506
+ */
24507
+ private static isAuthRefusal;
24508
+ /**
24509
+ * A not-sent result for something thrown.
24510
+ * @param error What was thrown.
24511
+ * @returns The result.
24512
+ */
24513
+ private static notSent;
24514
+ /**
24515
+ * A one-line description of something thrown.
24516
+ * @param error What was thrown.
24517
+ * @returns Its message.
24518
+ */
24519
+ private static describeError;
24520
+ }
24521
+ }
23897
24522
  declare namespace TOOLKIT {
23898
24523
  /** Marks a kart that this client does not simulate (a network replica) so local karts still bump it (D16). */
23899
24524
  class KartBumpTarget extends TOOLKIT.ScriptComponent {
@@ -23954,6 +24579,11 @@ declare namespace TOOLKIT {
23954
24579
  const DRIVER_HAS_ITEM_PARAMETER: string;
23955
24580
  /** Reversing: the driver turns to look behind (`Player.cs:1479-1489`, `Driver.SetBool("Reverse", …)`). */
23956
24581
  const DRIVER_REVERSE_PARAMETER: string;
24582
+ /**
24583
+ * The driver's trick triggers, in the order Unity fires them: `Player.cs:2557-2600` `trickJump()` cycles
24584
+ * `trickAnimCounter` 0 → 1 → 2 → 0 and sets `Driver.SetTrigger("JumpTrick1")`, `"JumpTrick2"`, `"GliderTrick"`.
24585
+ */
24586
+ const DRIVER_TRICK_TRIGGERS: readonly string[];
23957
24587
  /** Which way the driver leans this frame. Both false is the upright `New State`. */
23958
24588
  interface IDriverLeanState {
23959
24589
  /** The `TurnLeft` bool. */
@@ -24012,6 +24642,8 @@ declare namespace TOOLKIT {
24012
24642
  private hasWrittenHead;
24013
24643
  /** The `Reverse` value last delivered to at least one Animator; the bool is written only when it changes. */
24014
24644
  private reverseWritten;
24645
+ /** Index into `DRIVER_TRICK_TRIGGERS` of the next trick pose (Unity's `trickAnimCounter`). */
24646
+ private trickAnimationIndex;
24015
24647
  /** Scratch values, so the per-frame work allocates nothing. */
24016
24648
  private readonly lookRotation;
24017
24649
  private readonly localAxis;
@@ -24097,6 +24729,14 @@ declare namespace TOOLKIT {
24097
24729
  * @param animators The rig Animators; each that declares `Reverse` receives it.
24098
24730
  */
24099
24731
  private writeReverse;
24732
+ /**
24733
+ * `Player.cs:2557-2600`. Fires the next trick pose in Unity's rotation (`JumpTrick1`, `JumpTrick2`, `GliderTrick`,
24734
+ * then round again) on every rig Animator that declares it, and advances the rotation whether or not any did —
24735
+ * an Animator without the triggers plays nothing, as in Unity.
24736
+ * @param animators The rig Animators, as `updateFrame` receives them.
24737
+ * @returns The trigger name fired.
24738
+ */
24739
+ playTrick(animators: TOOLKIT.Animator[]): string;
24100
24740
  /**
24101
24741
  * Turns the steering wheel about its own column: Unity writes `localEulerAngles = (0, 180 ± 25, 0)` onto a
24102
24742
  * wheel whose rest is `(0, 180, 0)`, so the turn is the rest followed by a local yaw.
@@ -27237,7 +27877,10 @@ declare namespace TOOLKIT {
27237
27877
  * moment the race camera takes over, before the countdown starts charging the launch.
27238
27878
  */
27239
27879
  isRevvingOnGrid?(): boolean;
27240
- /** `RACE_MANAGER.RACE_COMPLETED` (`Player.cs:1193`) — silences the glider trick voice. */
27880
+ /**
27881
+ * `RACE_MANAGER.RACE_COMPLETED` (`Player.cs:1193`) — silences the glider trick voice and fades the engine out
27882
+ * (`PlayerSounds.cs:147-151`).
27883
+ */
27241
27884
  isRaceCompleted?(): boolean;
27242
27885
  /**
27243
27886
  * `RACE_STARTED` — the green light. Optional: the player's idle starts fading in at the latest here when the game
@@ -27286,6 +27929,13 @@ declare namespace TOOLKIT {
27286
27929
  driftAudioEnabled: boolean;
27287
27930
  /** The engine and idle loops (`PlayerSounds.kart_sounds`). */
27288
27931
  engineAudioEnabled: boolean;
27932
+ /**
27933
+ * `RACE_MANAGER.RACE_COMPLETED` for this kart's engine: true fades the engine out (`PlayerSounds.cs:147-151`,
27934
+ * `ComputerDriverSounds.cs:122-125`), false brings it back to its road level. Unity's flag is one static set when
27935
+ * the player finishes, so every kart's engine fades together; a kart's own `isRaceCompleted()` fades it without
27936
+ * this, so the game sets it on the other karts when its player finishes, and clears it for a new race.
27937
+ */
27938
+ raceCompleted: boolean;
27289
27939
  /** The payout voice (`Mario_Boost_Sounds`). */
27290
27940
  boostAudioEnabled: boolean;
27291
27941
  /** The hop blip (`effectSounds[6]`). Separate from `driftAudioEnabled` — see `tickHopAudio`. */
@@ -27458,6 +28108,8 @@ declare namespace TOOLKIT {
27458
28108
  protected enginePlayhead: KartEnginePlayhead;
27459
28109
  /** `kartSound.pitch` (`PlayerSounds.cs:122`). */
27460
28110
  protected enginePitch: number;
28111
+ /** `kartSound.volume` while it fades after the race (`PlayerSounds.cs:147-151`), before the master gain; null while racing. */
28112
+ protected raceEndEngineVolume: number | null;
27461
28113
  /** `kartIdle.volume` before the master gain: the player's eases from 0 to 0.8, an opponent's is 1 (D2). */
27462
28114
  protected idleLevel: number;
27463
28115
  /** `PlayerSounds.SceneEntryFinished` — the race intro has handed off, so the player's idle fades in. */
@@ -28022,6 +28674,22 @@ declare namespace TOOLKIT {
28022
28674
  * @returns The volume, `[0..1]`.
28023
28675
  */
28024
28676
  protected engineVolume(gliding: boolean): number;
28677
+ /**
28678
+ * This frame's engine volume before the master gain (`PlayerSounds.cs:138-151`). While racing it is the road level
28679
+ * or the glider duck, written every frame. Once the race is completed Unity stops writing those levels and takes
28680
+ * 0.01 off the volume every frame instead, down to silence, so the engine fades out while the race-end drive still
28681
+ * holds the kart at speed.
28682
+ * @param gliding Whether the kart is gliding.
28683
+ * @param deltaSeconds Frame time, seconds.
28684
+ * @returns The volume, `[0..1]`.
28685
+ */
28686
+ protected stepEngineLevel(gliding: boolean, deltaSeconds: number): number;
28687
+ /**
28688
+ * Whether the engine fades for a completed race: the game says so (`raceCompleted`, Unity's one static flag), or
28689
+ * the kart's own race is completed.
28690
+ * @returns True once the race is completed for this kart's engine.
28691
+ */
28692
+ protected isEngineRaceCompleted(): boolean;
28025
28693
  /**
28026
28694
  * D2: gives the engine and idle sources the rig's spatial values, whatever container they came from — so a person
28027
28695
  * driving Luigi (an AI-rig container) still hears a 2D engine, and a remote Mario (a player-rig container) is heard
@@ -29051,7 +29719,10 @@ declare namespace TOOLKIT {
29051
29719
  * volume nudges the kart's heading, it does not snap it.
29052
29720
  */
29053
29721
  const JUMP_PANEL_ROTATE_RATE: number;
29054
- /** `Player.cs:229`. Minimum `REALCURRENTSPEED` a trick needs — the ACTUAL nose-local speed. */
29722
+ /**
29723
+ * Minimum `REALCURRENTSPEED` a trick needs — the ACTUAL nose-local speed. Unity's `Player.cs:229` gate is 40; the
29724
+ * game lowers it to 30 (user, 2026-11-10) so tricks are easier to hit.
29725
+ */
29055
29726
  const TRICK_MIN_SPEED: number;
29056
29727
  /** How long the trick's upward push lasts, seconds. */
29057
29728
  const TRICK_SECONDS: number;
@@ -29070,7 +29741,10 @@ declare namespace TOOLKIT {
29070
29741
  const TRICK_FORCE_FLOOR: number;
29071
29742
  /** `Player.cs:539-541`. Seconds of boost a landed trick FLOORS `Boost_time` at. Never assigns. */
29072
29743
  const TRICK_LANDING_BOOST: number;
29073
- /** `Player.cs:1109-1214`. Above this `REALCURRENTSPEED` a glider deploy plays the trick variant. */
29744
+ /**
29745
+ * Above this `REALCURRENTSPEED` a glider deploy plays the trick variant (`Player.cs:1109-1214`). Unity's gate is 60;
29746
+ * the game lowers it to 50 (user, 2026-11-10) so glider tricks are easier to hit.
29747
+ */
29074
29748
  const GLIDER_TRICK_SPEED: number;
29075
29749
  /** The trick variant's pause before the canopy opens, seconds. */
29076
29750
  const GLIDER_TRICK_OPEN_DELAY: number;
@@ -30409,12 +31083,32 @@ declare namespace TOOLKIT {
30409
31083
  protected inputTrick: boolean;
30410
31084
  /** Seconds into the trick's upward push, or `-1` when no trick is running. */
30411
31085
  protected trickTime: number;
30412
- /** A `TrickCollider` has been touched, so a trick is allowed. Cleared on landing. */
31086
+ /**
31087
+ * Inside a `TrickCollider`, so a trick press is allowed (Unity's `trickAvailable`). Set on entering the volume,
31088
+ * cleared on leaving it and when a trick starts (`Player.cs:1030`, `:1221`, `:232`).
31089
+ */
30413
31090
  protected trickArmed: boolean;
30414
- /** A trick was performed this flight and its landing still owes the 0.9 s boost floor. */
31091
+ /**
31092
+ * A trick has started and its landing still owes the 0.9 s boost floor. Survives the end of the push window (the
31093
+ * landing normally comes later); cleared on landing, or when the window ends without the kart leaving the ground.
31094
+ */
30415
31095
  protected trickPerformed: boolean;
30416
- /** Edge-detect for the trick button: a trick fires on the PRESS, not on the hold. */
31096
+ /** The kart has left the ground since the running trick started; only a ground contact after this lands it. */
31097
+ protected trickLeftGround: boolean;
31098
+ /** A `Ground`/`Dirt`/`AntiGravity` contact arrived since the last step. Read and cleared by `trackTrickGroundContact`. */
31099
+ protected trickGroundContact: boolean;
31100
+ /** Edge-detect for the trick button, read in `drive()`: a trick fires on the PRESS, not on the hold. */
30417
31101
  protected trickPressed: boolean;
31102
+ /**
31103
+ * A trick press `drive()` saw that no physics step has read yet. Set on the press, cleared by the next step.
31104
+ *
31105
+ * WHY A QUEUE: `drive()` runs once per rendered frame, and the physics runs on a fixed 0.02 s step (0..N steps a
31106
+ * frame). A press is true for one frame only, so a frame that runs no step lost it — 17 % of frames at 60 Hz,
31107
+ * 58 % at 120 Hz, 65 % at 144 Hz. That made the trick hit or miss on the same ramp.
31108
+ */
31109
+ protected trickPressQueued: boolean;
31110
+ /** The driver trick trigger the last trick fired (`DRIVER_TRICK_TRIGGERS`), or null before the first one. */
31111
+ protected lastTrickTrigger: string | null;
30418
31112
  /** Set each step by `move()`: does a vertical push survive into the next step? See its note there. */
30419
31113
  protected verticalAccumulates: boolean;
30420
31114
  /**
@@ -30946,12 +31640,20 @@ declare namespace TOOLKIT {
30946
31640
  /** Ends a jump-panel flight. `Player.cs:494`/`529` — contact with `Ground` or `Dirt`. */
30947
31641
  protected endJumpPanel(): void;
30948
31642
  /**
30949
- * `Player.cs:229`. Starts a trick if all three gates pass, otherwise does nothing at all.
30950
- *
30951
- * Returns whether one started, because "the trick did nothing" is a thing the bench and the
30952
- * tests need to be able to assert positively rather than infer from an unchanged trajectory.
31643
+ * `Player.cs:229-232`. Starts a trick on the button press when every gate passes, otherwise does nothing at all.
31644
+ * A started trick disarms its volume (`trickAvailable = false`, `:232`), so a second press in it does nothing.
31645
+ * @returns Whether a trick started — so the bench and the tests can assert "nothing happened" positively.
30953
31646
  */
30954
31647
  protected tryTrick(): boolean;
31648
+ /**
31649
+ * Once per step, before the trick button is read: notes whether a trick in flight has left the ground, and clears
31650
+ * the per-step contact flag.
31651
+ *
31652
+ * "Left the ground" is the first step with no `Ground`/`Dirt`/`AntiGravity` contact (the contact analogue of Unity's
31653
+ * `OnCollisionExit`) or the ground probe reporting airborne, whichever comes first. The probe alone reaches
31654
+ * `activeGroundRayDist` (2 units) down and still reports grounded for a while past the lip.
31655
+ */
31656
+ protected trackTrickGroundContact(): void;
30955
31657
  /**
30956
31658
  * One step of the trick's upward push.
30957
31659
  *
@@ -30960,6 +31662,10 @@ declare namespace TOOLKIT {
30960
31662
  * which is the same curve sampled differently. The floor is what makes the last third of the
30961
31663
  * trick a gentle hold rather than the force going negative and hauling the kart down.
30962
31664
  *
31665
+ * When the window runs out the push stops but the landing is still owed (`trickPerformed`
31666
+ * survives), because the window normally ends mid-air. Only a trick whose kart never left the
31667
+ * ground ends there with nothing owed.
31668
+ *
30963
31669
  * HOW IT IS DELIVERED DEPENDS ON THE FRAME, not on the mode — see the branch in the body and
30964
31670
  * `verticalAccumulates`. This doc used to say "a STEP VELOCITY, not an acceleration, because the
30965
31671
  * clamp never lets the heading ADD vertical speed, so an upward force cannot accumulate in ANY
@@ -30967,10 +31673,15 @@ declare namespace TOOLKIT {
30967
31673
  * clamp, so it lands in the body, and the clamp then preserves the body's `y` on every frame
30968
31674
  * where the nose is pitched above it — which is every frame of a ramp jump. The claim was wrong,
30969
31675
  * and the code that followed from it made a trick 3.87x higher at 144 Hz than at 30 Hz.
31676
+ * @param dt Step length, seconds.
30970
31677
  */
30971
31678
  protected tickTrick(dt: number): void;
30972
31679
  /**
30973
- * `Player.cs:539-541`. Landing after a trick floors the boost at 0.9 s.
31680
+ * `Player.cs:537-545`. A trick's landing: the first `Ground`/`Dirt`/`AntiGravity` contact after the kart left the
31681
+ * ground ends the trick and floors the boost at 0.9 s. `AntiGravity` is a deliberate departure from Unity's
31682
+ * OnCollisionEnter list (mario-kart-trick-fixes F5): a ramp onto an anti-gravity road pays on that landing.
31683
+ * Called from `onSurfaceContact` on every contact step, enter and stay alike; a contact before the kart has left
31684
+ * the ground (the ramp it is still on) neither ends the trick nor pays.
30974
31685
  *
30975
31686
  * **A FLOOR, NEVER AN ASSIGNMENT** (§E.4). Landing a trick in the middle of a 2.5 s drift
30976
31687
  * payout must not cut it to 0.9, which is what an assignment would do and what would make
@@ -30978,6 +31689,13 @@ declare namespace TOOLKIT {
30978
31689
  * when it is called.
30979
31690
  */
30980
31691
  protected landTrick(): void;
31692
+ /**
31693
+ * `Player.cs:2557-2600`. Fires the driver's next trick pose on the rig Animators and remembers which. Only a
31694
+ * player trick calls it — the glider trick's payout does not.
31695
+ */
31696
+ protected playTrickAnimation(): void;
31697
+ /** Ends the running trick with nothing owed: no push, no pending landing, no flight noted. */
31698
+ protected clearTrickState(): void;
30981
31699
  /**
30982
31700
  * `Player.cs:1109-1214`. Leaving a `GliderPanelFly` volume deploys the glider.
30983
31701
  *
@@ -33294,9 +34012,15 @@ declare namespace TOOLKIT {
33294
34012
  isTricking(): boolean;
33295
34013
  /** Seconds into the trick push, or `-1`. */
33296
34014
  getTrickTime(): number;
33297
- /** A `TrickCollider` has been touched, so a trick is allowed until the next landing. */
34015
+ /**
34016
+ * The driver trick trigger the last trick fired — `JumpTrick1`, `JumpTrick2` or `GliderTrick`, in Unity's rotation —
34017
+ * or null before the first trick. Set even when no rig Animator declares it (only some racers have the poses).
34018
+ * @returns The trigger name, or null.
34019
+ */
34020
+ getLastTrickTrigger(): string | null;
34021
+ /** The kart is inside a `TrickCollider` it has not tricked in yet, so a trick press is allowed. */
33298
34022
  isTrickArmed(): boolean;
33299
- /** A trick was performed this flight and its landing still owes the 0.9 s boost floor. */
34023
+ /** A trick has started and its landing still owes the 0.9 s boost floor. */
33300
34024
  isTrickPending(): boolean;
33301
34025
  /** Front-wheel steer angle, degrees. Presentation only — see `updateWheels`. */
33302
34026
  getWheelSteer(): number;
@@ -62707,6 +63431,36 @@ declare namespace TOOLKIT {
62707
63431
  private static WarnLightmappedMaterial;
62708
63432
  /** Clears the riders of a mesh this network attached, lifts the ambient and Baked-light exclusions, removes the dispose observer, and (dynamic) compacts the registry by moving the last entry in. A mesh another network attached, or a raw clone sharing a rider, is left alone. */
62709
63433
  detach(mesh: BABYLON.AbstractMesh): void;
63434
+ /**
63435
+ * The dispose observer's detach. It runs before the loader's DisposeEntity, so the rider is normally intact and
63436
+ * detach() does the work. When the mesh's metadata is already gone (another observer cleared it first), the
63437
+ * registry entry is found by identity instead - never through metadata - so a disposed mesh never stays in the
63438
+ * registry for sampleDynamic to read.
63439
+ * @param mesh The mesh being disposed.
63440
+ */
63441
+ private detachDisposed;
63442
+ /**
63443
+ * Lets go of a mesh this network attached, reading nothing from its metadata (it may already be gone): lifts the
63444
+ * ambient and Baked-light exclusions, removes its dynamic registry entry (or its static count), clears the owner
63445
+ * and removes the dispose observer. The rider itself is detach()'s to clear.
63446
+ * @param mesh The mesh to release.
63447
+ * @param registryIndex The mesh's dynamic registry index, or -1 for a static mesh.
63448
+ */
63449
+ private releaseMesh;
63450
+ /**
63451
+ * Removes one dynamic registry entry by its index, never by reading the removed mesh's metadata: the last entry
63452
+ * moves into the freed index, the last slot is nulled and the count drops by one. The moved mesh's
63453
+ * lightProbeSlot follows it only while its metadata.toolkit exists - a moved mesh that lost its metadata is
63454
+ * dropped by the next late().
63455
+ * @param registryIndex The entry to remove, in [0, getDynamicCount()).
63456
+ */
63457
+ private removeDynamicEntry;
63458
+ /**
63459
+ * Drops every registry entry whose mesh was disposed, or lost its metadata, without the dispose observer
63460
+ * removing it, so sampleDynamic never reads a dead mesh. Walks from the end, so the move-last-in of
63461
+ * removeDynamicEntry only ever moves an entry that was already checked. One check per entry, no allocation.
63462
+ */
63463
+ private dropDisposedEntries;
62710
63464
  /** Re-interpolates one dynamic mesh now (ignores MoveThreshold). Returns the cell used. */
62711
63465
  sampleMeshNow(mesh: BABYLON.AbstractMesh): number;
62712
63466
  /** One registry entry's re-interpolation (Control flow › Frame step 4). */