Skip to content

Commit 87ba4d8

Browse files
committed
feat: add unique ids to each game event
1 parent d0db8a6 commit 87ba4d8

File tree

5 files changed

+77
-33
lines changed

5 files changed

+77
-33
lines changed

electron/common/game/game.types.ts

+28-17
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,46 @@ export type GameEvent =
2020
| ServerTimeGameEvent
2121
| RoundTimeGameEvent;
2222

23+
export interface GameEventBase {
24+
/**
25+
* Unique identifier for this game event.
26+
*/
27+
eventId: string;
28+
/**
29+
* Indicates the type of game event.
30+
*/
31+
type: GameEventType;
32+
}
33+
2334
/**
2435
* Indicates text to display to the player.
2536
* Note that previous game events may indicate how the
2637
* text should be styled and to which window to display it.
2738
*/
28-
export interface TextGameEvent {
39+
export interface TextGameEvent extends GameEventBase {
2940
type: GameEventType.TEXT;
3041
text: string;
3142
}
3243

3344
/**
3445
* <pushBold/>
3546
*/
36-
export interface PushBoldGameEvent {
47+
export interface PushBoldGameEvent extends GameEventBase {
3748
type: GameEventType.PUSH_BOLD;
3849
}
3950

4051
/**
4152
* <popBold/>
4253
*/
43-
export interface PopBoldGameEvent {
54+
export interface PopBoldGameEvent extends GameEventBase {
4455
type: GameEventType.POP_BOLD;
4556
}
4657

4758
/**
4859
* <output class="mono"/>
4960
* <output class=""/>
5061
*/
51-
export interface TextOutputClassGameEvent {
62+
export interface TextOutputClassGameEvent extends GameEventBase {
5263
type: GameEventType.TEXT_OUTPUT_CLASS;
5364
textOutputClass: string;
5465
}
@@ -58,15 +69,15 @@ export interface TextOutputClassGameEvent {
5869
* <preset id='roomDesc'>A neat row...</preset> You also see ...
5970
* Obvious exits: <d>out</d>.
6071
*/
61-
export interface TextStylePresetGameEvent {
72+
export interface TextStylePresetGameEvent extends GameEventBase {
6273
type: GameEventType.TEXT_STYLE_PRESET;
6374
textStylePreset: string;
6475
}
6576

6677
/**
6778
* <indicator id='IconBLEEDING' visible='n'/>
6879
*/
69-
export interface IndicatorGameEvent {
80+
export interface IndicatorGameEvent extends GameEventBase {
7081
type: GameEventType.INDICATOR;
7182
indicator: IndicatorType;
7283
active: boolean;
@@ -75,7 +86,7 @@ export interface IndicatorGameEvent {
7586
/**
7687
* <spell>Fire Shards</spell>
7788
*/
78-
export interface SpellGameEvent {
89+
export interface SpellGameEvent extends GameEventBase {
7990
type: GameEventType.SPELL;
8091
spell: string;
8192
}
@@ -84,46 +95,46 @@ export interface SpellGameEvent {
8495
* <left>Empty</left>
8596
* <right>red backpack</right>
8697
*/
87-
export interface HandGameEvent {
98+
export interface HandGameEvent extends GameEventBase {
8899
type: GameEventType.LEFT_HAND | GameEventType.RIGHT_HAND;
89100
item: string;
90101
}
91102

92103
/**
93104
* <clearStream id='inv'/>
94105
*/
95-
export interface ClearStreamGameEvent {
106+
export interface ClearStreamGameEvent extends GameEventBase {
96107
type: GameEventType.CLEAR_STREAM;
97108
streamId: string;
98109
}
99110

100111
/**
101112
* <pushStream id='experience'/>
102113
*/
103-
export interface PushStreamGameEvent {
114+
export interface PushStreamGameEvent extends GameEventBase {
104115
type: GameEventType.PUSH_STREAM;
105116
streamId: string;
106117
}
107118

108119
/**
109120
* <popStream/>
110121
*/
111-
export interface PopStreamGameEvent {
122+
export interface PopStreamGameEvent extends GameEventBase {
112123
type: GameEventType.POP_STREAM;
113124
}
114125

115126
/**
116127
* <compass><dir value="e"/><dir value="sw"/><dir value="out"/></compass>
117128
*/
118-
export interface CompassGameEvent {
129+
export interface CompassGameEvent extends GameEventBase {
119130
type: GameEventType.COMPASS;
120131
directions: Array<string>; // e.g. 'nw', 'n', 'up', or 'out'
121132
}
122133

123134
/**
124135
* <progressBar id='mana' value='100'/>
125136
*/
126-
export interface VitalsGameEvent {
137+
export interface VitalsGameEvent extends GameEventBase {
127138
type: GameEventType.VITALS;
128139
vitalId: string; // health, mana, concentration, spirit, stamina
129140
value: number; // 0-100 (percentage)
@@ -135,7 +146,7 @@ export interface VitalsGameEvent {
135146
* <component id='exp Attunement'> Attunement: 1 46% attentive </component>
136147
* <component id='exp Attunement'><preset id='whisper'> Attunement: 1 46% attentive </preset></component>
137148
*/
138-
export interface ExperienceGameEvent {
149+
export interface ExperienceGameEvent extends GameEventBase {
139150
type: GameEventType.EXPERIENCE;
140151
skill: string; // e.g. Attunement, First Aid, etc.
141152
rank: number; // integer of the skill's rank
@@ -154,7 +165,7 @@ export interface ExperienceGameEvent {
154165
* <component id='room players'>Also here: Katoak.</component>
155166
* <component id='room exits'>Obvious paths: <d>east</d>, <d>southwest</d>, <d>northwest</d>.<compass></compass></component>
156167
*/
157-
export interface RoomGameEvent {
168+
export interface RoomGameEvent extends GameEventBase {
158169
type: GameEventType.ROOM;
159170
roomName?: string;
160171
roomDescription?: string;
@@ -166,15 +177,15 @@ export interface RoomGameEvent {
166177
/**
167178
* <prompt time="1703617000">&gt;</prompt>
168179
*/
169-
export interface ServerTimeGameEvent {
180+
export interface ServerTimeGameEvent extends GameEventBase {
170181
type: GameEventType.SERVER_TIME;
171182
time: number;
172183
}
173184

174185
/**
175186
* <roundTime value='1703617016'/>
176187
*/
177-
export interface RoundTimeGameEvent {
188+
export interface RoundTimeGameEvent extends GameEventBase {
178189
type: GameEventType.ROUND_TIME;
179190
time: number;
180191
}

electron/main/game/game.parser.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as rxjs from 'rxjs';
2+
import { v4 as uuid } from 'uuid';
23
import type {
34
ExperienceGameEvent,
45
GameEvent,
@@ -163,7 +164,11 @@ export class GameParserImpl implements GameParser {
163164
this.activeTags = [];
164165
this.compassDirections = [];
165166
this.gameText = '';
166-
this.previousTextGameEvent = { type: GameEventType.TEXT, text: '' };
167+
this.previousTextGameEvent = {
168+
type: GameEventType.TEXT,
169+
eventId: '',
170+
text: '',
171+
};
167172
}
168173

169174
/**
@@ -590,6 +595,7 @@ export class GameParserImpl implements GameParser {
590595
if (matchResult) {
591596
return {
592597
type: GameEventType.EXPERIENCE,
598+
eventId: uuid(),
593599
skill: matchResult.groups?.skill ?? 'PARSE_ERROR',
594600
rank: parseInt(matchResult.groups?.rank ?? '0'),
595601
percent: parseInt(matchResult.groups?.percent ?? '0'),
@@ -598,6 +604,7 @@ export class GameParserImpl implements GameParser {
598604
}
599605
return {
600606
type: GameEventType.EXPERIENCE,
607+
eventId: uuid(),
601608
skill: tagId.slice(4),
602609
rank: 0,
603610
percent: 0,
@@ -637,6 +644,7 @@ export class GameParserImpl implements GameParser {
637644
// we compare the outgoing text with the previously sent.
638645
const event: GameEvent = {
639646
type: GameEventType.TEXT,
647+
eventId: uuid(),
640648
text: unescapeEntities(text),
641649
};
642650
this.emitGameEvent(event);
@@ -646,25 +654,29 @@ export class GameParserImpl implements GameParser {
646654
protected emitPushBoldGameEvent(): void {
647655
this.emitGameEvent({
648656
type: GameEventType.PUSH_BOLD,
657+
eventId: uuid(),
649658
});
650659
}
651660

652661
protected emitPopBoldGameEvent(): void {
653662
this.emitGameEvent({
654663
type: GameEventType.POP_BOLD,
664+
eventId: uuid(),
655665
});
656666
}
657667

658668
protected emitTextOutputClassGameEvent(className: string): void {
659669
this.emitGameEvent({
660670
type: GameEventType.TEXT_OUTPUT_CLASS,
671+
eventId: uuid(),
661672
textOutputClass: className,
662673
});
663674
}
664675

665676
protected emitTextStylePresetGameEvent(presetName: string): void {
666677
this.emitGameEvent({
667678
type: GameEventType.TEXT_STYLE_PRESET,
679+
eventId: uuid(),
668680
textStylePreset: presetName,
669681
});
670682
}
@@ -677,6 +689,7 @@ export class GameParserImpl implements GameParser {
677689
const indicator = INDICATOR_ID_TO_TYPE_MAP[tagId];
678690
this.emitGameEvent({
679691
type: GameEventType.INDICATOR,
692+
eventId: uuid(),
680693
indicator,
681694
active,
682695
});
@@ -685,47 +698,54 @@ export class GameParserImpl implements GameParser {
685698
protected emitSpellGameEvent(spell: string): void {
686699
this.emitGameEvent({
687700
type: GameEventType.SPELL,
701+
eventId: uuid(),
688702
spell: unescapeEntities(spell),
689703
});
690704
}
691705

692706
protected emitLeftHandGameEvent(item: string): void {
693707
this.emitGameEvent({
694708
type: GameEventType.LEFT_HAND,
709+
eventId: uuid(),
695710
item: unescapeEntities(item),
696711
});
697712
}
698713

699714
protected emitRightHandGameEvent(item: string): void {
700715
this.emitGameEvent({
701716
type: GameEventType.RIGHT_HAND,
717+
eventId: uuid(),
702718
item: unescapeEntities(item),
703719
});
704720
}
705721

706722
protected emitClearStreamGameEvent(streamId: string): void {
707723
this.emitGameEvent({
708724
type: GameEventType.CLEAR_STREAM,
725+
eventId: uuid(),
709726
streamId,
710727
});
711728
}
712729

713730
protected emitPushStreamGameEvent(streamId: string): void {
714731
this.emitGameEvent({
715732
type: GameEventType.PUSH_STREAM,
733+
eventId: uuid(),
716734
streamId,
717735
});
718736
}
719737

720738
protected emitPopStreamGameEvent(): void {
721739
this.emitGameEvent({
722740
type: GameEventType.POP_STREAM,
741+
eventId: uuid(),
723742
});
724743
}
725744

726745
protected emitCompassGameEvent(directions: Array<string>): void {
727746
this.emitGameEvent({
728747
type: GameEventType.COMPASS,
748+
eventId: uuid(),
729749
directions,
730750
});
731751
}
@@ -737,6 +757,7 @@ export class GameParserImpl implements GameParser {
737757
const { vitalId, value } = options;
738758
this.emitGameEvent({
739759
type: GameEventType.VITALS,
760+
eventId: uuid(),
740761
vitalId,
741762
value,
742763
});
@@ -751,6 +772,7 @@ export class GameParserImpl implements GameParser {
751772
const { skill, rank, percent, mindState } = options;
752773
this.emitGameEvent({
753774
type: GameEventType.EXPERIENCE,
775+
eventId: uuid(),
754776
skill,
755777
rank,
756778
percent,
@@ -766,20 +788,23 @@ export class GameParserImpl implements GameParser {
766788
const roomProperty = ROOM_ID_TO_EVENT_PROPERTY_MAP[tagId];
767789
this.emitGameEvent({
768790
type: GameEventType.ROOM,
791+
eventId: uuid(),
769792
[roomProperty]: unescapeEntities(roomText),
770793
});
771794
}
772795

773796
protected emitServerTimeGameEvent(time: number): void {
774797
this.emitGameEvent({
775798
type: GameEventType.SERVER_TIME,
799+
eventId: uuid(),
776800
time,
777801
});
778802
}
779803

780804
protected emitRoundTimeGameEvent(time: number): void {
781805
this.emitGameEvent({
782806
type: GameEventType.ROUND_TIME,
807+
eventId: uuid(),
783808
time,
784809
});
785810
}

electron/main/game/game.service.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import fs from 'fs-extra';
22
import * as rxjs from 'rxjs';
3+
import { v4 as uuid } from 'uuid';
34
import { waitUntil } from '../../common/async';
45
import { type GameEvent, GameEventType } from '../../common/game';
56
import type { Maybe } from '../../common/types';
@@ -127,6 +128,7 @@ class GameServiceImpl implements GameService {
127128
logger.debug('emitting command as text game event', { command });
128129
this.sentCommandsSubject$?.next({
129130
type: GameEventType.TEXT,
131+
eventId: uuid(),
130132
text: `> ${command}\n`,
131133
});
132134
}

electron/renderer/components/grid/grid.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@ const Grid: React.FC<GridProps> = (props: GridProps): ReactNode => {
185185
* https://stackoverflow.com/questions/65350114/useref-for-element-in-loop-in-react/65350394#65350394
186186
*/
187187
const itemRefs = useRef<Array<RefObject<HTMLDivElement>>>([]);
188-
itemRefs.current = layout.map((_layoutItem, i) => {
188+
itemRefs.current = layout.map((_layoutItem, index) => {
189189
// Note we use `createRef` and not `useRef` per "Rule of Hooks" for loops.
190-
return itemRefs.current[i] ?? createRef<HTMLDivElement>();
190+
return itemRefs.current[index] ?? createRef<HTMLDivElement>();
191191
});
192192

193193
/**
@@ -197,9 +197,9 @@ const Grid: React.FC<GridProps> = (props: GridProps): ReactNode => {
197197
* https://github.com/react-grid-layout/react-grid-layout?tab=readme-ov-file#performance
198198
*/
199199
const gridItems = useMemo(() => {
200-
return layout.map((layoutItem, i) => {
200+
return layout.map((layoutItem, index) => {
201201
const item = items.find((item) => item.itemId === layoutItem.i);
202-
const itemRef = itemRefs.current[i];
202+
const itemRef = itemRefs.current[index];
203203
return (
204204
<GridItem
205205
ref={itemRef}

0 commit comments

Comments
 (0)