Merge branch 'develop' of github.com:thecodingmachine/workadventure into develop
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
EmoteCallback,
|
||||
EntersCallback,
|
||||
LeavesCallback,
|
||||
LockGroupCallback,
|
||||
MovesCallback,
|
||||
PlayerDetailsUpdatedCallback,
|
||||
} from "_Model/Zone";
|
||||
@@ -44,7 +45,7 @@ export class GameRoom {
|
||||
// Users, sorted by ID
|
||||
private readonly users = new Map<number, User>();
|
||||
private readonly usersByUuid = new Map<string, User>();
|
||||
private readonly groups = new Set<Group>();
|
||||
private readonly groups: Map<number, Group> = new Map<number, Group>();
|
||||
private readonly admins = new Set<Admin>();
|
||||
|
||||
private itemsState = new Map<number, unknown>();
|
||||
@@ -66,6 +67,7 @@ export class GameRoom {
|
||||
onMoves: MovesCallback,
|
||||
onLeaves: LeavesCallback,
|
||||
onEmote: EmoteCallback,
|
||||
onLockGroup: LockGroupCallback,
|
||||
onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
|
||||
) {
|
||||
// A zone is 10 sprites wide.
|
||||
@@ -76,6 +78,7 @@ export class GameRoom {
|
||||
onMoves,
|
||||
onLeaves,
|
||||
onEmote,
|
||||
onLockGroup,
|
||||
onPlayerDetailsUpdated
|
||||
);
|
||||
}
|
||||
@@ -90,6 +93,7 @@ export class GameRoom {
|
||||
onMoves: MovesCallback,
|
||||
onLeaves: LeavesCallback,
|
||||
onEmote: EmoteCallback,
|
||||
onLockGroup: LockGroupCallback,
|
||||
onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
|
||||
): Promise<GameRoom> {
|
||||
const mapDetails = await GameRoom.getMapDetails(roomUrl);
|
||||
@@ -105,6 +109,7 @@ export class GameRoom {
|
||||
onMoves,
|
||||
onLeaves,
|
||||
onEmote,
|
||||
onLockGroup,
|
||||
onPlayerDetailsUpdated
|
||||
);
|
||||
|
||||
@@ -244,7 +249,7 @@ export class GameRoom {
|
||||
this.disconnectCallback,
|
||||
this.positionNotifier
|
||||
);
|
||||
this.groups.add(group);
|
||||
this.groups.set(group.getId(), group);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -328,7 +333,7 @@ export class GameRoom {
|
||||
this.disconnectCallback,
|
||||
this.positionNotifier
|
||||
);
|
||||
this.groups.add(newGroup);
|
||||
this.groups.set(newGroup.getId(), newGroup);
|
||||
} else {
|
||||
this.leaveGroup(user);
|
||||
}
|
||||
@@ -375,10 +380,10 @@ export class GameRoom {
|
||||
group.leave(user);
|
||||
if (group.isEmpty()) {
|
||||
group.destroy();
|
||||
if (!this.groups.has(group)) {
|
||||
if (!this.groups.has(group.getId())) {
|
||||
throw new Error(`Could not find group ${group.getId()} referenced by user ${user.id} in World.`);
|
||||
}
|
||||
this.groups.delete(group);
|
||||
this.groups.delete(group.getId());
|
||||
//todo: is the group garbage collected?
|
||||
} else {
|
||||
group.updatePosition();
|
||||
@@ -418,7 +423,7 @@ export class GameRoom {
|
||||
});
|
||||
|
||||
this.groups.forEach((group: Group) => {
|
||||
if (group.isFull()) {
|
||||
if (group.isFull() || group.isLocked()) {
|
||||
return;
|
||||
}
|
||||
const distance = GameRoom.computeDistanceBetweenPositions(user.getPosition(), group.getPosition());
|
||||
@@ -544,6 +549,10 @@ export class GameRoom {
|
||||
this.positionNotifier.emitEmoteEvent(user, emoteEventMessage);
|
||||
}
|
||||
|
||||
public emitLockGroupEvent(user: User, groupId: number) {
|
||||
this.positionNotifier.emitLockGroupEvent(user, groupId);
|
||||
}
|
||||
|
||||
public addRoomListener(socket: RoomSocket) {
|
||||
this.roomListeners.add(socket);
|
||||
}
|
||||
@@ -657,4 +666,8 @@ export class GameRoom {
|
||||
const variablesManager = await this.getVariableManager();
|
||||
return variablesManager.getVariablesForTags(tags);
|
||||
}
|
||||
|
||||
public getGroupById(id: number): Group | undefined {
|
||||
return this.groups.get(id);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -14,6 +14,7 @@ export class Group implements Movable {
|
||||
private x!: number;
|
||||
private y!: number;
|
||||
private wasDestroyed: boolean = false;
|
||||
private locked: boolean = false;
|
||||
private roomId: string;
|
||||
private currentZone: Zone | null = null;
|
||||
/**
|
||||
@@ -141,15 +142,19 @@ export class Group implements Movable {
|
||||
return this.users.size >= MAX_PER_GROUP;
|
||||
}
|
||||
|
||||
isLocked(): boolean {
|
||||
return this.locked;
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
return this.users.size <= 1;
|
||||
}
|
||||
|
||||
join(user: User): void {
|
||||
// Broadcast on the right event
|
||||
this.connectCallback(user, this);
|
||||
this.users.add(user);
|
||||
user.group = this;
|
||||
this.connectCallback(user, this);
|
||||
}
|
||||
|
||||
leave(user: User): void {
|
||||
@@ -167,6 +172,10 @@ export class Group implements Movable {
|
||||
this.disconnectCallback(user, this);
|
||||
}
|
||||
|
||||
lock(lock: boolean = true): void {
|
||||
this.locked = lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Let's kick everybody out.
|
||||
* Usually used when there is only one user left.
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
EmoteCallback,
|
||||
EntersCallback,
|
||||
LeavesCallback,
|
||||
LockGroupCallback,
|
||||
MovesCallback,
|
||||
PlayerDetailsUpdatedCallback,
|
||||
Zone,
|
||||
@@ -50,6 +51,7 @@ export class PositionNotifier {
|
||||
private onUserMoves: MovesCallback,
|
||||
private onUserLeaves: LeavesCallback,
|
||||
private onEmote: EmoteCallback,
|
||||
private onLockGroup: LockGroupCallback,
|
||||
private onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback
|
||||
) {}
|
||||
|
||||
@@ -111,6 +113,7 @@ export class PositionNotifier {
|
||||
this.onUserMoves,
|
||||
this.onUserLeaves,
|
||||
this.onEmote,
|
||||
this.onLockGroup,
|
||||
this.onPlayerDetailsUpdated,
|
||||
i,
|
||||
j
|
||||
@@ -137,6 +140,12 @@ export class PositionNotifier {
|
||||
zone.emitEmoteEvent(emoteEventMessage);
|
||||
}
|
||||
|
||||
public emitLockGroupEvent(user: User, groupId: number) {
|
||||
const zoneDesc = this.getZoneDescriptorFromCoordinates(user.getPosition().x, user.getPosition().y);
|
||||
const zone = this.getZone(zoneDesc.i, zoneDesc.j);
|
||||
zone.emitLockGroupEvent(groupId);
|
||||
}
|
||||
|
||||
public *getAllUsersInSquareAroundZone(zone: Zone): Generator<User> {
|
||||
const zoneDescriptor = this.getZoneDescriptorFromCoordinates(zone.x, zone.y);
|
||||
for (const d of getNearbyDescriptorsMatrix(zoneDescriptor)) {
|
||||
|
||||
@@ -13,6 +13,7 @@ export type EntersCallback = (thing: Movable, fromZone: Zone | null, listener: Z
|
||||
export type MovesCallback = (thing: Movable, position: PositionInterface, listener: ZoneSocket) => void;
|
||||
export type LeavesCallback = (thing: Movable, newZone: Zone | null, listener: ZoneSocket) => void;
|
||||
export type EmoteCallback = (emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) => void;
|
||||
export type LockGroupCallback = (groupId: number, listener: ZoneSocket) => void;
|
||||
export type PlayerDetailsUpdatedCallback = (
|
||||
playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage,
|
||||
listener: ZoneSocket
|
||||
@@ -27,6 +28,7 @@ export class Zone {
|
||||
private onMoves: MovesCallback,
|
||||
private onLeaves: LeavesCallback,
|
||||
private onEmote: EmoteCallback,
|
||||
private onLockGroup: LockGroupCallback,
|
||||
private onPlayerDetailsUpdated: PlayerDetailsUpdatedCallback,
|
||||
public readonly x: number,
|
||||
public readonly y: number
|
||||
@@ -108,6 +110,12 @@ export class Zone {
|
||||
}
|
||||
}
|
||||
|
||||
public emitLockGroupEvent(groupId: number) {
|
||||
for (const listener of this.listeners) {
|
||||
this.onLockGroup(groupId, listener);
|
||||
}
|
||||
}
|
||||
|
||||
public updatePlayerDetails(user: User, playerDetails: SetPlayerDetailsMessage) {
|
||||
const playerDetailsUpdatedMessage = new PlayerDetailsUpdatedMessage();
|
||||
playerDetailsUpdatedMessage.setUserid(user.id);
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
WebRtcSignalToServerMessage,
|
||||
WorldFullWarningToRoomMessage,
|
||||
ZoneMessage,
|
||||
LockGroupPromptMessage,
|
||||
} from "./Messages/generated/messages_pb";
|
||||
import { sendUnaryData, ServerDuplexStream, ServerUnaryCall, ServerWritableStream } from "grpc";
|
||||
import { socketManager } from "./Services/SocketManager";
|
||||
@@ -135,6 +136,12 @@ const roomManager: IRoomManagerServer = {
|
||||
user,
|
||||
message.getFollowabortmessage() as FollowAbortMessage
|
||||
);
|
||||
} else if (message.hasLockgrouppromptmessage()) {
|
||||
socketManager.handleLockGroupPromptMessage(
|
||||
room,
|
||||
user,
|
||||
message.getLockgrouppromptmessage() as LockGroupPromptMessage
|
||||
);
|
||||
} else if (message.hasSendusermessage()) {
|
||||
const sendUserMessage = message.getSendusermessage();
|
||||
socketManager.handleSendUserMessage(user, sendUserMessage as SendUserMessage);
|
||||
|
||||
@@ -38,6 +38,9 @@ import {
|
||||
SubToPusherRoomMessage,
|
||||
SetPlayerDetailsMessage,
|
||||
PlayerDetailsUpdatedMessage,
|
||||
GroupUsersUpdateMessage,
|
||||
LockGroupPromptMessage,
|
||||
RoomMessage,
|
||||
} from "../Messages/generated/messages_pb";
|
||||
import { User, UserSocket } from "../Model/User";
|
||||
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
||||
@@ -68,7 +71,6 @@ function emitZoneMessage(subMessage: SubToPusherMessage, socket: ZoneSocket): vo
|
||||
// TODO: should we batch those every 100ms?
|
||||
const batchMessage = new BatchToPusherMessage();
|
||||
batchMessage.addPayload(subMessage);
|
||||
|
||||
socket.write(batchMessage);
|
||||
}
|
||||
|
||||
@@ -266,18 +268,28 @@ export class SocketManager {
|
||||
if (roomPromise === undefined) {
|
||||
roomPromise = GameRoom.create(
|
||||
roomId,
|
||||
(user: User, group: Group) => this.joinWebRtcRoom(user, group),
|
||||
(user: User, group: Group) => this.disConnectedUser(user, group),
|
||||
(user: User, group: Group) => {
|
||||
this.joinWebRtcRoom(user, group);
|
||||
this.sendGroupUsersUpdateToGroupMembers(group);
|
||||
},
|
||||
(user: User, group: Group) => {
|
||||
this.disConnectedUser(user, group);
|
||||
this.sendGroupUsersUpdateToGroupMembers(group);
|
||||
},
|
||||
MINIMUM_DISTANCE,
|
||||
GROUP_RADIUS,
|
||||
(thing: Movable, fromZone: Zone | null, listener: ZoneSocket) =>
|
||||
this.onZoneEnter(thing, fromZone, listener),
|
||||
(thing: Movable, fromZone: Zone | null, listener: ZoneSocket) => {
|
||||
this.onZoneEnter(thing, fromZone, listener);
|
||||
},
|
||||
(thing: Movable, position: PositionInterface, listener: ZoneSocket) =>
|
||||
this.onClientMove(thing, position, listener),
|
||||
(thing: Movable, newZone: Zone | null, listener: ZoneSocket) =>
|
||||
this.onClientLeave(thing, newZone, listener),
|
||||
(emoteEventMessage: EmoteEventMessage, listener: ZoneSocket) =>
|
||||
this.onEmote(emoteEventMessage, listener),
|
||||
(groupId: number, listener: ZoneSocket) => {
|
||||
void this.onLockGroup(groupId, listener, roomPromise);
|
||||
},
|
||||
(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, listener: ZoneSocket) =>
|
||||
this.onPlayerDetailsUpdated(playerDetailsUpdatedMessage, listener)
|
||||
)
|
||||
@@ -381,10 +393,24 @@ export class SocketManager {
|
||||
emitZoneMessage(subMessage, client);
|
||||
}
|
||||
|
||||
private async onLockGroup(
|
||||
groupId: number,
|
||||
client: ZoneSocket,
|
||||
roomPromise: PromiseLike<GameRoom> | undefined
|
||||
): Promise<void> {
|
||||
if (!roomPromise) {
|
||||
return;
|
||||
}
|
||||
const group = (await roomPromise).getGroupById(groupId);
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
this.emitCreateUpdateGroupEvent(client, null, group);
|
||||
}
|
||||
|
||||
private onPlayerDetailsUpdated(playerDetailsUpdatedMessage: PlayerDetailsUpdatedMessage, client: ZoneSocket) {
|
||||
const subMessage = new SubToPusherMessage();
|
||||
subMessage.setPlayerdetailsupdatedmessage(playerDetailsUpdatedMessage);
|
||||
|
||||
emitZoneMessage(subMessage, client);
|
||||
}
|
||||
|
||||
@@ -398,6 +424,7 @@ export class SocketManager {
|
||||
groupUpdateMessage.setPosition(pointMessage);
|
||||
groupUpdateMessage.setGroupsize(group.getSize);
|
||||
groupUpdateMessage.setFromzone(this.toProtoZone(fromZone));
|
||||
groupUpdateMessage.setLocked(group.isLocked());
|
||||
|
||||
const subMessage = new SubToPusherMessage();
|
||||
subMessage.setGroupupdatezonemessage(groupUpdateMessage);
|
||||
@@ -413,7 +440,6 @@ export class SocketManager {
|
||||
|
||||
const subMessage = new SubToPusherMessage();
|
||||
subMessage.setGroupleftzonemessage(groupDeleteMessage);
|
||||
|
||||
emitZoneMessage(subMessage, client);
|
||||
//user.emitInBatch(subMessage);
|
||||
}
|
||||
@@ -425,7 +451,6 @@ export class SocketManager {
|
||||
|
||||
const subMessage = new SubToPusherMessage();
|
||||
subMessage.setUserleftzonemessage(userLeftMessage);
|
||||
|
||||
emitZoneMessage(subMessage, client);
|
||||
}
|
||||
|
||||
@@ -439,6 +464,19 @@ export class SocketManager {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private sendGroupUsersUpdateToGroupMembers(group: Group) {
|
||||
const groupUserUpdateMessage = new GroupUsersUpdateMessage();
|
||||
groupUserUpdateMessage.setGroupid(group.getId());
|
||||
groupUserUpdateMessage.setUseridsList(group.getUsers().map((user) => user.id));
|
||||
|
||||
const clientMessage = new ServerToClientMessage();
|
||||
clientMessage.setGroupusersupdatemessage(groupUserUpdateMessage);
|
||||
|
||||
group.getUsers().forEach((currentUser: User) => {
|
||||
currentUser.socket.write(clientMessage);
|
||||
});
|
||||
}
|
||||
|
||||
private joinWebRtcRoom(user: User, group: Group) {
|
||||
for (const otherUser of group.getUsers()) {
|
||||
if (user === otherUser) {
|
||||
@@ -634,6 +672,7 @@ export class SocketManager {
|
||||
const groupUpdateMessage = new GroupUpdateZoneMessage();
|
||||
groupUpdateMessage.setGroupid(thing.getId());
|
||||
groupUpdateMessage.setPosition(ProtobufUtils.toPointMessage(thing.getPosition()));
|
||||
groupUpdateMessage.setLocked(thing.isLocked());
|
||||
|
||||
const subMessage = new SubToPusherMessage();
|
||||
subMessage.setGroupupdatezonemessage(groupUpdateMessage);
|
||||
@@ -870,6 +909,15 @@ export class SocketManager {
|
||||
leader?.delFollower(user);
|
||||
}
|
||||
}
|
||||
|
||||
handleLockGroupPromptMessage(room: GameRoom, user: User, message: LockGroupPromptMessage) {
|
||||
const group = user.group;
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
group.lock(message.getLock());
|
||||
room.emitLockGroupEvent(user, group.getId());
|
||||
}
|
||||
}
|
||||
|
||||
export const socketManager = new SocketManager();
|
||||
|
||||
@@ -52,6 +52,7 @@ describe("GameRoom", () => {
|
||||
() => {},
|
||||
() => {},
|
||||
emote,
|
||||
() => {},
|
||||
() => {}
|
||||
);
|
||||
|
||||
@@ -88,6 +89,7 @@ describe("GameRoom", () => {
|
||||
() => {},
|
||||
() => {},
|
||||
emote,
|
||||
() => {},
|
||||
() => {}
|
||||
);
|
||||
|
||||
@@ -128,6 +130,7 @@ describe("GameRoom", () => {
|
||||
() => {},
|
||||
() => {},
|
||||
emote,
|
||||
() => {},
|
||||
() => {}
|
||||
);
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ describe("PositionNotifier", () => {
|
||||
leaveTriggered = true;
|
||||
},
|
||||
() => {},
|
||||
() => {},
|
||||
() => {}
|
||||
);
|
||||
|
||||
@@ -132,6 +133,7 @@ describe("PositionNotifier", () => {
|
||||
leaveTriggered = true;
|
||||
},
|
||||
() => {},
|
||||
() => {},
|
||||
() => {}
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user