@rpgjs/client 5.0.0-alpha.2 → 5.0.0-alpha.20
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/dist/Game/AnimationManager.d.ts +8 -0
- package/dist/Game/Map.d.ts +7 -1
- package/dist/Gui/Gui.d.ts +128 -5
- package/dist/RpgClient.d.ts +217 -59
- package/dist/RpgClientEngine.d.ts +345 -6
- package/dist/Sound.d.ts +199 -0
- package/dist/components/animations/index.d.ts +4 -0
- package/dist/components/dynamics/parse-value.d.ts +1 -0
- package/dist/components/gui/index.d.ts +3 -3
- package/dist/components/index.d.ts +3 -1
- package/dist/components/prebuilt/index.d.ts +18 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/index10.js +149 -4
- package/dist/index10.js.map +1 -1
- package/dist/index11.js +21 -7
- package/dist/index11.js.map +1 -1
- package/dist/index12.js +6 -4
- package/dist/index12.js.map +1 -1
- package/dist/index13.js +11 -14
- package/dist/index13.js.map +1 -1
- package/dist/index14.js +8 -40
- package/dist/index14.js.map +1 -1
- package/dist/index15.js +187 -180
- package/dist/index15.js.map +1 -1
- package/dist/index16.js +104 -7
- package/dist/index16.js.map +1 -1
- package/dist/index17.js +82 -372
- package/dist/index17.js.map +1 -1
- package/dist/index18.js +361 -26
- package/dist/index18.js.map +1 -1
- package/dist/index19.js +46 -20
- package/dist/index19.js.map +1 -1
- package/dist/index2.js +683 -32
- package/dist/index2.js.map +1 -1
- package/dist/index20.js +5 -2417
- package/dist/index20.js.map +1 -1
- package/dist/index21.js +383 -97
- package/dist/index21.js.map +1 -1
- package/dist/index22.js +41 -104
- package/dist/index22.js.map +1 -1
- package/dist/index23.js +21 -67
- package/dist/index23.js.map +1 -1
- package/dist/index24.js +2632 -20
- package/dist/index24.js.map +1 -1
- package/dist/index25.js +107 -34
- package/dist/index25.js.map +1 -1
- package/dist/index26.js +69 -3
- package/dist/index26.js.map +1 -1
- package/dist/index27.js +17 -318
- package/dist/index27.js.map +1 -1
- package/dist/index28.js +24 -22
- package/dist/index28.js.map +1 -1
- package/dist/index29.js +92 -8
- package/dist/index29.js.map +1 -1
- package/dist/index3.js +68 -8
- package/dist/index3.js.map +1 -1
- package/dist/index30.js +37 -7
- package/dist/index30.js.map +1 -1
- package/dist/index31.js +18 -168
- package/dist/index31.js.map +1 -1
- package/dist/index32.js +3 -499
- package/dist/index32.js.map +1 -1
- package/dist/index33.js +332 -9
- package/dist/index33.js.map +1 -1
- package/dist/index34.js +24 -4400
- package/dist/index34.js.map +1 -1
- package/dist/index35.js +6 -311
- package/dist/index35.js.map +1 -1
- package/dist/index36.js +8 -88
- package/dist/index36.js.map +1 -1
- package/dist/index37.js +182 -56
- package/dist/index37.js.map +1 -1
- package/dist/index38.js +500 -16
- package/dist/index38.js.map +1 -1
- package/dist/index39.js +10 -18
- package/dist/index39.js.map +1 -1
- package/dist/index4.js +23 -5
- package/dist/index4.js.map +1 -1
- package/dist/index40.js +7 -0
- package/dist/index40.js.map +1 -0
- package/dist/index41.js +3690 -0
- package/dist/index41.js.map +1 -0
- package/dist/index42.js +77 -0
- package/dist/index42.js.map +1 -0
- package/dist/index43.js +6 -0
- package/dist/index43.js.map +1 -0
- package/dist/index44.js +20 -0
- package/dist/index44.js.map +1 -0
- package/dist/index45.js +146 -0
- package/dist/index45.js.map +1 -0
- package/dist/index46.js +12 -0
- package/dist/index46.js.map +1 -0
- package/dist/index47.js +113 -0
- package/dist/index47.js.map +1 -0
- package/dist/index48.js +136 -0
- package/dist/index48.js.map +1 -0
- package/dist/index49.js +137 -0
- package/dist/index49.js.map +1 -0
- package/dist/index5.js +2 -1
- package/dist/index5.js.map +1 -1
- package/dist/index50.js +112 -0
- package/dist/index50.js.map +1 -0
- package/dist/index51.js +141 -0
- package/dist/index51.js.map +1 -0
- package/dist/index52.js +9 -0
- package/dist/index52.js.map +1 -0
- package/dist/index53.js +54 -0
- package/dist/index53.js.map +1 -0
- package/dist/index6.js +1 -1
- package/dist/index6.js.map +1 -1
- package/dist/index7.js +11 -3
- package/dist/index7.js.map +1 -1
- package/dist/index8.js +68 -7
- package/dist/index8.js.map +1 -1
- package/dist/index9.js +230 -15
- package/dist/index9.js.map +1 -1
- package/dist/presets/animation.d.ts +31 -0
- package/dist/presets/faceset.d.ts +30 -0
- package/dist/presets/index.d.ts +103 -0
- package/dist/presets/lpc.d.ts +89 -0
- package/dist/services/loadMap.d.ts +123 -2
- package/dist/services/mmorpg.d.ts +9 -4
- package/dist/services/standalone.d.ts +51 -2
- package/package.json +22 -18
- package/src/Game/{EffectManager.ts → AnimationManager.ts} +3 -2
- package/src/Game/Map.ts +20 -2
- package/src/Game/Object.ts +163 -9
- package/src/Gui/Gui.ts +300 -17
- package/src/RpgClient.ts +222 -58
- package/src/RpgClientEngine.ts +804 -36
- package/src/Sound.ts +253 -0
- package/src/components/{effects → animations}/animation.ce +3 -6
- package/src/components/{effects → animations}/index.ts +1 -1
- package/src/components/character.ce +165 -37
- package/src/components/dynamics/parse-value.ts +80 -0
- package/src/components/dynamics/text.ce +183 -0
- package/src/components/gui/box.ce +17 -0
- package/src/components/gui/dialogbox/index.ce +73 -35
- package/src/components/gui/dialogbox/selection.ce +16 -1
- package/src/components/gui/index.ts +3 -4
- package/src/components/index.ts +5 -1
- package/src/components/prebuilt/hp-bar.ce +255 -0
- package/src/components/prebuilt/index.ts +21 -0
- package/src/components/scenes/draw-map.ce +6 -23
- package/src/components/scenes/event-layer.ce +9 -3
- package/src/core/setup.ts +2 -0
- package/src/index.ts +5 -2
- package/src/module.ts +72 -6
- package/src/presets/animation.ts +46 -0
- package/src/presets/faceset.ts +60 -0
- package/src/presets/index.ts +7 -1
- package/src/presets/lpc.ts +108 -0
- package/src/services/loadMap.ts +132 -3
- package/src/services/mmorpg.ts +27 -5
- package/src/services/standalone.ts +68 -6
- package/tsconfig.json +1 -1
- package/vite.config.ts +1 -1
- package/dist/Game/EffectManager.d.ts +0 -5
- package/dist/components/effects/index.d.ts +0 -4
- package/src/components/scenes/element-map.ce +0 -23
- /package/src/components/{effects → animations}/hit.ce +0 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export declare const LPCSpritesheetPreset: (options: {
|
|
2
|
+
id: string;
|
|
3
|
+
imageSource: string;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
ratio?: number;
|
|
7
|
+
}) => {
|
|
8
|
+
id: string;
|
|
9
|
+
image: string;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
opacity: number;
|
|
13
|
+
rectWidth: number;
|
|
14
|
+
rectHeight: number;
|
|
15
|
+
framesWidth: number;
|
|
16
|
+
framesHeight: number;
|
|
17
|
+
spriteRealSize: {
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
};
|
|
21
|
+
textures: {
|
|
22
|
+
attack3?: {
|
|
23
|
+
offset: {
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
};
|
|
27
|
+
rectWidth: number;
|
|
28
|
+
rectHeight: number;
|
|
29
|
+
framesWidth: number;
|
|
30
|
+
framesHeight: number;
|
|
31
|
+
animations: ({ direction }: {
|
|
32
|
+
direction: any;
|
|
33
|
+
}) => any[];
|
|
34
|
+
} | undefined;
|
|
35
|
+
stand: {
|
|
36
|
+
offset: {
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
};
|
|
40
|
+
animations: ({ direction }: {
|
|
41
|
+
direction: any;
|
|
42
|
+
}) => {
|
|
43
|
+
time: number;
|
|
44
|
+
frameX: number;
|
|
45
|
+
frameY: number;
|
|
46
|
+
}[][];
|
|
47
|
+
};
|
|
48
|
+
walk: {
|
|
49
|
+
offset: {
|
|
50
|
+
x: number;
|
|
51
|
+
y: number;
|
|
52
|
+
};
|
|
53
|
+
framesWidth: number;
|
|
54
|
+
framesHeight: number;
|
|
55
|
+
animations: ({ direction }: {
|
|
56
|
+
direction: any;
|
|
57
|
+
}) => any[];
|
|
58
|
+
};
|
|
59
|
+
attack: {
|
|
60
|
+
offset: {
|
|
61
|
+
x: number;
|
|
62
|
+
y: number;
|
|
63
|
+
};
|
|
64
|
+
framesWidth: number;
|
|
65
|
+
framesHeight: number;
|
|
66
|
+
animations: ({ direction }: {
|
|
67
|
+
direction: any;
|
|
68
|
+
}) => any[];
|
|
69
|
+
};
|
|
70
|
+
skill: {
|
|
71
|
+
framesWidth: number;
|
|
72
|
+
framesHeight: number;
|
|
73
|
+
animations: ({ direction }: {
|
|
74
|
+
direction: any;
|
|
75
|
+
}) => any[];
|
|
76
|
+
};
|
|
77
|
+
attack2: {
|
|
78
|
+
offset: {
|
|
79
|
+
x: number;
|
|
80
|
+
y: number;
|
|
81
|
+
};
|
|
82
|
+
framesWidth: number;
|
|
83
|
+
framesHeight: number;
|
|
84
|
+
animations: ({ direction }: {
|
|
85
|
+
direction: any;
|
|
86
|
+
}) => any[];
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
};
|
|
@@ -1,14 +1,135 @@
|
|
|
1
1
|
import { Context } from '@signe/di';
|
|
2
2
|
export declare const LoadMapToken = "LoadMapToken";
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Represents the structure of map data that should be returned by the load map callback.
|
|
5
|
+
* This interface defines all the properties that can be provided when loading a custom map.
|
|
6
|
+
*
|
|
7
|
+
* @interface MapData
|
|
8
|
+
*/
|
|
9
|
+
type MapData = {
|
|
10
|
+
/** Raw map data that will be passed to the map component */
|
|
11
|
+
data: any;
|
|
12
|
+
/** CanvasEngine component that will render the map */
|
|
13
|
+
component: any;
|
|
14
|
+
/** Optional map width in pixels, used for viewport calculations */
|
|
15
|
+
width?: number;
|
|
16
|
+
/** Optional map height in pixels, used for viewport calculations */
|
|
17
|
+
height?: number;
|
|
18
|
+
/** Optional map events data (NPCs, interactive objects, etc.) */
|
|
19
|
+
events?: any;
|
|
20
|
+
/** Optional map identifier, defaults to the mapId parameter if not provided */
|
|
21
|
+
id?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Callback function type for loading map data.
|
|
25
|
+
* This function receives a map ID and should return either a MapData object directly
|
|
26
|
+
* or a Promise that resolves to a MapData object.
|
|
27
|
+
*
|
|
28
|
+
* @callback LoadMapOptions
|
|
29
|
+
* @param {string} mapId - The identifier of the map to load
|
|
30
|
+
* @returns {Promise<MapData> | MapData} The map data object or a promise resolving to it
|
|
31
|
+
*/
|
|
32
|
+
export type LoadMapOptions = (mapId: string) => Promise<MapData> | MapData;
|
|
4
33
|
export declare class LoadMapService {
|
|
5
34
|
private context;
|
|
6
35
|
private options;
|
|
7
36
|
private updateMapService;
|
|
8
37
|
constructor(context: Context, options: LoadMapOptions);
|
|
9
|
-
load(mapId: string): Promise<
|
|
38
|
+
load(mapId: string): Promise<MapData>;
|
|
10
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Creates a dependency injection configuration for custom map loading on the client side.
|
|
42
|
+
*
|
|
43
|
+
* This function allows you to customize how maps are loaded and displayed by providing
|
|
44
|
+
* a callback that defines custom map data and rendering components. It's designed to work
|
|
45
|
+
* with the RPG-JS dependency injection system and enables integration of custom map formats
|
|
46
|
+
* like Tiled TMX files or any other map data structure.
|
|
47
|
+
*
|
|
48
|
+
* The function sets up the necessary service providers for map loading, including:
|
|
49
|
+
* - UpdateMapToken: Handles map updates in the client context
|
|
50
|
+
* - LoadMapToken: Provides the LoadMapService with your custom loading logic
|
|
51
|
+
*
|
|
52
|
+
* **Design Concept:**
|
|
53
|
+
* The function follows the provider pattern, creating a modular way to inject custom
|
|
54
|
+
* map loading behavior into the RPG-JS client engine. It separates the concern of
|
|
55
|
+
* map data fetching from map rendering, allowing developers to focus on their specific
|
|
56
|
+
* map format while leveraging the engine's rendering capabilities.
|
|
57
|
+
*
|
|
58
|
+
* @param {LoadMapOptions} options - Callback function that handles map loading logic
|
|
59
|
+
* @returns {Array<Object>} Array of dependency injection provider configurations
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* import { provideLoadMap } from '@rpgjs/client'
|
|
64
|
+
* import { createModule } from '@rpgjs/common'
|
|
65
|
+
* import MyTiledMapComponent from './MyTiledMapComponent.ce'
|
|
66
|
+
*
|
|
67
|
+
* // Basic usage with JSON map data
|
|
68
|
+
* export function provideCustomMap() {
|
|
69
|
+
* return createModule("CustomMap", [
|
|
70
|
+
* provideLoadMap(async (mapId) => {
|
|
71
|
+
* const response = await fetch(`/maps/${mapId}.json`)
|
|
72
|
+
* const mapData = await response.json()
|
|
73
|
+
*
|
|
74
|
+
* return {
|
|
75
|
+
* data: mapData,
|
|
76
|
+
* component: MyTiledMapComponent,
|
|
77
|
+
* width: mapData.width,
|
|
78
|
+
* height: mapData.height,
|
|
79
|
+
* events: mapData.events
|
|
80
|
+
* }
|
|
81
|
+
* })
|
|
82
|
+
* ])
|
|
83
|
+
* }
|
|
84
|
+
*
|
|
85
|
+
* // Advanced usage with Tiled TMX files
|
|
86
|
+
* export function provideTiledMap() {
|
|
87
|
+
* return createModule("TiledMap", [
|
|
88
|
+
* provideLoadMap(async (mapId) => {
|
|
89
|
+
* // Load TMX file
|
|
90
|
+
* const tmxResponse = await fetch(`/tiled/${mapId}.tmx`)
|
|
91
|
+
* const tmxData = await tmxResponse.text()
|
|
92
|
+
*
|
|
93
|
+
* // Parse TMX data (using a TMX parser)
|
|
94
|
+
* const parsedMap = parseTMX(tmxData)
|
|
95
|
+
*
|
|
96
|
+
* return {
|
|
97
|
+
* data: parsedMap,
|
|
98
|
+
* component: TiledMapRenderer,
|
|
99
|
+
* width: parsedMap.width * parsedMap.tilewidth,
|
|
100
|
+
* height: parsedMap.height * parsedMap.tileheight,
|
|
101
|
+
* events: parsedMap.objectGroups?.find(g => g.name === 'events')?.objects
|
|
102
|
+
* }
|
|
103
|
+
* })
|
|
104
|
+
* ])
|
|
105
|
+
* }
|
|
106
|
+
*
|
|
107
|
+
* // Synchronous usage for static maps
|
|
108
|
+
* export function provideStaticMap() {
|
|
109
|
+
* return createModule("StaticMap", [
|
|
110
|
+
* provideLoadMap((mapId) => {
|
|
111
|
+
* const staticMaps = {
|
|
112
|
+
* 'town': { tiles: [...], npcs: [...] },
|
|
113
|
+
* 'dungeon': { tiles: [...], monsters: [...] }
|
|
114
|
+
* }
|
|
115
|
+
*
|
|
116
|
+
* return {
|
|
117
|
+
* data: staticMaps[mapId],
|
|
118
|
+
* component: StaticMapComponent,
|
|
119
|
+
* width: 800,
|
|
120
|
+
* height: 600
|
|
121
|
+
* }
|
|
122
|
+
* })
|
|
123
|
+
* ])
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @since 4.0.0
|
|
128
|
+
* @see {@link LoadMapOptions} for callback function signature
|
|
129
|
+
* @see {@link MapData} for return data structure
|
|
130
|
+
*/
|
|
11
131
|
export declare function provideLoadMap(options: LoadMapOptions): {
|
|
12
132
|
provide: string;
|
|
13
133
|
useFactory: (context: Context) => void;
|
|
14
134
|
}[];
|
|
135
|
+
export {};
|
|
@@ -4,17 +4,22 @@ import { RpgClientEngine } from '../RpgClientEngine';
|
|
|
4
4
|
import { AbstractWebsocket } from './AbstractSocket';
|
|
5
5
|
import { UpdateMapService } from '@rpgjs/common';
|
|
6
6
|
interface MmorpgOptions {
|
|
7
|
-
host
|
|
7
|
+
host?: string;
|
|
8
8
|
}
|
|
9
9
|
declare class BridgeWebsocket extends AbstractWebsocket {
|
|
10
10
|
protected context: Context;
|
|
11
11
|
private options;
|
|
12
12
|
private socket;
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
private privateId;
|
|
14
|
+
constructor(context: Context, options?: MmorpgOptions);
|
|
15
|
+
connection(listeners?: (data: any) => void): Promise<void>;
|
|
15
16
|
on(key: string, callback: (data: any) => void): void;
|
|
16
17
|
off(event: string, callback: (data: any) => void): void;
|
|
17
18
|
emit(event: string, data: any): void;
|
|
19
|
+
updateProperties({ room }: {
|
|
20
|
+
room: any;
|
|
21
|
+
}): void;
|
|
22
|
+
reconnect(listeners?: (data: any) => void): Promise<void>;
|
|
18
23
|
}
|
|
19
24
|
declare class UpdateMapStandaloneService extends UpdateMapService {
|
|
20
25
|
protected context: Context;
|
|
@@ -22,7 +27,7 @@ declare class UpdateMapStandaloneService extends UpdateMapService {
|
|
|
22
27
|
constructor(context: Context, options: MmorpgOptions);
|
|
23
28
|
update(map: any): Promise<void>;
|
|
24
29
|
}
|
|
25
|
-
export declare function provideMmorpg(options: MmorpgOptions): (typeof
|
|
30
|
+
export declare function provideMmorpg(options: MmorpgOptions): (typeof RpgClientEngine | typeof RpgGui | {
|
|
26
31
|
provide: string;
|
|
27
32
|
useFactory: (context: Context) => BridgeWebsocket;
|
|
28
33
|
} | {
|
|
@@ -8,21 +8,70 @@ declare class BridgeWebsocket extends AbstractWebsocket {
|
|
|
8
8
|
private server;
|
|
9
9
|
private room;
|
|
10
10
|
private socket;
|
|
11
|
+
private rooms;
|
|
11
12
|
constructor(context: Context, server: any);
|
|
12
13
|
connection(listeners?: (data: any) => void): Promise<any>;
|
|
14
|
+
private _connection;
|
|
13
15
|
on(key: string, callback: (data: any) => void): void;
|
|
14
16
|
off(event: string, callback: (data: any) => void): void;
|
|
15
17
|
emit(event: string, data: any): void;
|
|
18
|
+
/**
|
|
19
|
+
* Update underlying connection properties before a reconnect
|
|
20
|
+
*
|
|
21
|
+
* Design
|
|
22
|
+
* - Dynamically register a factory for the requested room to ensure a fresh server instance
|
|
23
|
+
* - Swap the internal ServerIo to target the new room
|
|
24
|
+
*
|
|
25
|
+
* @param params - Properties to update
|
|
26
|
+
* @param params.room - The target room id (e.g. `map-simplemap2`)
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* websocket.updateProperties({ room: 'map-simplemap2' })
|
|
31
|
+
* await websocket.reconnect()
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
16
34
|
updateProperties({ room }: {
|
|
17
35
|
room: any;
|
|
18
36
|
}): void;
|
|
37
|
+
/**
|
|
38
|
+
* Reconnect the client to the current Party room
|
|
39
|
+
*
|
|
40
|
+
* Design
|
|
41
|
+
* - Must be called after `updateProperties()` when switching rooms
|
|
42
|
+
* - Rebuilds the client <-> server bridge and re-triggers connection listeners
|
|
43
|
+
*
|
|
44
|
+
* @param listeners - Optional callback to re-bind event handlers on the new socket
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* websocket.updateProperties({ room: 'map-dungeon' })
|
|
49
|
+
* await websocket.reconnect((socket) => {
|
|
50
|
+
* // re-bind events here
|
|
51
|
+
* })
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
19
54
|
reconnect(listeners?: (data: any) => void): Promise<void>;
|
|
20
55
|
}
|
|
21
56
|
declare class UpdateMapStandaloneService extends UpdateMapService {
|
|
22
57
|
private server;
|
|
23
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Update the current room map data on the server side
|
|
60
|
+
*
|
|
61
|
+
* Design
|
|
62
|
+
* - Uses the in-memory server instance stored in context (standalone mode)
|
|
63
|
+
* - Builds a local HTTP-like request to the current Party room endpoint
|
|
64
|
+
*
|
|
65
|
+
* @param map - The map payload to apply on the server
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* await updateMapService.update({ width: 1024, height: 768, events: [] })
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
update(map: any): Promise<void>;
|
|
24
73
|
}
|
|
25
|
-
export declare function provideRpg(server: any): (typeof
|
|
74
|
+
export declare function provideRpg(server: any): (typeof RpgClientEngine | typeof RpgGui | {
|
|
26
75
|
provide: string;
|
|
27
76
|
useFactory: (context: Context) => BridgeWebsocket;
|
|
28
77
|
useClass?: undefined;
|
package/package.json
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpgjs/client",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.20",
|
|
4
4
|
"description": "RPGJS is a framework for creating RPG/MMORPG games",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"dev": "vite build --watch",
|
|
12
|
-
"build": "vite build"
|
|
13
|
-
},
|
|
14
10
|
"keywords": [
|
|
15
11
|
"rpg",
|
|
16
12
|
"game",
|
|
@@ -20,21 +16,29 @@
|
|
|
20
16
|
],
|
|
21
17
|
"author": "Samuel Ronce",
|
|
22
18
|
"license": "MIT",
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"@canvasengine/presets": "*",
|
|
21
|
+
"canvasengine": "*",
|
|
22
|
+
"pixi.js": "^8.9.2"
|
|
23
|
+
},
|
|
23
24
|
"dependencies": {
|
|
24
|
-
"@
|
|
25
|
-
"@rpgjs/common": "
|
|
26
|
-
"@
|
|
27
|
-
"@signe/
|
|
28
|
-
"@signe/
|
|
29
|
-
"
|
|
30
|
-
"pixi.js": "^8.10.1",
|
|
25
|
+
"@rpgjs/client": "5.0.0-alpha.20",
|
|
26
|
+
"@rpgjs/common": "5.0.0-alpha.20",
|
|
27
|
+
"@rpgjs/server": "5.0.0-alpha.20",
|
|
28
|
+
"@signe/di": "^2.5.1",
|
|
29
|
+
"@signe/room": "^2.5.1",
|
|
30
|
+
"@signe/sync": "^2.5.1",
|
|
31
31
|
"rxjs": "^7.8.2"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@canvasengine/compiler": "2.0.0-beta.
|
|
35
|
-
"vite": "^
|
|
36
|
-
"vite-plugin-dts": "^4.5.
|
|
37
|
-
"vitest": "^
|
|
34
|
+
"@canvasengine/compiler": "2.0.0-beta.34",
|
|
35
|
+
"vite": "^7.2.4",
|
|
36
|
+
"vite-plugin-dts": "^4.5.4",
|
|
37
|
+
"vitest": "^4.0.14"
|
|
38
38
|
},
|
|
39
|
-
"type": "module"
|
|
40
|
-
|
|
39
|
+
"type": "module",
|
|
40
|
+
"scripts": {
|
|
41
|
+
"dev": "vite build --watch",
|
|
42
|
+
"build": "vite build"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { generateUID, RpgCommonPlayer } from "@rpgjs/common";
|
|
2
2
|
import { signal } from "canvasengine";
|
|
3
3
|
|
|
4
|
-
export class
|
|
4
|
+
export class AnimationManager {
|
|
5
5
|
current = signal<any[]>([]);
|
|
6
6
|
|
|
7
|
-
displayEffect(params: any, player: RpgCommonPlayer) {
|
|
7
|
+
displayEffect(params: any, player: RpgCommonPlayer | { x: number, y: number }) {
|
|
8
8
|
const id = generateUID();
|
|
9
9
|
this.current().push({
|
|
10
10
|
...params,
|
|
11
11
|
id,
|
|
12
12
|
x: player.x,
|
|
13
13
|
y: player.y,
|
|
14
|
+
object: player,
|
|
14
15
|
onFinish: () => {
|
|
15
16
|
const index = this.current().findIndex((value) => value.id === id);
|
|
16
17
|
this.current().splice(index, 1);
|
package/src/Game/Map.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import { RpgCommonMap } from "@rpgjs/common";
|
|
2
2
|
import { sync, users } from "@signe/sync";
|
|
3
3
|
import { RpgClientPlayer } from "./Player";
|
|
4
|
-
import { Signal, signal } from "canvasengine";
|
|
4
|
+
import { Signal, signal, computed } from "canvasengine";
|
|
5
5
|
import { RpgClientEvent } from "./Event";
|
|
6
|
+
import { RpgClientEngine } from "../RpgClientEngine";
|
|
7
|
+
import { inject } from "../core/inject";
|
|
6
8
|
|
|
7
|
-
export class RpgClientMap extends RpgCommonMap<
|
|
9
|
+
export class RpgClientMap extends RpgCommonMap<any> {
|
|
10
|
+
engine: RpgClientEngine = inject(RpgClientEngine)
|
|
8
11
|
@users(RpgClientPlayer) players = signal<Record<string, RpgClientPlayer>>({});
|
|
9
12
|
@sync(RpgClientEvent) events = signal<Record<string, RpgClientEvent>>({});
|
|
13
|
+
currentPlayer = computed(() => this.players()[this.engine.playerIdSignal()!])
|
|
14
|
+
|
|
15
|
+
getCurrentPlayer() {
|
|
16
|
+
return this.currentPlayer()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
reset() {
|
|
20
|
+
this.players.set({})
|
|
21
|
+
this.events.set({})
|
|
22
|
+
this.clearPhysic()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
stepPredictionTick(): void {
|
|
26
|
+
this.forceSingleTick();
|
|
27
|
+
}
|
|
10
28
|
}
|
package/src/Game/Object.ts
CHANGED
|
@@ -1,16 +1,170 @@
|
|
|
1
|
-
import { RpgCommonPlayer } from "@rpgjs/common";
|
|
1
|
+
import { Hooks, ModulesToken, RpgCommonPlayer } from "@rpgjs/common";
|
|
2
2
|
import { trigger, signal } from "canvasengine";
|
|
3
|
+
import { filter, from, map, Subscription, switchMap } from "rxjs";
|
|
4
|
+
import { inject } from "../core/inject";
|
|
5
|
+
import { RpgClientEngine } from "../RpgClientEngine";
|
|
6
|
+
import TextComponent from "../components/dynamics/text.ce";
|
|
7
|
+
|
|
8
|
+
const DYNAMIC_COMPONENTS = {
|
|
9
|
+
text: TextComponent,
|
|
10
|
+
}
|
|
3
11
|
|
|
4
12
|
export abstract class RpgClientObject extends RpgCommonPlayer {
|
|
5
13
|
abstract type: string;
|
|
6
|
-
emitParticleTrigger = trigger()
|
|
7
|
-
particleName = signal(
|
|
14
|
+
emitParticleTrigger = trigger();
|
|
15
|
+
particleName = signal("");
|
|
16
|
+
animationCurrentIndex = signal(0);
|
|
17
|
+
animationIsPlaying = signal(false);
|
|
18
|
+
_param = signal({});
|
|
19
|
+
frames: { x: number; y: number; ts: number }[] = [];
|
|
20
|
+
graphicsSignals = signal<any[]>([]);
|
|
21
|
+
_component = {} // temporary component memory
|
|
22
|
+
|
|
23
|
+
constructor() {
|
|
24
|
+
super();
|
|
25
|
+
this.hooks.callHooks("client-sprite-onInit", this).subscribe();
|
|
26
|
+
|
|
27
|
+
this._frames.observable.subscribe(({ items }) => {
|
|
28
|
+
if (!this.id) return;
|
|
29
|
+
//if (this.id == this.engine.playerIdSignal()!) return;
|
|
30
|
+
this.frames = [...this.frames, ...items];
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
this.graphics.observable
|
|
34
|
+
.pipe(
|
|
35
|
+
map(({ items }) => items),
|
|
36
|
+
filter(graphics => graphics.length > 0),
|
|
37
|
+
switchMap(graphics => from(Promise.all(graphics.map(graphic => this.engine.getSpriteSheet(graphic)))))
|
|
38
|
+
)
|
|
39
|
+
.subscribe((sheets) => {
|
|
40
|
+
this.graphicsSignals.set(sheets);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
this.componentsTop.observable
|
|
44
|
+
.pipe(
|
|
45
|
+
filter(value => value !== null && value !== undefined),
|
|
46
|
+
map((value) => typeof value === 'string' ? JSON.parse(value) : value),
|
|
47
|
+
)
|
|
48
|
+
.subscribe(({components}) => {
|
|
49
|
+
for (const component of components) {
|
|
50
|
+
for (const [key, value] of Object.entries(component)) {
|
|
51
|
+
this._component = value as any; // temporary component memory
|
|
52
|
+
console.log(value)
|
|
53
|
+
const type = (value as any).type as keyof typeof DYNAMIC_COMPONENTS;
|
|
54
|
+
if (DYNAMIC_COMPONENTS[type]) {
|
|
55
|
+
this.engine.addSpriteComponentInFront(DYNAMIC_COMPONENTS[type]);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
this.engine.tick
|
|
62
|
+
.pipe
|
|
63
|
+
//throttleTime(10)
|
|
64
|
+
()
|
|
65
|
+
.subscribe(() => {
|
|
66
|
+
const frame = this.frames.shift();
|
|
67
|
+
if (frame) {
|
|
68
|
+
if (!frame.x || !frame.y) return;
|
|
69
|
+
this.engine.scene.setBodyPosition(
|
|
70
|
+
this.id,
|
|
71
|
+
frame.x,
|
|
72
|
+
frame.y,
|
|
73
|
+
"top-left"
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get hooks() {
|
|
80
|
+
return inject<Hooks>(ModulesToken);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get engine() {
|
|
84
|
+
return inject(RpgClientEngine);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private animationSubscription?: Subscription;
|
|
8
88
|
|
|
9
89
|
flash(color: string, duration: number = 100) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
90
|
+
return new Promise((resolve) => {
|
|
91
|
+
const lastTint = this.tint();
|
|
92
|
+
this.tint.set(color);
|
|
93
|
+
setTimeout(() => {
|
|
94
|
+
this.tint.set(lastTint);
|
|
95
|
+
resolve(true);
|
|
96
|
+
}, duration);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Reset animation state when animation changes externally
|
|
102
|
+
*
|
|
103
|
+
* This method should be called when the animation changes due to movement
|
|
104
|
+
* or other external factors to ensure the animation system doesn't get stuck
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* // Reset when player starts moving
|
|
109
|
+
* player.resetAnimationState();
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
resetAnimationState() {
|
|
113
|
+
this.animationIsPlaying.set(false);
|
|
114
|
+
this.animationCurrentIndex.set(0);
|
|
115
|
+
if (this.animationSubscription) {
|
|
116
|
+
this.animationSubscription.unsubscribe();
|
|
117
|
+
this.animationSubscription = undefined;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Set a custom animation for a specific number of times
|
|
123
|
+
*
|
|
124
|
+
* Plays a custom animation for the specified number of repetitions.
|
|
125
|
+
* The animation system prevents overlapping animations and automatically
|
|
126
|
+
* returns to the previous animation when complete.
|
|
127
|
+
*
|
|
128
|
+
* @param animationName - Name of the animation to play
|
|
129
|
+
* @param nbTimes - Number of times to repeat the animation (default: Infinity for continuous)
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* // Play attack animation 3 times
|
|
134
|
+
* player.setAnimation('attack', 3);
|
|
135
|
+
*
|
|
136
|
+
* // Play continuous spell animation
|
|
137
|
+
* player.setAnimation('spell');
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
setAnimation(animationName: string, nbTimes: number = Infinity) {
|
|
141
|
+
if (this.animationIsPlaying()) return;
|
|
142
|
+
this.animationIsPlaying.set(true);
|
|
143
|
+
const previousAnimationName = this.animationName();
|
|
144
|
+
this.animationCurrentIndex.set(0);
|
|
145
|
+
|
|
146
|
+
// Clean up any existing subscription
|
|
147
|
+
if (this.animationSubscription) {
|
|
148
|
+
this.animationSubscription.unsubscribe();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.animationSubscription =
|
|
152
|
+
this.animationCurrentIndex.observable.subscribe((index) => {
|
|
153
|
+
if (index >= nbTimes) {
|
|
154
|
+
this.animationCurrentIndex.set(0);
|
|
155
|
+
this.animationName.set(previousAnimationName);
|
|
156
|
+
this.animationIsPlaying.set(false);
|
|
157
|
+
if (this.animationSubscription) {
|
|
158
|
+
this.animationSubscription.unsubscribe();
|
|
159
|
+
this.animationSubscription = undefined;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
this.animationName.set(animationName);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
showComponentAnimation(id: string, params: any) {
|
|
167
|
+
const engine = inject(RpgClientEngine);
|
|
168
|
+
engine.getComponentAnimation(id).displayEffect(params, this);
|
|
15
169
|
}
|
|
16
|
-
}
|
|
170
|
+
}
|