evotars 0.0.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/.editorconfig +13 -0
- package/.prettierrc.json +3 -0
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/index.html +13 -0
- package/package.json +20 -0
- package/public/fonts/Rubik.ttf +0 -0
- package/public/sounds/jump.mp3 +0 -0
- package/public/sprites/agent/agent.json +166 -0
- package/public/sprites/agent/agent.png +0 -0
- package/public/sprites/cat/cat.json +231 -0
- package/public/sprites/cat/cat.png +0 -0
- package/public/sprites/dude/dude.json +231 -0
- package/public/sprites/dude/dude.png +0 -0
- package/public/sprites/girl/girl.json +231 -0
- package/public/sprites/girl/girl.png +0 -0
- package/public/sprites/nerd/nerd.json +231 -0
- package/public/sprites/nerd/nerd.png +0 -0
- package/public/sprites/senior/senior.json +231 -0
- package/public/sprites/senior/senior.png +0 -0
- package/public/sprites/sith/sith.json +166 -0
- package/public/sprites/sith/sith.png +0 -0
- package/src/app.ts +63 -0
- package/src/config/config.ts +133 -0
- package/src/config/constants.ts +1 -0
- package/src/dudes.ts +71 -0
- package/src/entities/Dude.ts +453 -0
- package/src/entities/DudeEmoteSpitter.ts +60 -0
- package/src/entities/DudeMessage.ts +163 -0
- package/src/entities/DudeName.ts +39 -0
- package/src/entities/DudeSpriteContainer.ts +68 -0
- package/src/entities/DudeTrailEffect.ts +72 -0
- package/src/helpers/timer.ts +43 -0
- package/src/helpers/types.ts +11 -0
- package/src/index.ts +75 -0
- package/src/services/assetsLoader.ts +27 -0
- package/src/services/dudesManager.ts +305 -0
- package/src/services/soundService.ts +28 -0
- package/src/services/spriteProvider.ts +93 -0
- package/src/styles.css +16 -0
- package/src/types/dto/action.ts +68 -0
- package/src/types/dto/chatter.ts +4 -0
- package/src/types/dto/event.ts +9 -0
- package/src/types/dto/index.ts +6 -0
- package/src/types/dto/message.ts +8 -0
- package/src/types/dto/settings.ts +5 -0
- package/src/types/dto/user.ts +13 -0
- package/src/types/index.ts +1 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MessageEntity,
|
|
3
|
+
RaidData,
|
|
4
|
+
TwitchChatterEntity,
|
|
5
|
+
UserActionEntity,
|
|
6
|
+
isColorUserActionEntity,
|
|
7
|
+
isDashUserActionEntity,
|
|
8
|
+
isGrowUserActionEntity,
|
|
9
|
+
isJumpUserActionEntity,
|
|
10
|
+
} from "../types";
|
|
11
|
+
import * as PIXI from "pixi.js";
|
|
12
|
+
import tinycolor from "tinycolor2";
|
|
13
|
+
import { app } from "../app";
|
|
14
|
+
import { config } from "../config/config";
|
|
15
|
+
import { Dude, DudeProps } from "../entities/Dude";
|
|
16
|
+
import { timers } from "../helpers/timer";
|
|
17
|
+
|
|
18
|
+
type DudesManagerSubscription = {
|
|
19
|
+
onAdd: (dude: Dude) => void;
|
|
20
|
+
onDelete: (dude: Dude) => void;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const DUDE_DESPAWN_TIMER = 1000 * 60 * 5;
|
|
24
|
+
|
|
25
|
+
class DudesManager {
|
|
26
|
+
private viewers: Record<string, Dude | undefined> = {};
|
|
27
|
+
|
|
28
|
+
private raiders: Dude[] = [];
|
|
29
|
+
|
|
30
|
+
private lastDudeActivity: Record<string, number | undefined> = {};
|
|
31
|
+
|
|
32
|
+
private subscriptions: DudesManagerSubscription[] = [];
|
|
33
|
+
|
|
34
|
+
public subscribe(subscription: DudesManagerSubscription) {
|
|
35
|
+
this.subscriptions.push(subscription);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public update() {
|
|
39
|
+
for (const id in this.viewers) {
|
|
40
|
+
const viewer = this.viewers[id];
|
|
41
|
+
|
|
42
|
+
if (viewer) {
|
|
43
|
+
viewer.update();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
for (const dude of this.raiders) {
|
|
48
|
+
dude.update();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public processRaid(data: RaidData) {
|
|
53
|
+
if (!app.settings.fallingRaiders) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const time = (1 / data.viewers) * 5000;
|
|
58
|
+
|
|
59
|
+
const spriteConfig = config.sprites["agent"];
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < data.viewers; i++) {
|
|
62
|
+
const dude = new Dude({
|
|
63
|
+
isAnonymous: true,
|
|
64
|
+
zIndex: -1,
|
|
65
|
+
sprite: spriteConfig,
|
|
66
|
+
color: new PIXI.Color(data.broadcaster.info.color),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
timers.add(time * i, () => {
|
|
70
|
+
this.addRaider(dude);
|
|
71
|
+
dude.spawn({ isFalling: true });
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
timers.add(i * time + 30000, () => {
|
|
75
|
+
dude.despawn({
|
|
76
|
+
onComplete: () => {
|
|
77
|
+
this.deleteRaider(dude);
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const dude = this.viewers[data.broadcaster.id];
|
|
84
|
+
|
|
85
|
+
const props: DudeProps = {
|
|
86
|
+
...this.prepareDudeProps(
|
|
87
|
+
data.broadcaster.info.displayName,
|
|
88
|
+
data.broadcaster.info.color,
|
|
89
|
+
),
|
|
90
|
+
scale: 8,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const spawnBroadcaster = () => {
|
|
94
|
+
const dude = new Dude(props);
|
|
95
|
+
this.addViewer(data.broadcaster.id, dude);
|
|
96
|
+
dude.spawn({ isFalling: true, positionX: 0.5 });
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
this.lastDudeActivity[data.broadcaster.id] = performance.now();
|
|
100
|
+
|
|
101
|
+
if (!dude) {
|
|
102
|
+
spawnBroadcaster();
|
|
103
|
+
} else {
|
|
104
|
+
dude.despawn({
|
|
105
|
+
onComplete: () => {
|
|
106
|
+
spawnBroadcaster();
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public processChatters(data: TwitchChatterEntity[]) {
|
|
113
|
+
for (const id in this.viewers) {
|
|
114
|
+
const lastMessageTime = this.lastDudeActivity[id];
|
|
115
|
+
const spawnedRecently =
|
|
116
|
+
!!lastMessageTime &&
|
|
117
|
+
performance.now() - lastMessageTime < DUDE_DESPAWN_TIMER;
|
|
118
|
+
|
|
119
|
+
if (data.every((chatter) => chatter.userId != id) && !spawnedRecently) {
|
|
120
|
+
const dude = this.viewers[id];
|
|
121
|
+
|
|
122
|
+
if (dude) {
|
|
123
|
+
dude.despawn({
|
|
124
|
+
onComplete: () => {
|
|
125
|
+
this.deleteViewer(id, dude);
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (app.settings.showAnonymousDudes) {
|
|
133
|
+
for (const chatter of data) {
|
|
134
|
+
const dude = this.viewers[chatter.userId];
|
|
135
|
+
|
|
136
|
+
if (!dude) {
|
|
137
|
+
const props = {
|
|
138
|
+
name: chatter.name,
|
|
139
|
+
isAnonymous: !this.hasActivity(chatter.userId),
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const dude = new Dude(props);
|
|
143
|
+
dude.spawn();
|
|
144
|
+
|
|
145
|
+
this.addViewer(chatter.userId, dude);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private hasActivity = (userId: string): boolean =>
|
|
152
|
+
!!this.lastDudeActivity[userId];
|
|
153
|
+
|
|
154
|
+
public doAction(action: UserActionEntity, dude: Dude) {
|
|
155
|
+
if (isJumpUserActionEntity(action)) {
|
|
156
|
+
dude.jump({
|
|
157
|
+
velocityX: action.data.velocityX,
|
|
158
|
+
velocityY: action.data.velocityY,
|
|
159
|
+
cooldown: action.cooldown,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (isDashUserActionEntity(action)) {
|
|
164
|
+
dude.dash({ force: action.data.force, cooldown: action.cooldown });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (isColorUserActionEntity(action)) {
|
|
168
|
+
const color = tinycolor(action.data.color);
|
|
169
|
+
|
|
170
|
+
if (color && color.isValid()) {
|
|
171
|
+
dude.setUserProps({ color: new PIXI.Color(action.data.color) });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (isGrowUserActionEntity(action)) {
|
|
176
|
+
dude.scale({
|
|
177
|
+
value: action.data.scale,
|
|
178
|
+
duration: action.data.duration,
|
|
179
|
+
cooldown: action.cooldown,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private prepareDudeProps(
|
|
185
|
+
name: string,
|
|
186
|
+
color?: string,
|
|
187
|
+
sprite?: string,
|
|
188
|
+
): DudeProps {
|
|
189
|
+
const props: DudeProps = {
|
|
190
|
+
name,
|
|
191
|
+
isAnonymous: false,
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const spriteConfig = sprite ? config.sprites[sprite] : null;
|
|
195
|
+
|
|
196
|
+
if (spriteConfig) {
|
|
197
|
+
props.sprite = spriteConfig;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (color) {
|
|
201
|
+
props.color = new PIXI.Color(color);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return props;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
public processAction(action: UserActionEntity): void {
|
|
208
|
+
const dude = this.viewers[action.userId];
|
|
209
|
+
|
|
210
|
+
const props: DudeProps = this.prepareDudeProps(
|
|
211
|
+
action.info.displayName,
|
|
212
|
+
action.info.color,
|
|
213
|
+
action.info.sprite,
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
if (!dude) {
|
|
217
|
+
const dude = new Dude(props);
|
|
218
|
+
|
|
219
|
+
dude.spawn({
|
|
220
|
+
onComplete: () => {
|
|
221
|
+
const dude = this.viewers[action.userId];
|
|
222
|
+
if (dude) {
|
|
223
|
+
this.doAction(action, dude);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
this.addViewer(action.userId, dude);
|
|
229
|
+
} else {
|
|
230
|
+
this.doAction(action, dude);
|
|
231
|
+
dude.setProps(props);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
public processMessage(data: MessageEntity): void {
|
|
236
|
+
const props: DudeProps = this.prepareDudeProps(
|
|
237
|
+
data.info.displayName,
|
|
238
|
+
data.info.color,
|
|
239
|
+
data.info.sprite,
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
let dude = this.viewers[data.userId];
|
|
243
|
+
|
|
244
|
+
if (!dude) {
|
|
245
|
+
const isFalling = app.settings.fallingDudes
|
|
246
|
+
? !this.hasActivity(data.userId)
|
|
247
|
+
: false;
|
|
248
|
+
|
|
249
|
+
dude = new Dude(props);
|
|
250
|
+
dude.spawn({ isFalling });
|
|
251
|
+
|
|
252
|
+
this.addViewer(data.userId, dude);
|
|
253
|
+
} else {
|
|
254
|
+
dude.setProps(props);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.lastDudeActivity[data.userId] = performance.now();
|
|
258
|
+
|
|
259
|
+
if (data.message) {
|
|
260
|
+
dude.addMessage(data.message);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (data.emotes.length > 0) {
|
|
264
|
+
dude.spitEmotes(data.emotes);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
public addViewer(id: string, dude: Dude): void {
|
|
269
|
+
this.subscriptions.forEach((s) => s.onAdd(dude));
|
|
270
|
+
this.viewers[id] = dude;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
public deleteViewer(id: string, dude: Dude): void {
|
|
274
|
+
this.subscriptions.forEach((s) => s.onDelete(dude));
|
|
275
|
+
delete this.viewers[id];
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
public addRaider(dude: Dude): void {
|
|
279
|
+
this.subscriptions.forEach((s) => s.onAdd(dude));
|
|
280
|
+
this.raiders.push(dude);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
public deleteRaider(dude: Dude): void {
|
|
284
|
+
this.subscriptions.forEach((s) => s.onDelete(dude));
|
|
285
|
+
this.raiders = this.raiders.filter((raider) => raider != dude);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
public zIndexDudeMax(from: number) {
|
|
289
|
+
return Object.values(this.viewers).reduce((zIndex, dude) => {
|
|
290
|
+
return dude && zIndex <= dude.container.zIndex
|
|
291
|
+
? dude.container.zIndex + 1
|
|
292
|
+
: zIndex;
|
|
293
|
+
}, from);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
public zIndexDudeMin(from: number) {
|
|
297
|
+
return Object.values(this.viewers).reduce((zIndex, dude) => {
|
|
298
|
+
return dude && zIndex >= dude.container.zIndex
|
|
299
|
+
? dude.container.zIndex - 1
|
|
300
|
+
: zIndex;
|
|
301
|
+
}, from);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export const dudesManager = new DudesManager();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type SoundManifest = {
|
|
2
|
+
[key: string]: string;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
class SoundService {
|
|
6
|
+
assets: { [key: string]: HTMLAudioElement } = {};
|
|
7
|
+
|
|
8
|
+
async init(manifest: SoundManifest) {
|
|
9
|
+
this.assets = Object.fromEntries(
|
|
10
|
+
Array.from(Object.entries(manifest)).map(([key, value]) => {
|
|
11
|
+
return [key, new Audio(value)];
|
|
12
|
+
})
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
play(name: string) {
|
|
17
|
+
const audio = this.assets[name];
|
|
18
|
+
|
|
19
|
+
if (audio) {
|
|
20
|
+
audio.volume = 0.2;
|
|
21
|
+
audio.pause();
|
|
22
|
+
audio.currentTime = 0;
|
|
23
|
+
audio.play();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const soundService = new SoundService();
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { AsepriteData, assetsLoader } from './assetsLoader';
|
|
2
|
+
import * as PIXI from 'pixi.js';
|
|
3
|
+
|
|
4
|
+
export type DudeLayerAnimatedSprite = {
|
|
5
|
+
layer: DudeSpriteLayers;
|
|
6
|
+
sprite: PIXI.AnimatedSprite;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type DudeTagAnimatedSprites = {
|
|
10
|
+
[tag in DudeSpriteTags]: DudeLayerAnimatedSprite[];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export enum DudeSpriteLayers {
|
|
14
|
+
Body = 'Body',
|
|
15
|
+
Eyes = 'Eyes',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export enum DudeSpriteTags {
|
|
19
|
+
Idle = 'Idle',
|
|
20
|
+
Jump = 'Jump',
|
|
21
|
+
Fall = 'Fall',
|
|
22
|
+
Land = 'Land',
|
|
23
|
+
Run = 'Run',
|
|
24
|
+
Die = 'Die',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type FrameTag = {
|
|
28
|
+
from: number;
|
|
29
|
+
name: string;
|
|
30
|
+
to: number;
|
|
31
|
+
direction: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export class SpriteProvider {
|
|
35
|
+
public createLayerAnimatedSprites(
|
|
36
|
+
name: string,
|
|
37
|
+
sheet: PIXI.Spritesheet<AsepriteData>,
|
|
38
|
+
frameTag: FrameTag
|
|
39
|
+
): DudeLayerAnimatedSprite[] {
|
|
40
|
+
const layers = sheet.data.meta.layers;
|
|
41
|
+
|
|
42
|
+
if (layers) {
|
|
43
|
+
const textures = Object.fromEntries<PIXI.FrameObject[]>(
|
|
44
|
+
layers.map((layer) => [layer.name, []])
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
for (let i = frameTag.from; i <= frameTag.to; i++) {
|
|
48
|
+
const framekey = i.toString();
|
|
49
|
+
|
|
50
|
+
for (const layer in textures) {
|
|
51
|
+
const key = name + '_' + layer + '_' + framekey;
|
|
52
|
+
const texture = sheet.textures[key];
|
|
53
|
+
const time = sheet.data.frames[key].duration;
|
|
54
|
+
|
|
55
|
+
textures[layer].push({ texture: texture, time: time });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return Object.entries(textures).map((entry) => {
|
|
60
|
+
const sprite = new PIXI.AnimatedSprite(entry[1]);
|
|
61
|
+
sprite.texture.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST;
|
|
62
|
+
return { layer: entry[0] as DudeSpriteLayers, sprite };
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
throw Error("Sprite sheet doesn't have layers");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public createTagAnimatedSprites(sheetName: string): DudeTagAnimatedSprites {
|
|
70
|
+
if (!sheetName) {
|
|
71
|
+
throw Error('Sheet is not defined');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const sheet = assetsLoader.sheets[sheetName];
|
|
75
|
+
|
|
76
|
+
return (sheet.data.meta.frameTags ?? []).reduce<DudeTagAnimatedSprites>(
|
|
77
|
+
(sprites, tag) => {
|
|
78
|
+
if (tag && tag.name) {
|
|
79
|
+
sprites[tag.name as DudeSpriteTags] = this.createLayerAnimatedSprites(
|
|
80
|
+
sheetName,
|
|
81
|
+
sheet,
|
|
82
|
+
tag
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return sprites;
|
|
87
|
+
},
|
|
88
|
+
{} as DudeTagAnimatedSprites
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const spriteProvider = new SpriteProvider();
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { UserInfo } from "./user";
|
|
2
|
+
|
|
3
|
+
export type ActionData = Record<string, string | number | undefined>;
|
|
4
|
+
|
|
5
|
+
export type ActionableData = {
|
|
6
|
+
arguments: string[];
|
|
7
|
+
action: ActionData;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type ActionEntity = {
|
|
11
|
+
id: number;
|
|
12
|
+
name: string;
|
|
13
|
+
title: string;
|
|
14
|
+
description: string;
|
|
15
|
+
data: ActionData;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type UserActionEntity = {
|
|
19
|
+
userId: string;
|
|
20
|
+
cooldown: number;
|
|
21
|
+
info: UserInfo;
|
|
22
|
+
} & ActionEntity;
|
|
23
|
+
|
|
24
|
+
export type JumpUserActionEntity = {
|
|
25
|
+
name: "jump";
|
|
26
|
+
data: {
|
|
27
|
+
velocityX: number;
|
|
28
|
+
velocityY: number;
|
|
29
|
+
};
|
|
30
|
+
} & UserActionEntity;
|
|
31
|
+
|
|
32
|
+
export type ColorUserActionEntity = {
|
|
33
|
+
name: "color";
|
|
34
|
+
data: {
|
|
35
|
+
color: string;
|
|
36
|
+
};
|
|
37
|
+
} & UserActionEntity;
|
|
38
|
+
|
|
39
|
+
export type GrowUserActionEntity = {
|
|
40
|
+
name: "grow";
|
|
41
|
+
data: {
|
|
42
|
+
duration: number;
|
|
43
|
+
scale: number;
|
|
44
|
+
};
|
|
45
|
+
} & UserActionEntity;
|
|
46
|
+
|
|
47
|
+
export type DashUserActionEntity = {
|
|
48
|
+
name: "dash";
|
|
49
|
+
data: {
|
|
50
|
+
force: number;
|
|
51
|
+
};
|
|
52
|
+
} & UserActionEntity;
|
|
53
|
+
|
|
54
|
+
export const isJumpUserActionEntity = (
|
|
55
|
+
entity: ActionEntity,
|
|
56
|
+
): entity is JumpUserActionEntity => entity.name == "jump";
|
|
57
|
+
|
|
58
|
+
export const isColorUserActionEntity = (
|
|
59
|
+
entity: ActionEntity,
|
|
60
|
+
): entity is ColorUserActionEntity => entity.name == "color";
|
|
61
|
+
|
|
62
|
+
export const isGrowUserActionEntity = (
|
|
63
|
+
entity: ActionEntity,
|
|
64
|
+
): entity is GrowUserActionEntity => entity.name == "grow";
|
|
65
|
+
|
|
66
|
+
export const isDashUserActionEntity = (
|
|
67
|
+
entity: ActionEntity,
|
|
68
|
+
): entity is DashUserActionEntity => entity.name == "dash";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dto';
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable", "ES2021.String"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
|
|
16
|
+
/* Linting */
|
|
17
|
+
"strict": true,
|
|
18
|
+
"noUnusedLocals": true,
|
|
19
|
+
"noUnusedParameters": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true
|
|
21
|
+
},
|
|
22
|
+
"include": ["src"]
|
|
23
|
+
}
|