1681-engine 0.5.10 → 0.6.1
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 +61 -1
- package/README.md +12 -6
- package/dist/1681-engine.js +588 -522
- package/dist/ai/behaviorTree.js +198 -0
- package/dist/ai/buildTree.js +54 -0
- package/dist/audio/spatial.js +118 -0
- package/dist/cjs/electron/webPatcher.d.ts +4 -1
- package/dist/cjs/electron/webPatcher.js +9 -2
- package/dist/core/Camera.js +10 -0
- package/dist/core/ObjectFactory.js +23 -21
- package/dist/core/PixelGrid.js +47 -0
- package/dist/core/SharpText.js +72 -0
- package/dist/core/Stage.js +48 -31
- package/dist/core/gridPlacement.js +14 -0
- package/dist/dialogue/DialogueRunner.js +173 -0
- package/dist/dialogue/expr.js +137 -0
- package/dist/dialogue/validateDialogue.js +52 -0
- package/dist/ecs/prefab.js +94 -0
- package/dist/electron/webPatcher.js +16 -10
- package/dist/input/Actions.js +58 -27
- package/dist/input/InputCapture.js +98 -0
- package/dist/input/Keymap.js +32 -26
- package/dist/input/inputTape.js +68 -0
- package/dist/mobile/backButton.js +40 -0
- package/dist/mobile/capacitor.js +48 -0
- package/dist/mobile/screen.js +31 -0
- package/dist/mobile.js +12 -0
- package/dist/nav/flowField.js +58 -0
- package/dist/nav/steering.js +77 -0
- package/dist/net/InterpolationBuffer.js +30 -23
- package/dist/net/LagCompensator.js +100 -0
- package/dist/net/Room.js +122 -43
- package/dist/net/RoomHost.js +13 -4
- package/dist/net/SpatialHash.js +66 -0
- package/dist/types/ai/behaviorTree.d.ts +133 -0
- package/dist/types/ai/behaviorTree.d.ts.map +1 -0
- package/dist/types/ai/buildTree.d.ts +55 -0
- package/dist/types/ai/buildTree.d.ts.map +1 -0
- package/dist/types/audio/spatial.d.ts +107 -0
- package/dist/types/audio/spatial.d.ts.map +1 -0
- package/dist/types/core/Camera.d.ts +8 -0
- package/dist/types/core/Camera.d.ts.map +1 -1
- package/dist/types/core/ObjectFactory.d.ts.map +1 -1
- package/dist/types/core/PixelGrid.d.ts +30 -0
- package/dist/types/core/PixelGrid.d.ts.map +1 -0
- package/dist/types/core/SharpText.d.ts +32 -0
- package/dist/types/core/SharpText.d.ts.map +1 -0
- package/dist/types/core/Stage.d.ts +14 -0
- package/dist/types/core/Stage.d.ts.map +1 -1
- package/dist/types/core/gridPlacement.d.ts +20 -0
- package/dist/types/core/gridPlacement.d.ts.map +1 -0
- package/dist/types/dialogue/DialogueRunner.d.ts +78 -0
- package/dist/types/dialogue/DialogueRunner.d.ts.map +1 -0
- package/dist/types/dialogue/expr.d.ts +12 -0
- package/dist/types/dialogue/expr.d.ts.map +1 -0
- package/dist/types/dialogue/script.d.ts +78 -0
- package/dist/types/dialogue/script.d.ts.map +1 -0
- package/dist/types/dialogue/validateDialogue.d.ts +21 -0
- package/dist/types/dialogue/validateDialogue.d.ts.map +1 -0
- package/dist/types/ecs/prefab.d.ts +84 -0
- package/dist/types/ecs/prefab.d.ts.map +1 -0
- package/dist/types/electron/webPatcher.d.ts +4 -1
- package/dist/types/electron/webPatcher.d.ts.map +1 -1
- package/dist/types/index.d.ts +18 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/input/Actions.d.ts +14 -0
- package/dist/types/input/Actions.d.ts.map +1 -1
- package/dist/types/input/InputCapture.d.ts +53 -0
- package/dist/types/input/InputCapture.d.ts.map +1 -0
- package/dist/types/input/Keymap.d.ts +12 -6
- package/dist/types/input/Keymap.d.ts.map +1 -1
- package/dist/types/input/inputTape.d.ts +66 -0
- package/dist/types/input/inputTape.d.ts.map +1 -0
- package/dist/types/mobile/backButton.d.ts +30 -0
- package/dist/types/mobile/backButton.d.ts.map +1 -0
- package/dist/types/mobile/capacitor.d.ts +62 -0
- package/dist/types/mobile/capacitor.d.ts.map +1 -0
- package/dist/types/mobile/index.d.ts +4 -0
- package/dist/types/mobile/index.d.ts.map +1 -0
- package/dist/types/mobile/screen.d.ts +27 -0
- package/dist/types/mobile/screen.d.ts.map +1 -0
- package/dist/types/nav/flowField.d.ts +31 -0
- package/dist/types/nav/flowField.d.ts.map +1 -0
- package/dist/types/nav/steering.d.ts +47 -0
- package/dist/types/nav/steering.d.ts.map +1 -0
- package/dist/types/net/InterpolationBuffer.d.ts +5 -0
- package/dist/types/net/InterpolationBuffer.d.ts.map +1 -1
- package/dist/types/net/LagCompensator.d.ts +70 -0
- package/dist/types/net/LagCompensator.d.ts.map +1 -0
- package/dist/types/net/Room.d.ts +72 -3
- package/dist/types/net/Room.d.ts.map +1 -1
- package/dist/types/net/RoomHost.d.ts +8 -3
- package/dist/types/net/RoomHost.d.ts.map +1 -1
- package/dist/types/net/SpatialHash.d.ts +25 -0
- package/dist/types/net/SpatialHash.d.ts.map +1 -0
- package/dist/types/ui/ScrollView.d.ts.map +1 -1
- package/dist/ui/ScrollView.js +10 -8
- package/package.json +5 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** A back handler: true when it used the press (closed a dialog, went up a menu), false to let the next one try. */
|
|
2
|
+
export type BackHandler = () => boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Who answers Android's back button (and the back gesture): the most recently pushed handler first, then the ones
|
|
5
|
+
* under it, then `onRoot` when none took it. A dialog pushes "close me" when it opens and pops it when it closes; a
|
|
6
|
+
* pause menu pushes "resume"; the title screen leaves the press to `onRoot`, which by default asks for a second press
|
|
7
|
+
* to quit, so a stray swipe never ends a run.
|
|
8
|
+
*/
|
|
9
|
+
export declare class BackStack {
|
|
10
|
+
private readonly onRoot;
|
|
11
|
+
private readonly handlers;
|
|
12
|
+
constructor(onRoot?: () => void);
|
|
13
|
+
/** Puts `handler` on top; the returned function takes it off (from anywhere in the stack). */
|
|
14
|
+
push(handler: BackHandler): () => void;
|
|
15
|
+
get size(): number;
|
|
16
|
+
/** A back press: offered from the top down; `onRoot` when none uses it. True when a handler used it. */
|
|
17
|
+
press(): boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface DoubleBackOptions {
|
|
20
|
+
/** A second press within this (ms) quits (default 2000). */
|
|
21
|
+
withinMs?: number;
|
|
22
|
+
/** The first press: tell the player ("press back again to quit"). */
|
|
23
|
+
notify: () => void;
|
|
24
|
+
/** The second: leave (Capacitor's `App.exitApp`, or `minimizeApp` to keep the game alive in the background). */
|
|
25
|
+
exit: () => void;
|
|
26
|
+
now?: () => number;
|
|
27
|
+
}
|
|
28
|
+
/** An `onRoot` that quits on a second back press soon after the first, and tells the player after the first. */
|
|
29
|
+
export declare function doubleBackToExit(options: DoubleBackOptions): () => void;
|
|
30
|
+
//# sourceMappingURL=backButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backButton.d.ts","sourceRoot":"","sources":["../../../src/mobile/backButton.ts"],"names":[],"mappings":"AAAA,oHAAoH;AACpH,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC;AAExC;;;;;GAKG;AACH,qBAAa,SAAS;IAGR,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;gBAEjB,MAAM,GAAE,MAAM,IAAsB;IAEjE,8FAA8F;IAC9F,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,IAAI;IAQtC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,wGAAwG;IACxG,KAAK,IAAI,OAAO;CAOjB;AAED,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,gHAAgH;IAChH,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,gHAAgH;AAChH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAcvE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { BackStack } from './backButton.js';
|
|
2
|
+
/** What a plugin's `addListener` resolves to. */
|
|
3
|
+
export interface ListenerHandle {
|
|
4
|
+
remove(): Promise<void> | void;
|
|
5
|
+
}
|
|
6
|
+
/** The slice of `@capacitor/app`'s `App` the engine uses. */
|
|
7
|
+
export interface AppLike {
|
|
8
|
+
addListener(event: 'backButton', cb: (e: {
|
|
9
|
+
canGoBack: boolean;
|
|
10
|
+
}) => void): Promise<ListenerHandle> | ListenerHandle;
|
|
11
|
+
exitApp(): Promise<void> | void;
|
|
12
|
+
minimizeApp?(): Promise<void> | void;
|
|
13
|
+
getInfo?(): Promise<{
|
|
14
|
+
version: string;
|
|
15
|
+
build: string;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Sends Android's back button to a `BackStack`. Capacitor's own default (the web view going back in its history,
|
|
20
|
+
* then closing the app) is replaced as soon as a listener is added, so the stack decides everything. Resolves to
|
|
21
|
+
* the uninstall.
|
|
22
|
+
*/
|
|
23
|
+
export declare function installBackButton(app: AppLike, stack: BackStack): Promise<() => void>;
|
|
24
|
+
/**
|
|
25
|
+
* The app's native build as a number, for `pickWebUpdate`'s `nativeBuild`: Android's versionCode, iOS's
|
|
26
|
+
* CFBundleVersion (its first number, for "508.1"). `Infinity` where there is no native layer (a browser), so every
|
|
27
|
+
* web update fits; 0 when the build cannot be read, so none that needs native code does.
|
|
28
|
+
*/
|
|
29
|
+
export declare function nativeBuildOf(app: Pick<AppLike, 'getInfo'> | null | undefined): Promise<number>;
|
|
30
|
+
/** Options for `capacitorConfig`: what differs between games. */
|
|
31
|
+
export interface MobileConfigOptions {
|
|
32
|
+
/** Reverse-domain id, as the stores know it ("com.example.mygame"). */
|
|
33
|
+
appId: string;
|
|
34
|
+
appName: string;
|
|
35
|
+
/** The built web, relative to the project (default 'dist'). */
|
|
36
|
+
webDir?: string;
|
|
37
|
+
/** Behind the web view while it loads, and under the safe-area bands (default black). */
|
|
38
|
+
backgroundColor?: string;
|
|
39
|
+
/** Let Chrome's and Safari's inspectors attach (default false: on for a debug build only). */
|
|
40
|
+
debug?: boolean;
|
|
41
|
+
/** Anything else, laid over the defaults (`plugins`, `server`, …). */
|
|
42
|
+
extra?: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A `capacitor.config.ts` for a game, with the defaults a game wants rather than a web page's:
|
|
46
|
+
*
|
|
47
|
+
* - the page is served from `https://localhost` (Android) so cookies, `crypto.subtle` and service workers behave as on
|
|
48
|
+
* the web, and nothing is fetched over plain http;
|
|
49
|
+
* - the web view does not scroll, bounce or zoom on iOS, and draws edge to edge (`contentInset: 'never'`, mind the
|
|
50
|
+
* safe area: `safeAreaInsets`);
|
|
51
|
+
* - the splash screen stays until the game hides it (`SplashScreen.hide()` once the first scene draws), so the player
|
|
52
|
+
* never sees a blank web view;
|
|
53
|
+
* - `@capgo/capacitor-updater` does not update on its own: the engine's `pickWebUpdate` decides.
|
|
54
|
+
*
|
|
55
|
+
* ```ts
|
|
56
|
+
* // capacitor.config.ts
|
|
57
|
+
* import { capacitorConfig } from '1681-engine/mobile';
|
|
58
|
+
* export default capacitorConfig({ appId: 'com.example.mygame', appName: 'My Game', debug: process.env.DEBUG === '1' });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function capacitorConfig(options: MobileConfigOptions): Record<string, unknown>;
|
|
62
|
+
//# sourceMappingURL=capacitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capacitor.d.ts","sourceRoot":"","sources":["../../../src/mobile/capacitor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAQ9C,iDAAiD;AACjD,MAAM,WAAW,cAAc;IAC7B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAChC;AAED,6DAA6D;AAC7D,MAAM,WAAW,OAAO;IACtB,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,cAAc,CAAC;IACpH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACrC,OAAO,CAAC,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAK3F;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CASrG;AAED,iEAAiE;AACjE,MAAM,WAAW,mBAAmB;IAClC,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8FAA8F;IAC9F,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBrF"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { BackStack, doubleBackToExit, type BackHandler, type DoubleBackOptions } from './backButton.js';
|
|
2
|
+
export { installBackButton, nativeBuildOf, capacitorConfig, type AppLike, type ListenerHandle, type MobileConfigOptions } from './capacitor.js';
|
|
3
|
+
export { safeAreaInsets, keepScreenOn, type Insets, type WakeLockLike } from './screen.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mobile/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACrG,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC7I,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Px kept clear at each edge: the notch, the rounded corners, the home bar. */
|
|
2
|
+
export interface Insets {
|
|
3
|
+
top: number;
|
|
4
|
+
right: number;
|
|
5
|
+
bottom: number;
|
|
6
|
+
left: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The safe-area insets as the browser has them now (CSS `env(safe-area-inset-*)`), read through a hidden probe
|
|
10
|
+
* element: what a canvas HUD must keep its buttons out of when the web view is drawn edge to edge. Zeros where
|
|
11
|
+
* there is no document or no notch.
|
|
12
|
+
*/
|
|
13
|
+
export declare function safeAreaInsets(doc?: Document | undefined): Insets;
|
|
14
|
+
/** The slice of the Screen Wake Lock API used, so a test can hand in its own. */
|
|
15
|
+
export interface WakeLockLike {
|
|
16
|
+
request(type: 'screen'): Promise<{
|
|
17
|
+
release(): Promise<void>;
|
|
18
|
+
addEventListener?(type: 'release', cb: () => void): void;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Keeps the screen on while the game runs (a phone dims and locks during a cut scene or a long think otherwise),
|
|
23
|
+
* through the Screen Wake Lock API. The browser drops the lock whenever the page is hidden, so it is asked for again
|
|
24
|
+
* each time the page comes back. Resolves to the release; does nothing where the API is missing or refuses.
|
|
25
|
+
*/
|
|
26
|
+
export declare function keepScreenOn(wakeLock?: WakeLockLike | undefined, doc?: Pick<Document, 'visibilityState' | 'addEventListener' | 'removeEventListener'> | undefined): Promise<() => void>;
|
|
27
|
+
//# sourceMappingURL=screen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../../src/mobile/screen.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,QAAQ,GAAG,SAA+B,GAAG,MAAM,CAatF;AAED,iFAAiF;AACjF,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAC1H;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,QAAQ,GAAE,YAAY,GAAG,SAAmG,EAC5H,GAAG,GAAE,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,kBAAkB,GAAG,qBAAqB,CAAC,GAAG,SAA+B,GACpH,OAAO,CAAC,MAAM,IAAI,CAAC,CA2BrB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type NavGrid, type NavOptions, type TilePoint } from './navGrid.js';
|
|
2
|
+
/**
|
|
3
|
+
* Which way to step from every tile to reach the nearest goal: one search for a whole crowd. A hundred monsters
|
|
4
|
+
* chasing one player cost one flow field a re-plan, where a hundred `findPath`s would cost a hundred searches.
|
|
5
|
+
*/
|
|
6
|
+
export interface FlowField {
|
|
7
|
+
readonly width: number;
|
|
8
|
+
readonly height: number;
|
|
9
|
+
/** Walking cost from each tile (row-major) to its nearest goal, `Infinity` where none can be reached. */
|
|
10
|
+
readonly costs: Float32Array;
|
|
11
|
+
/** The step to take from each tile, an index into `NAV_STEPS`; -1 on a goal and where nothing is reached. */
|
|
12
|
+
readonly steps: Int8Array;
|
|
13
|
+
/** The step from tile (tx, ty) as [dx, dy], or null on a goal, a wall, outside the grid or out of reach. */
|
|
14
|
+
stepAt(tx: number, ty: number): readonly [number, number] | null;
|
|
15
|
+
/** The cost from (tx, ty) to its nearest goal (`Infinity` out of reach or outside the grid). */
|
|
16
|
+
costAt(tx: number, ty: number): number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A flow field towards `goals` (any number: every door out of a burning house), by the same steps, corner rules,
|
|
20
|
+
* costs and end-only tiles `findPath` takes, so a body following it walks the route `findPath` would have found.
|
|
21
|
+
* `maxCost` stops the spread (bodies further off stand still or wander).
|
|
22
|
+
*/
|
|
23
|
+
export declare function flowField(g: NavGrid, goals: readonly TilePoint[], options?: NavOptions & {
|
|
24
|
+
maxCost?: number;
|
|
25
|
+
}): FlowField;
|
|
26
|
+
/**
|
|
27
|
+
* The tiles a body at `from` walks by following the field, to the goal (both ends included), or null when `from` is
|
|
28
|
+
* out of reach. For drawing the route, and for tests; a body steps one tile at a time with `stepAt`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function followField(field: FlowField, from: TilePoint, maxSteps?: number): TilePoint[] | null;
|
|
31
|
+
//# sourceMappingURL=flowField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flowField.d.ts","sourceRoot":"","sources":["../../../src/nav/flowField.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,KAAK,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtG;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yGAAyG;IACzG,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,6GAA6G;IAC7G,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,4GAA4G;IAC5G,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACjE,gGAAgG;IAChG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,GAAE,UAAU,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,SAAS,CA0D7H;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,SAA6B,GAAG,SAAS,EAAE,GAAG,IAAI,CAaxH"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface SteerVec {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
}
|
|
5
|
+
/** A body as steering sees it. */
|
|
6
|
+
export interface SteerAgent {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
vx: number;
|
|
10
|
+
vy: number;
|
|
11
|
+
}
|
|
12
|
+
/** Full speed straight at a point. */
|
|
13
|
+
export declare function seek(agent: SteerAgent, tx: number, ty: number, maxSpeed: number): SteerVec;
|
|
14
|
+
/** Full speed straight away from a point, within `panic` px of it (default always). */
|
|
15
|
+
export declare function flee(agent: SteerAgent, tx: number, ty: number, maxSpeed: number, panic?: number): SteerVec;
|
|
16
|
+
/** Like `seek`, but slowing inside `slowRadius` px so it stops on the point instead of overshooting. */
|
|
17
|
+
export declare function arrive(agent: SteerAgent, tx: number, ty: number, maxSpeed: number, slowRadius: number): SteerVec;
|
|
18
|
+
/**
|
|
19
|
+
* Away from neighbours closer than `radius` px, harder the closer they are: bodies of a crowd stop stacking on one
|
|
20
|
+
* tile. A neighbour exactly on top is pushed off along a direction picked from the pair's places, so two bodies
|
|
21
|
+
* spawned on one spot still part.
|
|
22
|
+
*/
|
|
23
|
+
export declare function separation(agent: SteerAgent, neighbours: Iterable<SteerAgent>, radius: number, strength: number): SteerVec;
|
|
24
|
+
/** Towards the average heading of neighbours within `radius` (a flock turning together). */
|
|
25
|
+
export declare function alignment(agent: SteerAgent, neighbours: Iterable<SteerAgent>, radius: number): SteerVec;
|
|
26
|
+
/** Towards the middle of neighbours within `radius` (a flock keeping together). */
|
|
27
|
+
export declare function cohesion(agent: SteerAgent, neighbours: Iterable<SteerAgent>, radius: number, maxSpeed: number): SteerVec;
|
|
28
|
+
/** What `followFlow` reads: a flow field (`flowField.ts`). */
|
|
29
|
+
export interface StepSource {
|
|
30
|
+
stepAt(tx: number, ty: number): readonly [number, number] | null;
|
|
31
|
+
costAt(tx: number, ty: number): number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Full speed along a flow field from the tile the body stands on. On a goal it brakes to a stop, so a crowd gathers
|
|
35
|
+
* there rather than coasting past. Pushed off the field (into a wall, off the grid, by a crowd's shoving), it heads
|
|
36
|
+
* for the cheapest tile around it that is on the field, so it is never stranded; with none within two tiles, it
|
|
37
|
+
* brakes.
|
|
38
|
+
*/
|
|
39
|
+
export declare function followFlow(agent: SteerAgent, field: StepSource, tileSize: number, maxSpeed: number): SteerVec;
|
|
40
|
+
/** Weighs steering forces, sums them and caps the sum at `maxForce` (px/s of change a step). */
|
|
41
|
+
export declare function combineSteering(maxForce: number, ...weighted: [SteerVec, number][]): SteerVec;
|
|
42
|
+
/**
|
|
43
|
+
* One step of steering applied to a body: velocity changed by `force × dt`, capped at `maxSpeed`, position moved.
|
|
44
|
+
* For bodies with no physics of their own (birds, a crowd of extras); a physics body takes the force instead.
|
|
45
|
+
*/
|
|
46
|
+
export declare function applySteering(agent: SteerAgent, force: SteerVec, maxSpeed: number, dt: number): void;
|
|
47
|
+
//# sourceMappingURL=steering.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"steering.d.ts","sourceRoot":"","sources":["../../../src/nav/steering.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,kCAAkC;AAClC,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAUD,sCAAsC;AACtC,wBAAgB,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAE1F;AAED,uFAAuF;AACvF,wBAAgB,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAW,GAAG,QAAQ,CAK5G;AAED,wGAAwG;AACxG,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,QAAQ,CAMhH;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,CA0B1H;AAED,4FAA4F;AAC5F,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAWvG;AAED,mFAAmF;AACnF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAWxH;AAED,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACjE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;CACxC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAuB7G;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,GAAG,QAAQ,CAa7F;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAUpG"}
|
|
@@ -26,6 +26,11 @@ export declare class InterpolationBuffer {
|
|
|
26
26
|
delayMs?: number, maxExtrapolateMs?: number, keep?: number);
|
|
27
27
|
/** Records every body of a snapshot taken at `time`. */
|
|
28
28
|
push(time: number, updates: readonly EntityUpdate[]): void;
|
|
29
|
+
/**
|
|
30
|
+
* The server time bodies are drawn at when it is `now` (`serverNow()`): what a shot should carry, so a server with
|
|
31
|
+
* lag compensation judges it against the picture the player aimed at.
|
|
32
|
+
*/
|
|
33
|
+
viewTime(now: number): number;
|
|
29
34
|
/** Forgets a body (it left view). */
|
|
30
35
|
remove(id: number): void;
|
|
31
36
|
has(id: number): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InterpolationBuffer.d.ts","sourceRoot":"","sources":["../../../src/net/InterpolationBuffer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAahD,MAAM,WAAW,iBAAiB;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAI5B,yGAAyG;IACzG,QAAQ,CAAC,OAAO;IAChB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI;IANvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;;IAGrD,yGAAyG;IAChG,OAAO,SAAM,EACL,gBAAgB,SAAM,EACtB,IAAI,SAAK;IAG5B,wDAAwD;IACxD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,IAAI;IAe1D,qCAAqC;IACrC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIxB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC;IAI/B,+FAA+F;IAC/F,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;CAqB1D"}
|
|
1
|
+
{"version":3,"file":"InterpolationBuffer.d.ts","sourceRoot":"","sources":["../../../src/net/InterpolationBuffer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAahD,MAAM,WAAW,iBAAiB;IAChC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAI5B,yGAAyG;IACzG,QAAQ,CAAC,OAAO;IAChB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI;IANvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;;IAGrD,yGAAyG;IAChG,OAAO,SAAM,EACL,gBAAgB,SAAM,EACtB,IAAI,SAAK;IAG5B,wDAAwD;IACxD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,IAAI;IAe1D;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAI7B,qCAAqC;IACrC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIxB,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC;IAI/B,+FAA+F;IAC/F,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;CAqB1D"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/** A body's position at one recorded moment. */
|
|
2
|
+
export interface RewoundBody {
|
|
3
|
+
id: number;
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
}
|
|
7
|
+
/** A body a ray passed through: `along` is how far from the ray's start it was met (px). */
|
|
8
|
+
export interface RewoundHit extends RewoundBody {
|
|
9
|
+
along: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Lag compensation for a server: where every body was a moment ago, so a shot is judged against what the shooter saw.
|
|
13
|
+
* A client draws other bodies `delayMs` in the past between two snapshots (`InterpolationBuffer`); the server records
|
|
14
|
+
* the same positions at the same times, when each snapshot goes out, and blends between them the same way, so a
|
|
15
|
+
* rewind lands on the very picture the shooter aimed at, not on where the target has walked to since.
|
|
16
|
+
*
|
|
17
|
+
* How far back a client may ask is capped (`clampTime`): a client that claims an old time to shoot round a corner
|
|
18
|
+
* gets no further back than `maxRewindMs`.
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* // when snapshots go out (RoomHost does this for a Room made with `rewindMs`)
|
|
22
|
+
* lag.record(now, players);
|
|
23
|
+
* // a client's shot, sent with `at: buffer.viewTime(serverNow())`
|
|
24
|
+
* const at = LagCompensator.clampTime(msg.at, now, 250);
|
|
25
|
+
* const hit = lag.alongRay(at, x, y, dx, dy, range, 6, shooterId)[0];
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare class LagCompensator {
|
|
29
|
+
readonly keepMs: number;
|
|
30
|
+
private readonly frames;
|
|
31
|
+
/** `keepMs`: how much history is kept; at least the longest rewind allowed plus a snapshot interval. */
|
|
32
|
+
constructor(keepMs?: number);
|
|
33
|
+
/** The latest recorded time, or -Infinity before any. */
|
|
34
|
+
get newest(): number;
|
|
35
|
+
get oldest(): number;
|
|
36
|
+
/** Records every body's position at `time`. A time not after the last one recorded replaces that frame. */
|
|
37
|
+
record(time: number, bodies: Iterable<{
|
|
38
|
+
readonly id: number;
|
|
39
|
+
readonly x: number;
|
|
40
|
+
readonly y: number;
|
|
41
|
+
}>): void;
|
|
42
|
+
/** Forgets a body everywhere in the history (it left the game, not just the view). */
|
|
43
|
+
forget(id: number): void;
|
|
44
|
+
clear(): void;
|
|
45
|
+
/**
|
|
46
|
+
* A time a client claims it saw, kept within `[now - maxRewindMs, now]`: the window a rewind is honoured in. A
|
|
47
|
+
* claim that is not a finite number is taken as `now` (no rewind).
|
|
48
|
+
*/
|
|
49
|
+
static clampTime(claimed: unknown, now: number, maxRewindMs: number): number;
|
|
50
|
+
/**
|
|
51
|
+
* Where body `id` was at `time`, blended between the frames around it as `InterpolationBuffer` blends; null when
|
|
52
|
+
* the history has no frame of it. Before the oldest frame it is where it was then; after the newest, where it is.
|
|
53
|
+
*/
|
|
54
|
+
at(id: number, time: number): {
|
|
55
|
+
x: number;
|
|
56
|
+
y: number;
|
|
57
|
+
} | null;
|
|
58
|
+
/** Every body in the history at `time`. */
|
|
59
|
+
all(time: number): RewoundBody[];
|
|
60
|
+
/** The bodies whose centre was within `radius` of (x, y) at `time`, nearest first; `except` (the shooter) left out. */
|
|
61
|
+
near(time: number, x: number, y: number, radius: number, except?: number): RewoundBody[];
|
|
62
|
+
/**
|
|
63
|
+
* A hitscan at `time`: the bodies a ray from (x, y) along (dx, dy) passed within `radius` of, before `range` px, in
|
|
64
|
+
* the order it met them. `except` (the shooter) is left out. Walls are the game's to check against the first hit.
|
|
65
|
+
*/
|
|
66
|
+
alongRay(time: number, x: number, y: number, dx: number, dy: number, range: number, radius: number, except?: number): RewoundHit[];
|
|
67
|
+
/** The two frames around `time` and how far between them it is (0 at the first, 1 at the second). */
|
|
68
|
+
private around;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=LagCompensator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LagCompensator.d.ts","sourceRoot":"","sources":["../../../src/net/LagCompensator.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,4FAA4F;AAC5F,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf;AAOD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,cAAc;IAIb,QAAQ,CAAC,MAAM;IAH3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IAEtC,wGAAwG;gBACnF,MAAM,SAAO;IAElC,yDAAyD;IACzD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,2GAA2G;IAC3G,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI;IAY7G,sFAAsF;IACtF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIxB,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM;IAK5E;;;OAGG;IACH,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAM7D,2CAA2C;IAC3C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE;IAahC,uHAAuH;IACvH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE;IAKxF;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,EAAE;IAqBlI,qGAAqG;IACrG,OAAO,CAAC,MAAM;CAaf"}
|
package/dist/types/net/Room.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { InputStep, MovementParams } from './constants.js';
|
|
2
|
+
import { LagCompensator } from './LagCompensator.js';
|
|
2
3
|
import { type CollisionGrid, type MoverState } from './movement.js';
|
|
3
4
|
import { type Snapshot } from './protocol.js';
|
|
4
5
|
export interface RoomPlayer<D = unknown> {
|
|
6
|
+
readonly kind: 'player';
|
|
5
7
|
readonly id: number;
|
|
6
8
|
readonly mover: MoverState;
|
|
7
9
|
/** The game's own data for this player (sent to others in `sp` when they first see it). */
|
|
@@ -19,7 +21,39 @@ export interface RoomPlayer<D = unknown> {
|
|
|
19
21
|
/** Refused inputs (nonsense numbers, a flood): a game may kick past some count. */
|
|
20
22
|
strikes: number;
|
|
21
23
|
}
|
|
22
|
-
|
|
24
|
+
/**
|
|
25
|
+
* A body the server moves itself (a monster, a projectile, a crate): no input, no prediction, sent to players beside
|
|
26
|
+
* them in the same snapshots. The game writes `x`, `y` and the rest as its own simulation runs.
|
|
27
|
+
*/
|
|
28
|
+
export interface RoomBody<B = unknown> {
|
|
29
|
+
readonly kind: 'body';
|
|
30
|
+
readonly id: number;
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
aim: number;
|
|
34
|
+
anim: number;
|
|
35
|
+
hp: number;
|
|
36
|
+
flags: number;
|
|
37
|
+
/** The game's own description of it, sent in `sp` when a player first sees it. */
|
|
38
|
+
data: B;
|
|
39
|
+
}
|
|
40
|
+
/** Anything a snapshot carries: a player or a body the server moves. */
|
|
41
|
+
export type RoomSeen<D = unknown, B = unknown> = RoomPlayer<D> | RoomBody<B>;
|
|
42
|
+
/** Server bodies get ids from here up unless given one, far above the ids `RoomHost` hands players. */
|
|
43
|
+
export declare const BODY_ID_BASE: number;
|
|
44
|
+
/** Who a player is sent: the bodies near it, not the whole room. */
|
|
45
|
+
export interface RoomInterest<D, B = unknown> {
|
|
46
|
+
/** A body comes into view within this many px of the player (centre to centre). */
|
|
47
|
+
radius: number;
|
|
48
|
+
/**
|
|
49
|
+
* And leaves only past `radius + leaveMargin` (default a quarter of `radius`), so a body walking along the edge is
|
|
50
|
+
* not spawned and removed on every snapshot.
|
|
51
|
+
*/
|
|
52
|
+
leaveMargin?: number;
|
|
53
|
+
/** A further test, for what distance alone does not decide (a team's own always, a hidden enemy never). */
|
|
54
|
+
canSee?: (viewer: RoomPlayer<D>, other: RoomSeen<D, B>) => boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface RoomOptions<D, B = unknown> {
|
|
23
57
|
grid: CollisionGrid;
|
|
24
58
|
/** Movement rules a new player starts with. */
|
|
25
59
|
params: MovementParams;
|
|
@@ -35,6 +69,13 @@ export interface RoomOptions<D> {
|
|
|
35
69
|
backlog?: number;
|
|
36
70
|
/** Called after each step a player takes (set aim, anim, flags from it). */
|
|
37
71
|
onStep?: (player: RoomPlayer<D>, step: InputStep) => void;
|
|
72
|
+
/** Send each player only the bodies near it (default: everyone to everyone). */
|
|
73
|
+
interest?: RoomInterest<D, B>;
|
|
74
|
+
/**
|
|
75
|
+
* Keep this many ms of positions for lag compensation (`history`), recorded as each round of snapshots goes out
|
|
76
|
+
* (`record`). Off by default.
|
|
77
|
+
*/
|
|
78
|
+
rewindMs?: number;
|
|
38
79
|
}
|
|
39
80
|
/**
|
|
40
81
|
* An authoritative room for a server: players send input steps, the room applies them with the same `stepMover` the
|
|
@@ -44,17 +85,38 @@ export interface RoomOptions<D> {
|
|
|
44
85
|
* Every step a player sends is applied once, in order; a client cannot move faster by sending more (the queue is
|
|
45
86
|
* capped and drained at most `maxStepsPerTick` a tick), and nonsense input is refused and counted.
|
|
46
87
|
*/
|
|
47
|
-
export declare class Room<D = unknown> {
|
|
88
|
+
export declare class Room<D = unknown, B = unknown> {
|
|
48
89
|
private readonly options;
|
|
49
90
|
readonly players: Map<number, RoomPlayer<D>>;
|
|
91
|
+
/** The bodies the server moves (`addBody`). */
|
|
92
|
+
readonly bodies: Map<number, RoomBody<B>>;
|
|
50
93
|
tick: number;
|
|
94
|
+
/** Past positions for judging shots against what a client saw, when the room was made with `rewindMs`. */
|
|
95
|
+
readonly history: LagCompensator | null;
|
|
96
|
+
/** How far back a client's claimed view time is honoured (`rewindMs`, 0 when off). */
|
|
97
|
+
readonly rewindMs: number;
|
|
51
98
|
private readonly known;
|
|
99
|
+
private readonly hash;
|
|
100
|
+
private readonly nearby;
|
|
52
101
|
private readonly maxQueue;
|
|
53
102
|
private readonly maxSteps;
|
|
54
103
|
private readonly backlog;
|
|
55
|
-
|
|
104
|
+
private nextBodyId;
|
|
105
|
+
constructor(options: RoomOptions<D, B>);
|
|
56
106
|
join(id: number, data: D): RoomPlayer<D>;
|
|
57
107
|
leave(id: number): void;
|
|
108
|
+
/**
|
|
109
|
+
* Records where every body is now, at server time `time`, into `history`; `RoomHost` calls it as each round of
|
|
110
|
+
* snapshots goes out, so the history holds exactly the positions clients interpolate between.
|
|
111
|
+
*/
|
|
112
|
+
record(time: number): void;
|
|
113
|
+
/**
|
|
114
|
+
* Adds a body the server moves, at (x, y), with the game's `data` (what players are told it looks like). Its id
|
|
115
|
+
* is `id`, or the next from `BODY_ID_BASE` up; an id a player or body has is refused.
|
|
116
|
+
*/
|
|
117
|
+
addBody(data: B, x: number, y: number, id?: number): RoomBody<B>;
|
|
118
|
+
/** Takes a body out: players who saw it get it in `rm` with their next snapshot. */
|
|
119
|
+
removeBody(id: number): void;
|
|
58
120
|
/**
|
|
59
121
|
* Input steps `seq`, `seq + 1`, … from a player. Steps already received are skipped (a resend), any step with
|
|
60
122
|
* numbers no client sends refuses the whole message, and steps past a full queue are dropped. Returns false when
|
|
@@ -63,7 +125,14 @@ export declare class Room<D = unknown> {
|
|
|
63
125
|
input(id: number, seq: number, steps: readonly InputStep[]): boolean;
|
|
64
126
|
/** One simulation step for everyone. */
|
|
65
127
|
step(): void;
|
|
128
|
+
/**
|
|
129
|
+
* Moves a player by hand (a teleport, a respawn), and files it in the interest grid at once. Writing `mover.x/y`
|
|
130
|
+
* directly also works; the room then finds it at its new place from the next step.
|
|
131
|
+
*/
|
|
132
|
+
place(id: number, x: number, y: number): void;
|
|
66
133
|
/** The snapshot player `id` should get now. `time` is the server's wall clock (ms). */
|
|
67
134
|
snapshotFor(id: number, time: number): Snapshot | null;
|
|
135
|
+
/** What `me` is sent: itself always; with interest, the rest in range (a known one until past the margin). */
|
|
136
|
+
private visibleTo;
|
|
68
137
|
}
|
|
69
138
|
//# sourceMappingURL=Room.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Room.d.ts","sourceRoot":"","sources":["../../../src/net/Room.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAA0B,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"Room.d.ts","sourceRoot":"","sources":["../../../src/net/Room.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,8 +39,8 @@ export interface RoomHostOptions<D> {
|
|
|
39
39
|
* host.start();
|
|
40
40
|
* ```
|
|
41
41
|
*/
|
|
42
|
-
export declare class RoomHost<D = unknown> {
|
|
43
|
-
readonly room: Room<D>;
|
|
42
|
+
export declare class RoomHost<D = unknown, B = unknown> {
|
|
43
|
+
readonly room: Room<D, B>;
|
|
44
44
|
private readonly options;
|
|
45
45
|
private readonly sockets;
|
|
46
46
|
private readonly joined;
|
|
@@ -51,7 +51,7 @@ export declare class RoomHost<D = unknown> {
|
|
|
51
51
|
private readonly stepMs;
|
|
52
52
|
private readonly snapEvery;
|
|
53
53
|
private readonly now;
|
|
54
|
-
constructor(room: Room<D>, options?: RoomHostOptions<D>);
|
|
54
|
+
constructor(room: Room<D, B>, options?: RoomHostOptions<D>);
|
|
55
55
|
/** A socket connected; returns the id its messages and its close are reported under. */
|
|
56
56
|
connect(socket: HostSocket): number;
|
|
57
57
|
/** A message arrived from socket `id` (text as a string, binary as bytes). */
|
|
@@ -68,6 +68,11 @@ export declare class RoomHost<D = unknown> {
|
|
|
68
68
|
stop(): void;
|
|
69
69
|
/** One step, and the snapshots when they are due. Exposed for tests and for servers that drive their own loop. */
|
|
70
70
|
stepOnce(): void;
|
|
71
|
+
/**
|
|
72
|
+
* The server time a client's claimed view time (`InterpolationBuffer.viewTime`, sent with a shot) is judged at:
|
|
73
|
+
* kept within the room's `rewindMs` of now, so no claim reaches further back. `now` with no history kept.
|
|
74
|
+
*/
|
|
75
|
+
rewindTime(claimed: unknown): number;
|
|
71
76
|
private strike;
|
|
72
77
|
private checkStrikes;
|
|
73
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RoomHost.d.ts","sourceRoot":"","sources":["../../../src/net/RoomHost.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RoomHost.d.ts","sourceRoot":"","sources":["../../../src/net/RoomHost.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC,OAAO,KAAK,EAAiB,aAAa,EAAY,MAAM,YAAY,CAAC;AAEzE,uGAAuG;AACvG,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IACtC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kGAAkG;IAClG,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,KAAK,CAAC,CAAC;IACzC,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IAC3E,4CAA4C;IAC5C,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IAY1C,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAZ1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,SAAS,CAA+C;IAChE,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAGxB,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EACR,OAAO,GAAE,eAAe,CAAC,CAAC,CAAM;IAOnD,wFAAwF;IACxF,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM;IAMnC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI;IAyClE,0BAA0B;IAC1B,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAQ5B,wDAAwD;IACxD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GAAG,IAAI;IAOlF,0GAA0G;IAC1G,KAAK,IAAI,IAAI;IAgBb,IAAI,IAAI,IAAI;IAKZ,kHAAkH;IAClH,QAAQ,IAAI,IAAI;IAYhB;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAIpC,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,YAAY;CAOrB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Points sorted into square cells, for asking who is near a spot without looking at everyone: a room's interest
|
|
3
|
+
* management, a server's hit test. Moving a point within its cell costs a write; across cells, a set delete and add.
|
|
4
|
+
* Pure and transport-free, so the same class serves the client.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SpatialHash {
|
|
7
|
+
readonly cellSize: number;
|
|
8
|
+
private readonly cells;
|
|
9
|
+
private readonly entries;
|
|
10
|
+
/** `cellSize`: world px per cell. About the radius queries ask for keeps a query to a 3×3 block. */
|
|
11
|
+
constructor(cellSize: number);
|
|
12
|
+
get size(): number;
|
|
13
|
+
has(id: number): boolean;
|
|
14
|
+
/** Puts `id` at (x, y), or moves it there. */
|
|
15
|
+
set(id: number, x: number, y: number): void;
|
|
16
|
+
delete(id: number): void;
|
|
17
|
+
clear(): void;
|
|
18
|
+
/** The ids within `radius` of (x, y), edge included, pushed onto `out` in no set order. */
|
|
19
|
+
near(x: number, y: number, radius: number, out?: number[]): number[];
|
|
20
|
+
/** The ids inside the box from (x0, y0) to (x1, y1), edges included. */
|
|
21
|
+
inRect(x0: number, y0: number, x1: number, y1: number, out?: number[]): number[];
|
|
22
|
+
private visit;
|
|
23
|
+
private unlink;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=SpatialHash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpatialHash.d.ts","sourceRoot":"","sources":["../../../src/net/SpatialHash.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,qBAAa,WAAW;IAKV,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAJrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IAEpD,oGAAoG;gBAC/E,QAAQ,EAAE,MAAM;IAIrC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIxB,8CAA8C;IAC9C,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAe3C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAOxB,KAAK,IAAI,IAAI;IAKb,2FAA2F;IAC3F,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE;IAUxE,wEAAwE;IACxE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE;IAOpF,OAAO,CAAC,KAAK;IAkBb,OAAO,CAAC,MAAM;CAMf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScrollView.d.ts","sourceRoot":"","sources":["../../../src/ui/ScrollView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAA8F,MAAM,SAAS,CAAC;AAEhI,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,UAAW,SAAQ,MAAO,YAAW,SAAS;IAmB7C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAlBpC,QAAQ,CAAC,OAAO,8CAAmB;IACnC,uGAAuG;IACvG,cAAc,UAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkD;IACzE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;gBAEhB,OAAO,EAAE,iBAAiB;IAsBvD,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,6EAA6E;IAC7E,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAOjC,kEAAkE;IAClE,OAAO,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"ScrollView.d.ts","sourceRoot":"","sources":["../../../src/ui/ScrollView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAA8F,MAAM,SAAS,CAAC;AAEhI,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,UAAW,SAAQ,MAAO,YAAW,SAAS;IAmB7C,OAAO,CAAC,QAAQ,CAAC,OAAO;IAlBpC,QAAQ,CAAC,OAAO,8CAAmB;IACnC,uGAAuG;IACvG,cAAc,UAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkD;IACzE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;gBAEhB,OAAO,EAAE,iBAAiB;IAsBvD,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,6EAA6E;IAC7E,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAOjC,kEAAkE;IAClE,OAAO,IAAI,IAAI;IAUf,yDAAyD;IACzD,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO;IAQ5B,6FAA6F;IAC7F,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAO9B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAQlB,OAAO,IAAI,IAAI;IAKxB,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,OAAO;IAef,SAAS,CAAC,MAAM,IAAI,IAAI;CA0BzB"}
|
package/dist/ui/ScrollView.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Sprite as a, Texture as l, Rectangle as
|
|
1
|
+
import { Sprite as a, Texture as l, Rectangle as n, Container as c, Graphics as f } from "pixi.js";
|
|
2
2
|
import { clampScroll as p, scrollIntoView as d, stepFling as g, maxScroll as u } from "./layout/scroll.js";
|
|
3
|
-
import { Widget as
|
|
4
|
-
class w extends
|
|
3
|
+
import { Widget as r } from "./Widget.js";
|
|
4
|
+
class w extends r {
|
|
5
5
|
constructor(t) {
|
|
6
6
|
super(), this.options = t, this.addChild(this.content, this.clip), this.content.mask = this.clip;
|
|
7
7
|
const s = t.barColor === void 0 ? 16777215 : t.barColor;
|
|
8
|
-
this.bar = s === null ? null : new a(l.WHITE), this.bar && (this.bar.tint = s, this.bar.alpha = 0.4, this.addChild(this.bar)), this.makeInteractive(), this.hitArea = new
|
|
8
|
+
this.bar = s === null ? null : new a(l.WHITE), this.bar && (this.bar.tint = s, this.bar.alpha = 0.4, this.addChild(this.bar)), this.makeInteractive(), this.hitArea = new n(0, 0, 0, 0), this.on("wheel", (i) => {
|
|
9
9
|
const o = t.wheelStep ?? 48, e = Math.max(-o, Math.min(o, i.deltaY));
|
|
10
10
|
this.scrollTo(this.offset + e) && i.stopPropagation();
|
|
11
11
|
}), this.on("pointerdown", (i) => this.dragStart(i)), this.resize(t.width, t.height);
|
|
@@ -40,8 +40,10 @@ class w extends n {
|
|
|
40
40
|
}
|
|
41
41
|
/** Measures the content's drawn height; call after filling it. */
|
|
42
42
|
measure() {
|
|
43
|
-
const t = this.content.
|
|
44
|
-
|
|
43
|
+
const t = this.content.mask;
|
|
44
|
+
this.content.mask = null;
|
|
45
|
+
const s = this.content.getLocalBounds();
|
|
46
|
+
return this.content.mask = t, this.setContentHeight(s.maxY);
|
|
45
47
|
}
|
|
46
48
|
/** Scrolls to `y`, kept in range; true when it moved. */
|
|
47
49
|
scrollTo(t) {
|
|
@@ -50,7 +52,7 @@ class w extends n {
|
|
|
50
52
|
}
|
|
51
53
|
/** Brings a child into view (the focus manager calls it when a widget inside is focused). */
|
|
52
54
|
reveal(t) {
|
|
53
|
-
const s = this.content.toLocal(t.getGlobalPosition()).y, i = t instanceof
|
|
55
|
+
const s = this.content.toLocal(t.getGlobalPosition()).y, i = t instanceof r ? t.boxHeight : t.getLocalBounds().maxY;
|
|
54
56
|
this.velocity = 0, this.scrollTo(d(this.offset, s, i, this.boxH, this.contentH));
|
|
55
57
|
}
|
|
56
58
|
tick(t) {
|
|
@@ -79,7 +81,7 @@ class w extends n {
|
|
|
79
81
|
}
|
|
80
82
|
redraw() {
|
|
81
83
|
const t = this.boxW, s = this.boxH;
|
|
82
|
-
(t !== this.clipW || s !== this.clipH) && (this.clipW = t, this.clipH = s, this.clip.clear().rect(0, 0, t, s).fill(16777215)), this.hitArea instanceof
|
|
84
|
+
(t !== this.clipW || s !== this.clipH) && (this.clipW = t, this.clipH = s, this.clip.clear().rect(0, 0, t, s).fill(16777215)), this.hitArea instanceof n && (this.hitArea.width = t, this.hitArea.height = s);
|
|
83
85
|
const i = this.host?.pixelPerfect ?? !1;
|
|
84
86
|
if (this.content.y = i ? -Math.round(this.offset) : -this.offset, this.bar) {
|
|
85
87
|
const o = u(this.contentH, s);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "1681-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "A 2D game engine on PixiJS 8 for any art style: scenes and a fast ECS, a fixed-step loop, asset loading, Tiled maps, sprite animation, input actions, camera follow, audio and deterministic, server-replayable movement, plus Dither, an optional pixel-art module (pixel-perfect effects, dithered lighting).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -53,6 +53,10 @@
|
|
|
53
53
|
"default": "./dist/cjs/electron/index.js"
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
|
+
"./mobile": {
|
|
57
|
+
"types": "./dist/types/mobile/index.d.ts",
|
|
58
|
+
"import": "./dist/mobile.js"
|
|
59
|
+
},
|
|
56
60
|
"./package.json": "./package.json"
|
|
57
61
|
},
|
|
58
62
|
"scripts": {
|