Skip to content

Commit f615dc1

Browse files
authored
Notification system - Local + Global
Notification system - Local + Global
2 parents 28f73c6 + 4fbe2e1 commit f615dc1

File tree

22 files changed

+458
-203
lines changed

22 files changed

+458
-203
lines changed

back/src/ecs/component/events/ChatMessageEvent.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { SerializedMessageType } from '../../../../../shared/network/server/serialized.js'
2+
import { Component } from '../../../../../shared/component/Component.js'
3+
4+
5+
/**
6+
* This event is triggered when a message is sent
7+
*
8+
* Messages can be :
9+
* - Global chat messages
10+
* - Targeted chat messages (to specific players)
11+
* - Global notifications
12+
* - Targeted notifications (to specific players)
13+
*/
14+
export class MessageEvent extends Component {
15+
constructor(
16+
entityId: number,
17+
public sender: string,
18+
public content: string,
19+
public messageType: SerializedMessageType = SerializedMessageType.GLOBAL_CHAT,
20+
public targetPlayerIds: number[] = [] // Only used for targeted messages
21+
) {
22+
super(entityId)
23+
}
24+
}

back/src/ecs/entity/Chat.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { ChatListComponent } from '../../../../shared/component/ChatComponent.js'
1+
import { MessageListComponent } from '../../../../shared/component/MessageComponent.js'
22
import { Entity } from '../../../../shared/entity/Entity.js'
33
import { EntityManager } from '../../../../shared/system/EntityManager.js'
44
import { EventSystem } from '../../../../shared/system/EventSystem.js'
55
import { SerializedEntityType } from '../../../../shared/network/server/serialized.js'
66
import { NetworkDataComponent } from '../../../../shared/network/NetworkDataComponent.js'
7-
import { ChatMessageEvent } from '../component/events/ChatMessageEvent.js'
7+
import { MessageEvent } from '../component/events/MessageEvent.js'
88
import { ChatComponent } from '../component/tag/TagChatComponent.js'
99

