@rpgjs/common 3.3.2 → 4.0.0-beta.10
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/LICENSE +19 -0
- package/lib/AbstractObject.d.ts +3 -2
- package/lib/AbstractObject.js +296 -323
- package/lib/AbstractObject.js.map +1 -1
- package/lib/Color.js +1 -5
- package/lib/Color.js.map +1 -1
- package/lib/Event.js +2 -6
- package/lib/Event.js.map +1 -1
- package/lib/EventEmitter.js +3 -7
- package/lib/EventEmitter.js.map +1 -1
- package/lib/Game.js +73 -85
- package/lib/Game.js.map +1 -1
- package/lib/Hit.js +21 -28
- package/lib/Hit.js.map +1 -1
- package/lib/Logger.js +2 -7
- package/lib/Logger.js.map +1 -1
- package/lib/Map.d.ts +1 -0
- package/lib/Map.js +29 -53
- package/lib/Map.js.map +1 -1
- package/lib/Module.d.ts +2 -2
- package/lib/Module.js +84 -97
- package/lib/Module.js.map +1 -1
- package/lib/Player.d.ts +1 -0
- package/lib/Player.js +4 -7
- package/lib/Player.js.map +1 -1
- package/lib/Plugin.d.ts +4 -3
- package/lib/Plugin.js +14 -14
- package/lib/Plugin.js.map +1 -1
- package/lib/Scheduler.js +14 -21
- package/lib/Scheduler.js.map +1 -1
- package/lib/Shape.d.ts +1 -1
- package/lib/Shape.js +39 -52
- package/lib/Shape.js.map +1 -1
- package/lib/Utils.d.ts +4 -1
- package/lib/Utils.js +38 -53
- package/lib/Utils.js.map +1 -1
- package/lib/Vector2d.js +3 -8
- package/lib/Vector2d.js.map +1 -1
- package/lib/VirtualGrid.d.ts +1 -1
- package/lib/VirtualGrid.js +5 -12
- package/lib/VirtualGrid.js.map +1 -1
- package/lib/Worker.js +2 -10
- package/lib/Worker.js.map +1 -1
- package/lib/WorldMaps.d.ts +3 -1
- package/lib/WorldMaps.js +29 -15
- package/lib/WorldMaps.js.map +1 -1
- package/lib/gui/PrebuiltGui.js +2 -5
- package/lib/gui/PrebuiltGui.js.map +1 -1
- package/lib/index.d.ts +3 -1
- package/lib/index.js +24 -69
- package/lib/index.js.map +1 -1
- package/lib/transports/io.js +5 -9
- package/lib/transports/io.js.map +1 -1
- package/lib/workers/move.js +26 -42
- package/lib/workers/move.js.map +1 -1
- package/package.json +9 -11
- package/src/AbstractObject.ts +915 -0
- package/src/Color.ts +29 -0
- package/src/DefaultInput.ts +26 -0
- package/src/Event.ts +3 -0
- package/src/EventEmitter.ts +52 -0
- package/src/Game.ts +150 -0
- package/src/Hit.ts +70 -0
- package/src/Logger.ts +7 -0
- package/src/Map.ts +335 -0
- package/src/Module.ts +108 -0
- package/src/Player.ts +30 -0
- package/src/Plugin.ts +91 -0
- package/src/Scheduler.ts +88 -0
- package/src/Shape.ts +300 -0
- package/src/Utils.ts +168 -0
- package/src/Vector2d.ts +70 -0
- package/src/VirtualGrid.ts +78 -0
- package/src/Worker.ts +17 -0
- package/src/WorldMaps.ts +204 -0
- package/src/gui/PrebuiltGui.ts +27 -0
- package/src/index.ts +24 -0
- package/src/transports/io.ts +91 -0
- package/src/workers/move.ts +61 -0
- package/tsconfig.json +25 -0
package/src/Utils.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { constructor } from "@rpgjs/types";
|
|
2
|
+
|
|
3
|
+
export function random(min: number, max: number): number {
|
|
4
|
+
return Math.floor(Math.random() * (max - min + 1) + min)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function isBrowser(): boolean {
|
|
8
|
+
return typeof window !== 'undefined'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function isFunction(val: unknown): boolean {
|
|
12
|
+
return {}.toString.call(val) === '[object Function]'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isClass(func: unknown): boolean {
|
|
16
|
+
return typeof func === 'function'
|
|
17
|
+
&& /^class\s/.test(Function.prototype.toString.call(func));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isPromise(val: unknown) {
|
|
21
|
+
return isInstanceOf<Promise<unknown>>(val, Promise)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function isArray(val: unknown) {
|
|
25
|
+
return isInstanceOf<Array<unknown>>(val, Array)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isObject(val: unknown): boolean {
|
|
29
|
+
return typeof val == 'object' && val != null && !isArray(val)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function isString(val: unknown): boolean {
|
|
33
|
+
return typeof val == 'string'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function isInstanceOf<T = any>(val: unknown, _class: any) {
|
|
37
|
+
return val instanceof _class
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function arrayUniq(array: any[]): any[] {
|
|
41
|
+
return [...new Set(array)]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function arrayFlat(array: any[]): any[] {
|
|
45
|
+
return array.reduce((acc, val) => acc.concat(val), [])
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function intersection([start1, end1]: [number, number], [start2, end2]: [number, number]): boolean {
|
|
49
|
+
return (start1 >= start2 && start1 <= end2) || (start2 >= start1 && start2 < end1)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function capitalize(s: unknown): string {
|
|
53
|
+
if (typeof s !== 'string') return ''
|
|
54
|
+
return s.charAt(0).toUpperCase() + s.slice(1)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function arrayEquals(a: any[], b: any[]): boolean {
|
|
58
|
+
return a.length === b.length && a.every((v, i) => v === b[i])
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function applyMixins(derivedCtor: constructor<any>, baseCtors: constructor<any>[]) {
|
|
62
|
+
baseCtors.forEach((baseCtor) => {
|
|
63
|
+
Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {
|
|
64
|
+
const baseCtorName = Object.getOwnPropertyDescriptor(baseCtor.prototype, name)
|
|
65
|
+
if (!baseCtorName) {
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
Object.defineProperty(derivedCtor.prototype, name, baseCtorName)
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function generateUID(): string {
|
|
74
|
+
let firstPart: any = (Math.random() * 46656) | 0
|
|
75
|
+
let secondPart: any = (Math.random() * 46656) | 0
|
|
76
|
+
firstPart = ("000" + firstPart.toString(36)).slice(-3)
|
|
77
|
+
secondPart = ("000" + secondPart.toString(36)).slice(-3)
|
|
78
|
+
return firstPart + secondPart
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function createConstructor<T>(...propNames: any[]): T {
|
|
82
|
+
return class {
|
|
83
|
+
constructor(...propValues){
|
|
84
|
+
propNames.forEach((name, idx) => {
|
|
85
|
+
this[name] = propValues[idx]
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
} as unknown as T
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function sharedArrayBuffer() {
|
|
92
|
+
let buffer
|
|
93
|
+
if (typeof SharedArrayBuffer != 'undefined') {
|
|
94
|
+
buffer = SharedArrayBuffer
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
buffer = ArrayBuffer
|
|
98
|
+
}
|
|
99
|
+
return buffer
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function toRadians(angle: number) {
|
|
103
|
+
return angle * (Math.PI / 180)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function hexaToNumber(hexa: string): {
|
|
107
|
+
value: number,
|
|
108
|
+
alpha: number
|
|
109
|
+
} {
|
|
110
|
+
let val = hexa.replace('#', '')
|
|
111
|
+
let alpha = 1
|
|
112
|
+
if (val.length === 3) {
|
|
113
|
+
val = val.split('').map((v) => v + v).join('')
|
|
114
|
+
}
|
|
115
|
+
if (val.length === 8) {
|
|
116
|
+
alpha = parseInt(val.substring(0, 2), 16) / 255
|
|
117
|
+
val = val.substring(2)
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
value: parseInt(val, 16),
|
|
121
|
+
alpha
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function extractId(path: string): string | null {
|
|
126
|
+
const id = path.match(/([a-zA-Z0-9-_$!]+)\.[a-z]+$/i)
|
|
127
|
+
if (!id) return null
|
|
128
|
+
return id[1]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function basename(path: string): string {
|
|
132
|
+
return path.substring(path.lastIndexOf('/') + 1)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function fps2ms(fps: number): number {
|
|
136
|
+
return 1000 / fps
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function preciseNow(): number {
|
|
140
|
+
return typeof performance !== 'undefined' ? performance.now() : Date.now()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export default {
|
|
144
|
+
random,
|
|
145
|
+
isBrowser,
|
|
146
|
+
isPromise,
|
|
147
|
+
isArray,
|
|
148
|
+
isObject,
|
|
149
|
+
isString,
|
|
150
|
+
isFunction,
|
|
151
|
+
isClass,
|
|
152
|
+
isInstanceOf,
|
|
153
|
+
arrayUniq,
|
|
154
|
+
arrayFlat,
|
|
155
|
+
arrayEquals,
|
|
156
|
+
intersection,
|
|
157
|
+
applyMixins,
|
|
158
|
+
capitalize,
|
|
159
|
+
sharedArrayBuffer,
|
|
160
|
+
generateUID,
|
|
161
|
+
createConstructor,
|
|
162
|
+
toRadians,
|
|
163
|
+
extractId,
|
|
164
|
+
basename,
|
|
165
|
+
fps2ms,
|
|
166
|
+
preciseNow,
|
|
167
|
+
hexaToNumber
|
|
168
|
+
}
|
package/src/Vector2d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export class Vector2d {
|
|
2
|
+
constructor(public x: number, public y: number, public z: number = 0) {}
|
|
3
|
+
|
|
4
|
+
set(vector: Vector2d) {
|
|
5
|
+
this.x = vector.x
|
|
6
|
+
this.y = vector.y
|
|
7
|
+
this.z = vector.z
|
|
8
|
+
return this
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
add(vector: Vector2d) {
|
|
12
|
+
this.x += vector.x
|
|
13
|
+
this.y += vector.y
|
|
14
|
+
return this
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
subtract(vector: Vector2d) {
|
|
18
|
+
this.x -= vector.x
|
|
19
|
+
this.y -= vector.y
|
|
20
|
+
return this
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
multiply(scalar: number) {
|
|
24
|
+
this.x *= scalar
|
|
25
|
+
this.y *= scalar
|
|
26
|
+
return this
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
divide(scalar: number) {
|
|
30
|
+
this.x /= scalar
|
|
31
|
+
this.y /= scalar
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
distanceWith(vector: Vector2d): number {
|
|
36
|
+
const dx = this.x - vector.x
|
|
37
|
+
const dy = this.y - vector.y
|
|
38
|
+
return Math.sqrt(dx ** 2 + dy ** 2)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
magnitude(): number {
|
|
42
|
+
return Math.sqrt(this.x * this.x + this.y * this.y)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
copy(): Vector2d {
|
|
46
|
+
return new Vector2d(this.x, this.y, this.z)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
normalize() {
|
|
50
|
+
return this.divide(this.magnitude())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
isEqual(vector: Vector2d): boolean {
|
|
54
|
+
return this.x === vector.x &&
|
|
55
|
+
this.y === vector.y &&
|
|
56
|
+
this.z === vector.z
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
hasDifferentValues(vector: Vector2d): boolean {
|
|
60
|
+
return this.x !== vector.x ||
|
|
61
|
+
this.y !== vector.y ||
|
|
62
|
+
this.z !== vector.z
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class Vector2dZero extends Vector2d {
|
|
67
|
+
constructor() {
|
|
68
|
+
super(0, 0)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export type Box = { minX: number, minY: number, maxX: number, maxY: number }
|
|
2
|
+
|
|
3
|
+
export class VirtualGrid {
|
|
4
|
+
private cells: Map<number, Set<string>> = new Map()
|
|
5
|
+
private inverseCells: Map<string, Set<number>> = new Map()
|
|
6
|
+
|
|
7
|
+
constructor(private nbCellWidth: number, private cellWidth: number, private cellHeight: number) {}
|
|
8
|
+
|
|
9
|
+
zoom(nbCell: number): VirtualGrid {
|
|
10
|
+
this.nbCellWidth = Math.ceil(this.nbCellWidth / nbCell)
|
|
11
|
+
this.cellWidth *= nbCell
|
|
12
|
+
this.cellHeight *= nbCell
|
|
13
|
+
return this
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getCellIndex(x: number, y: number) {
|
|
17
|
+
return this.nbCellWidth * Math.floor(y / this.cellHeight) + Math.floor(x / this.cellWidth)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getCells(box: Box, cb: (index: number) => void) {
|
|
21
|
+
const {
|
|
22
|
+
minX,
|
|
23
|
+
minY,
|
|
24
|
+
maxX,
|
|
25
|
+
maxY
|
|
26
|
+
} = box
|
|
27
|
+
const topLeft = this.getCellIndex(minX, minY)
|
|
28
|
+
const topRight = this.getCellIndex(maxX, minY)
|
|
29
|
+
const bottomLeft = this.getCellIndex(minX, maxY)
|
|
30
|
+
const nbLines = (bottomLeft - topLeft) / this.nbCellWidth + 1
|
|
31
|
+
for (let j=0 ; j < nbLines ; j++) {
|
|
32
|
+
for (let i = topLeft ; i <= topRight ; i++) {
|
|
33
|
+
const index = i + (j * this.nbCellWidth)
|
|
34
|
+
cb(index)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getObjectsByBox(box: Box): Set<string> {
|
|
40
|
+
let objects: string[] = []
|
|
41
|
+
this.getCells(box, (index) => {
|
|
42
|
+
objects = [...objects, ...this.cells.get(index) || []]
|
|
43
|
+
})
|
|
44
|
+
return new Set(objects)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
getObjectsById(id: string): Set<string> {
|
|
48
|
+
let objects: string[] = []
|
|
49
|
+
const cells = this.inverseCells.get(id)
|
|
50
|
+
cells?.forEach((index) => {
|
|
51
|
+
objects = [...objects, ...this.cells.get(index) || []]
|
|
52
|
+
})
|
|
53
|
+
return new Set(objects)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
clearObjectInCells(id: string) {
|
|
57
|
+
if (this.inverseCells.has(id)) {
|
|
58
|
+
this.inverseCells.get(id)?.forEach((cellIndex: number) => {
|
|
59
|
+
this.cells.get(cellIndex)?.delete(id)
|
|
60
|
+
})
|
|
61
|
+
this.inverseCells.delete(id)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
insertInCells(id: string, box: { minX: number, minY: number, maxX: number, maxY: number }) {
|
|
66
|
+
this.clearObjectInCells(id)
|
|
67
|
+
const cells: Set<number> = new Set()
|
|
68
|
+
this.getCells(box, (index) => {
|
|
69
|
+
cells.add(index)
|
|
70
|
+
const memoryCells = this.cells.get(index)
|
|
71
|
+
if (!memoryCells) {
|
|
72
|
+
this.cells.set(index, new Set())
|
|
73
|
+
}
|
|
74
|
+
this.cells.get(index)?.add(id)
|
|
75
|
+
})
|
|
76
|
+
this.inverseCells.set(id, cells)
|
|
77
|
+
}
|
|
78
|
+
}
|
package/src/Worker.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import workerpool from 'workerpool'
|
|
2
|
+
|
|
3
|
+
export class GameWorker {
|
|
4
|
+
pool: any
|
|
5
|
+
|
|
6
|
+
constructor(private options = {}) {
|
|
7
|
+
//this.pool = workerpool.pool(__dirname + '/workers/move.js', options)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
load() {
|
|
11
|
+
return this
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
call(methodName: string, data: any) {
|
|
15
|
+
return this.pool.exec(methodName, [data])
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/WorldMaps.ts
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import RBush from 'rbush'
|
|
2
|
+
import { TiledWorldMap } from '@rpgjs/tiled'
|
|
3
|
+
import { RpgCommonMap } from './Map'
|
|
4
|
+
import { Direction } from '@rpgjs/types'
|
|
5
|
+
|
|
6
|
+
export interface RpgClassMap<T> {
|
|
7
|
+
id?: string
|
|
8
|
+
new (server: any): T,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface RpgTiledWorldMap extends TiledWorldMap{
|
|
12
|
+
properties?: {
|
|
13
|
+
[key: string]: any
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type PositionBox = { minX: number, minY: number, maxX: number, maxY: number }
|
|
18
|
+
type MapTree = { map: RpgClassMap<RpgCommonMap> } & PositionBox
|
|
19
|
+
|
|
20
|
+
export class RpgCommonWorldMaps {
|
|
21
|
+
private mapsTree: RBush = new RBush(500)
|
|
22
|
+
private maps: Map<string, RpgTiledWorldMap> = new Map()
|
|
23
|
+
|
|
24
|
+
constructor(public id: string) {}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Adding information from the map to the world
|
|
28
|
+
*
|
|
29
|
+
* > Maximum maps in world: 500
|
|
30
|
+
*
|
|
31
|
+
* @title Add Map in world
|
|
32
|
+
* @method world.addMap(wordMapInfo,map)
|
|
33
|
+
* @param {object} wordMapInfo
|
|
34
|
+
* Object file:
|
|
35
|
+
* ```ts
|
|
36
|
+
* {
|
|
37
|
+
* fileName: string;
|
|
38
|
+
height: number;
|
|
39
|
+
width: number;
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
* }
|
|
43
|
+
```
|
|
44
|
+
`fileName` represents a file to the JSON file (TMX transformed) or directly the Tiled Map Editor object
|
|
45
|
+
*
|
|
46
|
+
* @param {class of RpgMap} map
|
|
47
|
+
* @since 3.0.0-beta.8
|
|
48
|
+
* @memberof RpgWorldMaps
|
|
49
|
+
*/
|
|
50
|
+
addMap(wordMapInfo: RpgTiledWorldMap, map: RpgClassMap<RpgCommonMap>) {
|
|
51
|
+
const { x, y, height, width } = wordMapInfo
|
|
52
|
+
map.prototype.worldMapParent = this
|
|
53
|
+
this.maps.set(map.id as string, wordMapInfo)
|
|
54
|
+
this.mapsTree.insert<MapTree>({
|
|
55
|
+
minX: x,
|
|
56
|
+
minY: y,
|
|
57
|
+
maxX: x + width,
|
|
58
|
+
maxY: y + height,
|
|
59
|
+
map
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
updateMap(mapId: string, wordMapInfo: RpgTiledWorldMap): boolean {
|
|
64
|
+
const map = this.maps.get(mapId)
|
|
65
|
+
if (map) {
|
|
66
|
+
const item = (this.mapsTree.all() as MapTree[]).find(item => item.map.id == mapId)
|
|
67
|
+
if (!item) return false
|
|
68
|
+
this.maps.set(mapId, wordMapInfo)
|
|
69
|
+
item.map.prototype.worldMapParent = this
|
|
70
|
+
item.minX = wordMapInfo.x
|
|
71
|
+
item.minY = wordMapInfo.y
|
|
72
|
+
item.maxX = wordMapInfo.x + wordMapInfo.width
|
|
73
|
+
item.maxY = wordMapInfo.y + wordMapInfo.height
|
|
74
|
+
return true
|
|
75
|
+
}
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Remove map of the world
|
|
81
|
+
* @title Remove map of the world
|
|
82
|
+
* @method world.removeMap(mapId)
|
|
83
|
+
* @param {string} mapId
|
|
84
|
+
* @returns {boolean}
|
|
85
|
+
* @since 3.0.0-beta.8
|
|
86
|
+
* @memberof RpgWorldMaps
|
|
87
|
+
*/
|
|
88
|
+
removeMap(mapId: string): boolean {
|
|
89
|
+
const map = this.maps.get(mapId)
|
|
90
|
+
if (map) {
|
|
91
|
+
const item = (this.mapsTree.all() as MapTree[]).find(item => item.map.id == mapId)
|
|
92
|
+
if (!item) return false
|
|
93
|
+
this.maps.delete(mapId)
|
|
94
|
+
item.map.prototype.worldMapParent = undefined
|
|
95
|
+
this.mapsTree.remove(item)
|
|
96
|
+
return true
|
|
97
|
+
}
|
|
98
|
+
return false
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
removeAllMaps() {
|
|
102
|
+
this.maps.forEach((map, id) => {
|
|
103
|
+
this.removeMap(id)
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Retrieve information from the world
|
|
109
|
+
*
|
|
110
|
+
* @title Retrieve information from the world
|
|
111
|
+
* @method world.getMapInfo(id)
|
|
112
|
+
* @param {string} id map id
|
|
113
|
+
* @return {RpgTiledWorldMap | undefined}
|
|
114
|
+
* {
|
|
115
|
+
* id?: string
|
|
116
|
+
* properties?: object
|
|
117
|
+
* fileName: string;
|
|
118
|
+
height: number;
|
|
119
|
+
width: number;
|
|
120
|
+
x: number;
|
|
121
|
+
y: number;
|
|
122
|
+
* }
|
|
123
|
+
* @since 3.0.0-beta.8
|
|
124
|
+
* @memberof RpgWorldMaps
|
|
125
|
+
*/
|
|
126
|
+
getMapInfo(id: string): RpgTiledWorldMap | undefined {
|
|
127
|
+
return this.maps.get(id)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Retrieves neighboring maps according to positions or direction
|
|
132
|
+
*
|
|
133
|
+
* @title Retrieves neighboring maps
|
|
134
|
+
* @method world.getAdjacentMaps(map,search)
|
|
135
|
+
* @param {RpgMap} map The source map. We want to find the neighboring maps of the source map
|
|
136
|
+
* @param { PositionBox | Direction | { x: number, y: number } } search Research method
|
|
137
|
+
* * PositionBox. An object of the following form:
|
|
138
|
+
* `{ minX: number, minY: number, maxX: number, maxY: number }`
|
|
139
|
+
* * Direction. Collect all the maps in the given direction (e.g. the maps at the top)
|
|
140
|
+
* * Point: { x: number, y: number }
|
|
141
|
+
* @return { {class of RpgMap}[] }
|
|
142
|
+
* @since 3.0.0-beta.8
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* world.getAdjacentMaps(mymap, Direction.Up) // returns [class of RpgMap]
|
|
146
|
+
* ```
|
|
147
|
+
* @memberof RpgWorldMaps
|
|
148
|
+
*/
|
|
149
|
+
getAdjacentMaps(map: RpgCommonMap, search: PositionBox | Direction | { x: number, y: number }): RpgClassMap<RpgCommonMap>[] {
|
|
150
|
+
let position: PositionBox = {} as PositionBox
|
|
151
|
+
const point = search as { x: number, y: number }
|
|
152
|
+
if (typeof search == 'number') {
|
|
153
|
+
const padding = 1
|
|
154
|
+
switch (search) {
|
|
155
|
+
case Direction.Up:
|
|
156
|
+
position = {
|
|
157
|
+
minX: map.worldX + padding,
|
|
158
|
+
maxX: map.worldX + map.widthPx - padding,
|
|
159
|
+
minY: map.worldY - padding - 1,
|
|
160
|
+
maxY: map.worldY - padding
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
163
|
+
case Direction.Right:
|
|
164
|
+
position = {
|
|
165
|
+
minX: map.worldX + map.widthPx + padding,
|
|
166
|
+
maxX: map.worldX + map.widthPx + padding + 1,
|
|
167
|
+
minY: map.worldY + padding,
|
|
168
|
+
maxY: map.worldY + map.heightPx - padding
|
|
169
|
+
}
|
|
170
|
+
break;
|
|
171
|
+
case Direction.Down:
|
|
172
|
+
position = {
|
|
173
|
+
minX: map.worldX + padding,
|
|
174
|
+
maxX: map.worldX + map.widthPx - padding,
|
|
175
|
+
minY: map.worldY + map.heightPx + padding,
|
|
176
|
+
maxY: map.worldY + map.heightPx + padding + 1
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
case Direction.Left:
|
|
180
|
+
position = {
|
|
181
|
+
minX: map.worldX - padding,
|
|
182
|
+
maxX: map.worldX - padding - 1,
|
|
183
|
+
minY: map.worldY + padding,
|
|
184
|
+
maxY: map.worldY + map.heightPx - padding
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
else if (point.x) {
|
|
191
|
+
position = {
|
|
192
|
+
minX: point.x,
|
|
193
|
+
maxX: point.x,
|
|
194
|
+
minY: point.y,
|
|
195
|
+
maxY: point.y
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
position = search as PositionBox
|
|
200
|
+
}
|
|
201
|
+
const result = this.mapsTree.search(position)
|
|
202
|
+
return result.map(ret => ret.map)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Pre-made GUIs already exist. For example, the command `player.showText()` displays the rpg-dialog component. It is up to you to customize the component or take advantage of the `@rpgjs/default-gui` module which already contains ready-made components
|
|
4
|
+
*
|
|
5
|
+
* @title Prebuilt GUI
|
|
6
|
+
* @enum {string}
|
|
7
|
+
*
|
|
8
|
+
* PrebuiltGui.Dialog | rpg-dialog
|
|
9
|
+
* PrebuiltGui.MainMenu | rpg-main-menu
|
|
10
|
+
* PrebuiltGui.Shop | rpg-shop
|
|
11
|
+
* PrebuiltGui.Disconnect | rpg-disconnect
|
|
12
|
+
* PrebuiltGui.Gameover | rpg-gameover
|
|
13
|
+
* PrebuiltGui.Save | rpg-save
|
|
14
|
+
* PrebuiltGui.Controls | rpg-controls
|
|
15
|
+
* PrebuiltGui.Notification | rpg-notification
|
|
16
|
+
* @memberof PrebuiltGui
|
|
17
|
+
* */
|
|
18
|
+
export enum PrebuiltGui {
|
|
19
|
+
Dialog = 'rpg-dialog',
|
|
20
|
+
MainMenu = 'rpg-main-menu',
|
|
21
|
+
Shop = 'rpg-shop',
|
|
22
|
+
Disconnect = 'rpg-disconnect',
|
|
23
|
+
Gameover = 'rpg-gameover',
|
|
24
|
+
Save = 'rpg-save',
|
|
25
|
+
Controls = 'rpg-controls',
|
|
26
|
+
Notification = 'rpg-notification'
|
|
27
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import AbstractObject from './Player';
|
|
2
|
+
export { LiteralDirection, RpgCommonPlayer } from './Player'
|
|
3
|
+
export { AbstractObject }
|
|
4
|
+
export { RpgCommonEvent } from './Event'
|
|
5
|
+
export { RpgCommonMap } from './Map'
|
|
6
|
+
export { RpgCommonGame, GameSide } from './Game'
|
|
7
|
+
export { EventEmitter } from './EventEmitter'
|
|
8
|
+
export { PrebuiltGui } from './gui/PrebuiltGui'
|
|
9
|
+
export *as Utils from './Utils'
|
|
10
|
+
export { RpgPlugin, Plugin, HookServer, HookClient } from './Plugin'
|
|
11
|
+
export * as TransportIo from './transports/io'
|
|
12
|
+
export { Input, Control } from '@rpgjs/types'
|
|
13
|
+
export { Hit } from './Hit'
|
|
14
|
+
export { Scheduler } from './Scheduler'
|
|
15
|
+
export { RpgModule, loadModules, ModuleType } from './Module'
|
|
16
|
+
export * as MockIo from './transports/io'
|
|
17
|
+
export * as Logger from './Logger';
|
|
18
|
+
export { RpgShape, ShapePositioning } from './Shape'
|
|
19
|
+
export { VirtualGrid } from './VirtualGrid'
|
|
20
|
+
export { RpgCommonWorldMaps } from './WorldMaps'
|
|
21
|
+
export { Vector2d } from './Vector2d'
|
|
22
|
+
export { Direction } from '@rpgjs/types'
|
|
23
|
+
export { transitionColor } from './Color'
|
|
24
|
+
export { DefaultInput } from './DefaultInput'
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
class MockIo {
|
|
2
|
+
events: Map<string, any> = new Map()
|
|
3
|
+
|
|
4
|
+
on(name: string, value) {
|
|
5
|
+
this.events.set(name, value)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
off(name: string) {
|
|
9
|
+
this.events.delete(name)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
once(name: string, value) {
|
|
13
|
+
this.on(name, value)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
_trigger(name: string, data, client?) {
|
|
17
|
+
const fn = this.events.get(name)
|
|
18
|
+
if (fn) fn(data, client)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class MockSocket {
|
|
23
|
+
id: string
|
|
24
|
+
|
|
25
|
+
constructor(private io: any, public handshake) {
|
|
26
|
+
this.id = ''+Math.random()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
on(name: string, value) {
|
|
30
|
+
this.io.on(name, value, this.id)
|
|
31
|
+
return this
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
once(name: string, value) {
|
|
35
|
+
this.io.once(name, value, this.id)
|
|
36
|
+
return this
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
emit(name: string, data) {
|
|
40
|
+
this.io.emit(name, data, this.id)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
removeAllListeners(name: string) {
|
|
44
|
+
return this.off(name)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
off(name: string) {
|
|
48
|
+
this.io.off(name, this.id)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
class MockClientIo extends MockIo {
|
|
53
|
+
id: string = ''
|
|
54
|
+
|
|
55
|
+
connection(handshake: any) {
|
|
56
|
+
serverIo.connection(this, handshake)
|
|
57
|
+
this._trigger('connect', undefined)
|
|
58
|
+
return this
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
emit(name: string, data) {
|
|
62
|
+
serverIo._trigger(name, data, this)
|
|
63
|
+
return this
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
disconnect() {
|
|
67
|
+
this.emit('disconnect', undefined)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
class MockServerIo extends MockIo {
|
|
72
|
+
private clients: Map<string, MockClientIo> = new Map()
|
|
73
|
+
|
|
74
|
+
connection(client, handshake) {
|
|
75
|
+
const socket = new MockSocket(this, handshake)
|
|
76
|
+
this.clients.set(socket.id, client)
|
|
77
|
+
client.id = socket.id
|
|
78
|
+
this._trigger('connection', socket)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
emit(name: string, data, id) {
|
|
82
|
+
this.clients.get(id)?._trigger(name, data)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
clear() {
|
|
86
|
+
this.clients.clear()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const serverIo = new MockServerIo()
|
|
91
|
+
export const ClientIo = MockClientIo
|