1010
export class Chat {
@@ -16,14 +16,14 @@ export class Chat {
1616
this.entity.addComponent(new ChatComponent(this.entity.id))
1717

1818
EventSystem.addEvent(
19-
new ChatMessageEvent(this.entity.id, '🖥️ [SERVER]', `Started ${new Date().toLocaleString()}`)
19+
new MessageEvent(this.entity.id, '🖥️ [SERVER]', `Started ${new Date().toLocaleString()}`)
2020
)
2121

2222
EventSystem.addEvent(
23-
new ChatMessageEvent(this.entity.id, '🖥️ [SERVER]', 'Welcome to the chat !')
23+
new MessageEvent(this.entity.id, '🖥️ [SERVER]', 'Welcome to the chat !')
2424
)
2525

26-
const chatListComponent = new ChatListComponent(this.entity.id, [])
26+
const chatListComponent = new MessageListComponent(this.entity.id, [])
2727
this.entity.addComponent(chatListComponent)
2828

2929
const networkDataComponent = new NetworkDataComponent(this.entity.id, this.entity.type, [

back/src/ecs/system/events/ChatEventSystem.ts

Lines changed: 0 additions & 51 deletions
This file was deleted.

back/src/ecs/system/events/DestroyEventSystem.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { EntityDestroyedEvent } from '../../../../../shared/component/events/Ent
22
import { Entity } from '../../../../../shared/entity/Entity.js'
33
import { EntityManager } from '../../../../../shared/system/EntityManager.js'
44
import { EventSystem } from '../../../../../shared/system/EventSystem.js'
5-
import { ChatMessageEvent } from '../../component/events/ChatMessageEvent.js'
5+
import { MessageEvent } from '../../component/events/MessageEvent.js'
66
import { PlayerComponent } from '../../../../../shared/component/PlayerComponent.js'
77

88
export class DestroyEventSystem {
@@ -18,7 +18,7 @@ export class DestroyEventSystem {
1818

1919
if (entity.getComponent(PlayerComponent)) {
2020
EventSystem.addEvent(
21-
new ChatMessageEvent(entity.id, '🖥️ [SERVER]', `Player ${entity.id} left the game.`)
21+
new MessageEvent(entity.id, '🖥️ [SERVER]', `Player ${entity.id} left the game.`)
2222
)
2323
}
2424

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { EntityManager } from '../../../../../shared/system/EntityManager.js'
2+
import { MessageListComponent } from '../../../../../shared/component/MessageComponent.js'
3+
import { Entity } from '../../../../../shared/entity/Entity.js'
4+
import { MessageEvent } from '../../component/events/MessageEvent.js'
5+
import { ChatComponent } from '../../component/tag/TagChatComponent.js'
6+
import { EventSystem } from '../../../../../shared/system/EventSystem.js'
7+
import { SerializedMessageType } from '../../../../../shared/network/server/serialized.js'
8+
9+
export class MessageEventSystem {
10+
private MAX_MESSAGES: number = 20
11+
private MAX_CONTENT_LENGTH: number = 160
12+
13+
update(entities: Entity[]) {
14+
const chatMessageEvents = EventSystem.getEvents(MessageEvent)
15+
16+
// Check if there are any chat messages to process
17+
if (chatMessageEvents.length === 0) {
18+
return
19+
}
20+
21+
// Find Chat Entity
22+
// For now, we assume there is only one chat entity, but we could have multiple chat entities (local, group, etc)
23+
const chatEntity = EntityManager.getFirstEntityWithComponent(entities, ChatComponent)
24+
25+
if (!chatEntity) {
26+
console.error('ChatEventSystem : A chat entity is required to send messages.')
27+
return
28+
}
29+
30+
for (const chatMessageEvent of chatMessageEvents) {
31+
const chatListComponent = chatEntity.getComponent(MessageListComponent)
32+
if (chatListComponent) {
33+
let content = chatMessageEvent.content
34+
const sender = chatMessageEvent.sender
35+
const messageType = chatMessageEvent.messageType
36+
const targetPlayerIds = chatMessageEvent.targetPlayerIds
37+
38+
// Limit content length
39+
if (content.length > this.MAX_CONTENT_LENGTH) {
40+
content = content.substring(0, this.MAX_CONTENT_LENGTH)
41+
}
42+
43+
// Handle different message types
44+
switch (messageType) {
45+
case SerializedMessageType.GLOBAL_NOTIFICATION:
46+
// Add global notification
47+
chatListComponent.addMessage(sender, content, SerializedMessageType.GLOBAL_NOTIFICATION)
48+
break;
49+
50+
case SerializedMessageType.TARGETED_NOTIFICATION:
51+
case SerializedMessageType.TARGETED_CHAT:
52+
// Check if we have valid target player IDs
53+
if (targetPlayerIds && targetPlayerIds.length > 0) {
54+
// Add targeted message with appropriate message type
55+
chatListComponent.addMessage(sender, content, messageType, targetPlayerIds)
56+
} else {
57+
console.warn(`ChatEventSystem: ${messageType} without target player IDs`)
58+
// Fall back to regular chat message
59+
this.addGlobalChatMessage(chatListComponent, sender, content)
60+
}
61+
break;
62+
63+
case SerializedMessageType.GLOBAL_CHAT:
64+
default:
65+
// Regular chat message
66+
this.addGlobalChatMessage(chatListComponent, sender, content)
67+
break;
68+
}
69+
}
70+
}
71+
}
72+
73+
private addGlobalChatMessage(chatListComponent: MessageListComponent, sender: string, content: string) {
74+
// Limit history to maxMessages
75+
if (chatListComponent.list.length >= this.MAX_MESSAGES) {
76+
chatListComponent.list.shift()
77+
}
78+
79+
chatListComponent.addMessage(sender, content, SerializedMessageType.GLOBAL_CHAT)
80+
}
81+
}

back/src/ecs/system/network/WebsocketSystem.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
import { ConnectionMessage, ServerMessageType } from '../../../../../shared/network/server/index.js'
2323
import { EventSystem } from '../../../../../shared/system/EventSystem.js'
2424

25-
import { ChatMessageEvent } from '../../component/events/ChatMessageEvent.js'
25+
import { MessageEvent } from '../../component/events/MessageEvent.js'
2626
import { Player } from '../../entity/Player.js'
2727
import { InputProcessingSystem } from '../InputProcessingSystem.js'
2828
import { NetworkSystem } from './NetworkSystem.js'
@@ -166,7 +166,7 @@ export class WebsocketSystem {
166166
ws.send(NetworkSystem.compress(connectionMessage), true)
167167

168168
EventSystem.addEvent(
169-
new ChatMessageEvent(
169+
new MessageEvent(
170170
player.entity.id,
171171
'🖥️ [SERVER]',
172172
`Player ${player.entity.id} joined at ${new Date().toLocaleString()}`
@@ -226,7 +226,7 @@ export class WebsocketSystem {
226226
return
227227
}
228228
EventSystem.addEvent(
229-
new ChatMessageEvent(player.entity.id, `Player ${player.entity.id}`, content)
229+
new MessageEvent(player.entity.id, `Player ${player.entity.id}`, content)
230230
)
231231
}
232232
private handleProximityPromptInteractMessage(ws: any, message: ProximityPromptInteractMessage) {

back/src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Chat } from './ecs/entity/Chat.js'
88
import { AnimationSystem } from './ecs/system/AnimationSystem.js'
99
import { MovementSystem } from './ecs/system/MovementSystem.js'
1010
import { RandomizeSystem } from './ecs/system/RandomizeSystem.js'
11-
import { ChatEventSystem } from './ecs/system/events/ChatEventSystem.js'
11+
import { MessageEventSystem } from './ecs/system/events/MessageEventSystem.js'
1212
import { ColorEventSystem } from './ecs/system/events/ColorEventSystem.js'
1313
import { DestroyEventSystem } from './ecs/system/events/DestroyEventSystem.js'
1414
import { SingleSizeEventSystem } from './ecs/system/events/SingleSizeEventSystem.js'
@@ -58,7 +58,7 @@ const singleSizeEventSystem = new SingleSizeEventSystem()
5858
const sizeEventSystem = new SizeEventSystem()
5959
const syncPositionSystem = new SyncPositionSystem()
6060
const syncRotationSystem = new SyncRotationSystem()
61-
const chatSystem = new ChatEventSystem()
61+
const messageEventSystem = new MessageEventSystem()
6262
const destroyEventSystem = new DestroyEventSystem()
6363
const proximityPromptSystem = new ProximityPromptSystem()
6464

@@ -122,7 +122,7 @@ async function updateGameState(dt: number) {
122122
syncRotationSystem.update(entities)
123123
syncPositionSystem.update(entities)
124124

125-
chatSystem.update(entities)
125+
messageEventSystem.update(entities)
126126
lockedRotationSystem.update(entities)
127127
networkSystem.update(entities)
128128
sleepCheckSystem.update(entities)

back/src/sandbox.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { LockedRotationComponent } from './ecs/component/LockedRotationComponent
1313
import { RandomizeComponent } from './ecs/component/RandomizeComponent.js'
1414
import { SpawnPositionComponent } from './ecs/component/SpawnPositionComponent.js'
1515
import { ZombieComponent } from './ecs/component/ZombieComponent.js'
16-
import { ChatMessageEvent } from './ecs/component/events/ChatMessageEvent.js'
16+
import { MessageEvent } from './ecs/component/events/MessageEvent.js'
1717
import { OnCollisionEnterEvent } from './ecs/component/events/OnCollisionEnterEvent.js'
1818
import { OnCollisionExitEvent } from './ecs/component/events/OnCollisionExitEvent.js'
1919
import { BoxColliderComponent } from './ecs/component/physics/BoxColliderComponent.js'
@@ -23,7 +23,6 @@ import { KinematicRigidBodyComponent } from './ecs/component/physics/KinematicRi
2323
import { PhysicsPropertiesComponent } from './ecs/component/physics/PhysicsPropertiesComponent.js'
2424
import { SphereColliderComponent } from './ecs/component/physics/SphereColliderComponent.js'
2525
import { TrimeshColliderComponent } from './ecs/component/physics/TrimeshColliderComponent.js'
26-
import { ChatComponent } from './ecs/component/tag/TagChatComponent.js'
2726
import { PlayerComponent } from '../../shared/component/PlayerComponent.js'
2827
import { Cube } from './ecs/entity/Cube.js'
2928
import { MapWorld } from './ecs/entity/MapWorld.js'
@@ -45,6 +44,8 @@ import { Mesh } from './ecs/entity/Mesh.js'
4544
import { ComponentRemovedEvent } from '../../shared/component/events/ComponentRemovedEvent.js'
4645
import { ComponentAddedEvent } from '../../shared/component/events/ComponentAddedEvent.js'
4746
import { InvisibleComponent } from '../../shared/component/InvisibleComponent.js'
47+
import { ChatComponent } from './ecs/component/tag/TagChatComponent.js'
48+
import { SerializedMessageType } from '../../shared/network/server/serialized.js'
4849

4950
async function loadGameLogic() {
5051
const gameScript = process.env.GAME_SCRIPT || 'defaultScript.js' // Default script name if not provided
@@ -76,6 +77,8 @@ async function loadGameLogic() {
7677
NetworkDataComponent,
7778
TextComponent,
7879
InvisibleComponent,
80+
SerializedMessageType,
81+
7982

8083
// Physics Components
8184
BoxColliderComponent,
@@ -87,13 +90,13 @@ async function loadGameLogic() {
8790
PhysicsPropertiesComponent,
8891

8992
// Tag Components
90-
PlayerComponent,
93+
PlayerComponent,
9194
ChatComponent,
9295

9396
// Events
9497
OnCollisionEnterEvent,
9598
OnCollisionExitEvent,
96-
ChatMessageEvent,
99+
MessageEvent,
97100
ColorEvent,
98101
SizeEvent,
99102
SingleSizeEvent,

back/src/scripts/footballScript.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,17 @@ const chatEntity = EntityManager.getFirstEntityWithComponent(
4646
EntityManager.getInstance().getAllEntities(),
4747
ChatComponent
4848
)
49-
50-
const sendChatMessage = (author, message) => {
51-
EventSystem.addEvent(new ChatMessageEvent(chatEntity.id, author, message))
49+
function sendGlobalChatMessage(author, message) {
50+
EventSystem.addEvent(new MessageEvent(chatEntity.id, author, message, SerializedMessageType.GLOBAL_CHAT))
5251
}
5352

5453
const updateScore = () => {
55-
sendChatMessage('⚽', `Score: 🔴 Red ${redScore} - ${blueScore} Blue 🔵`)
54+
sendGlobalChatMessage('⚽', `Score: 🔴 Red ${redScore} - ${blueScore} Blue 🔵`)
5655
scoreText.updateText(`🔴 ${redScore} - ${blueScore} 🔵`)
5756
}
5857

5958
// Initialize chat and score
60-
sendChatMessage('⚽', 'Football NotBlox.Online')
59+
sendGlobalChatMessage('⚽', 'Football NotBlox.Online')
6160
updateScore()
6261

6362
// Team spawn teleporters and coloring
@@ -93,7 +92,7 @@ function handleGoal(scoringTeam) {
9392
if (scoringTeam === 'blue') blueScore++
9493
else redScore++
9594

96-
sendChatMessage('⚽', `${scoringTeam === 'blue' ? '🔵 Blue' : '🔴 Red'} team scores! 🎉`)
95+
sendGlobalChatMessage('⚽', `${scoringTeam === 'blue' ? '🔵 Blue' : '🔴 Red'} team scores! 🎉`)
9796
updateScore()
9897

9998
const body = ball.entity.getComponent(DynamicRigidBodyComponent).body
@@ -135,7 +134,7 @@ ScriptableSystem.update = (dt, entities) => {
135134

136135
if (!hasPlayers) {
137136
// No players are present. Reset the game
138-
sendChatMessage('⚽', 'No players, resetting game...')
137+
sendGlobalChatMessage('⚽', 'No players, resetting game...')
139138

140139
const ballBody = ball.entity.getComponent(DynamicRigidBodyComponent).body
141140
ballBody.setTranslation(

0 commit comments

Comments
 (0)