Merge branch 'develop' of github.com:thecodingmachine/workadventure

This commit is contained in:
_Bastler
2022-01-03 19:10:22 +01:00
52 changed files with 1449 additions and 863 deletions
+54 -16
View File
@@ -16,7 +16,8 @@ export class EmbeddedWebsiteManager {
if (website === undefined) {
throw new Error('Cannot find embedded website with name "' + name + '"');
}
const rect = website.iframe.getBoundingClientRect();
const scale = website.scale ?? 1;
return {
url: website.url,
name: website.name,
@@ -26,9 +27,11 @@ export class EmbeddedWebsiteManager {
position: {
x: website.phaserObject.x,
y: website.phaserObject.y,
width: rect["width"],
height: rect["height"],
width: website.phaserObject.width * scale,
height: website.phaserObject.height * scale,
},
origin: website.origin,
scale: website.scale,
};
});
@@ -59,7 +62,9 @@ export class EmbeddedWebsiteManager {
createEmbeddedWebsiteEvent.position.height,
createEmbeddedWebsiteEvent.visible ?? true,
createEmbeddedWebsiteEvent.allowApi ?? false,
createEmbeddedWebsiteEvent.allow ?? ""
createEmbeddedWebsiteEvent.allow ?? "",
createEmbeddedWebsiteEvent.origin ?? "map",
createEmbeddedWebsiteEvent.scale ?? 1
);
}
);
@@ -107,10 +112,18 @@ export class EmbeddedWebsiteManager {
website.phaserObject.y = embeddedWebsiteEvent.y;
}
if (embeddedWebsiteEvent?.width !== undefined) {
website.iframe.style.width = embeddedWebsiteEvent.width + "px";
website.position.width = embeddedWebsiteEvent.width;
website.iframe.style.width = embeddedWebsiteEvent.width / website.phaserObject.scale + "px";
}
if (embeddedWebsiteEvent?.height !== undefined) {
website.iframe.style.height = embeddedWebsiteEvent.height + "px";
website.position.height = embeddedWebsiteEvent.height;
website.iframe.style.height = embeddedWebsiteEvent.height / website.phaserObject.scale + "px";
}
if (embeddedWebsiteEvent?.scale !== undefined) {
website.phaserObject.scale = embeddedWebsiteEvent.scale;
website.iframe.style.width = website.position.width / embeddedWebsiteEvent.scale + "px";
website.iframe.style.height = website.position.height / embeddedWebsiteEvent.scale + "px";
}
}
);
@@ -125,7 +138,9 @@ export class EmbeddedWebsiteManager {
height: number,
visible: boolean,
allowApi: boolean,
allow: string
allow: string,
origin: "map" | "player" | undefined,
scale: number | undefined
): void {
if (this.embeddedWebsites.has(name)) {
throw new Error('An embedded website with the name "' + name + '" already exists in your map');
@@ -135,9 +150,9 @@ export class EmbeddedWebsiteManager {
name,
url,
/*x,
y,
width,
height,*/
y,
width,
height,*/
allow,
allowApi,
visible,
@@ -147,6 +162,8 @@ export class EmbeddedWebsiteManager {
width,
height,
},
origin,
scale,
};
const embeddedWebsite = this.doCreateEmbeddedWebsite(embeddedWebsiteEvent, visible);
@@ -161,22 +178,43 @@ export class EmbeddedWebsiteManager {
const absoluteUrl = new URL(embeddedWebsiteEvent.url, this.gameScene.MapUrlFile).toString();
const iframe = document.createElement("iframe");
const scale = embeddedWebsiteEvent.scale ?? 1;
iframe.src = absoluteUrl;
iframe.tabIndex = -1;
iframe.style.width = embeddedWebsiteEvent.position.width + "px";
iframe.style.height = embeddedWebsiteEvent.position.height + "px";
iframe.style.width = embeddedWebsiteEvent.position.width / scale + "px";
iframe.style.height = embeddedWebsiteEvent.position.height / scale + "px";
iframe.style.margin = "0";
iframe.style.padding = "0";
iframe.style.border = "none";
const domElement = new DOMElement(
this.gameScene,
embeddedWebsiteEvent.position.x,
embeddedWebsiteEvent.position.y,
iframe
);
domElement.setOrigin(0, 0);
if (embeddedWebsiteEvent.scale) {
domElement.scale = embeddedWebsiteEvent.scale;
}
domElement.setVisible(visible);
switch (embeddedWebsiteEvent.origin) {
case "player":
this.gameScene.CurrentPlayer.add(domElement);
break;
case "map":
default:
this.gameScene.add.existing(domElement);
}
const embeddedWebsite = {
...embeddedWebsiteEvent,
phaserObject: this.gameScene.add
.dom(embeddedWebsiteEvent.position.x, embeddedWebsiteEvent.position.y, iframe)
.setVisible(visible)
.setOrigin(0, 0),
phaserObject: domElement,
iframe: iframe,
};
if (embeddedWebsiteEvent.allowApi) {
iframeListener.registerIframe(iframe);
}
+4 -4
View File
@@ -1,13 +1,13 @@
import { emoteEventStream } from "../../Connexion/EmoteEventStream";
import type { GameScene } from "./GameScene";
import type { Subscription } from "rxjs";
import type { RoomConnection } from "../../Connexion/RoomConnection";
export class EmoteManager {
private subscription: Subscription;
constructor(private scene: GameScene) {
this.subscription = emoteEventStream.stream.subscribe((event) => {
const actor = this.scene.MapPlayersByKey.get(event.userId);
constructor(private scene: GameScene, private connection: RoomConnection) {
this.subscription = connection.emoteEventMessageStream.subscribe((event) => {
const actor = this.scene.MapPlayersByKey.get(event.actorUserId);
if (actor) {
actor.playEmote(event.emote);
}
+98 -29
View File
@@ -40,7 +40,6 @@ import { ReconnectingSceneName } from "../Reconnecting/ReconnectingScene";
import { GameMap } from "./GameMap";
import { PlayerMovement } from "./PlayerMovement";
import { PlayersPositionInterpolator } from "./PlayersPositionInterpolator";
import { worldFullMessageStream } from "../../Connexion/WorldFullMessageStream";
import { DirtyScene } from "./DirtyScene";
import { TextUtils } from "../Components/TextUtils";
import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick";
@@ -60,7 +59,6 @@ import type {
PositionInterface,
RoomJoinedMessageInterface,
} from "../../Connexion/ConnexionModels";
import type { UserMovedMessage } from "../../Messages/generated/messages_pb";
import type { RoomConnection } from "../../Connexion/RoomConnection";
import type { ActionableItem } from "../Items/ActionableItem";
import type { ItemFactoryInterface } from "../Items/ItemFactoryInterface";
@@ -90,9 +88,10 @@ import SpriteSheetFile = Phaser.Loader.FileTypes.SpriteSheetFile;
import { deepCopy } from "deep-copy-ts";
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
import { MapStore } from "../../Stores/Utils/MapStore";
import { SetPlayerDetailsMessage } from "../../Messages/generated/messages_pb";
import { followUsersColorStore, followUsersStore } from "../../Stores/FollowStore";
import { getColorRgbFromHue } from "../../WebRtc/ColorGenerator";
import Camera = Phaser.Cameras.Scene2D.Camera;
import type { WasCameraUpdatedEvent } from "../../Api/Events/WasCameraUpdatedEvent";
export interface GameSceneInitInterface {
initPosition: PointInterface | null;
@@ -210,6 +209,8 @@ export class GameScene extends DirtyScene {
private objectsByType = new Map<string, ITiledMapObject[]>();
private embeddedWebsiteManager!: EmbeddedWebsiteManager;
private loader: Loader;
private lastCameraEvent: WasCameraUpdatedEvent | undefined;
private firstCameraUpdateSent: boolean = false;
constructor(private room: Room, MapUrlFile: string, customKey?: string | undefined) {
super({
@@ -454,10 +455,6 @@ export class GameScene extends DirtyScene {
this.pinchManager = new PinchManager(this);
}
this.messageSubscription = worldFullMessageStream.stream.subscribe((message) =>
this.showWorldFullError(message)
);
const playerName = gameManager.getPlayerName();
if (!playerName) {
throw "playerName is not set";
@@ -540,7 +537,9 @@ export class GameScene extends DirtyScene {
object.height,
object.visible,
allowApi ?? false,
""
"",
"map",
1
);
}
}
@@ -634,8 +633,6 @@ export class GameScene extends DirtyScene {
this.connect();
}
this.emoteManager = new EmoteManager(this);
let oldPeerNumber = 0;
this.peerStoreUnsubscribe = peerStore.subscribe((peers) => {
const newPeerNumber = peers.size;
@@ -710,7 +707,7 @@ export class GameScene extends DirtyScene {
playersStore.connectToRoomConnection(this.connection);
userIsAdminStore.set(this.connection.hasTag("admin"));
this.connection.onUserJoins((message: MessageUserJoined) => {
this.connection.userJoinedMessageStream.subscribe((message) => {
const userMessage: AddPlayerInterface = {
userId: message.userId,
characterLayers: message.characterLayers,
@@ -724,31 +721,33 @@ export class GameScene extends DirtyScene {
this.addPlayer(userMessage);
});
this.connection.onUserMoved((message: UserMovedMessage) => {
const position = message.getPosition();
this.connection.userMovedMessageStream.subscribe((message) => {
const position = message.position;
if (position === undefined) {
throw new Error("Position missing from UserMovedMessage");
}
const messageUserMoved: MessageUserMovedInterface = {
userId: message.getUserid(),
userId: message.userId,
position: ProtobufClientUtils.toPointInterface(position),
};
this.updatePlayerPosition(messageUserMoved);
});
this.connection.onUserLeft((userId: number) => {
this.removePlayer(userId);
this.connection.userLeftMessageStream.subscribe((message) => {
this.removePlayer(message.userId);
});
this.connection.onGroupUpdatedOrCreated((groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
this.shareGroupPosition(groupPositionMessage);
});
this.connection.groupUpdateMessageStream.subscribe(
(groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
this.shareGroupPosition(groupPositionMessage);
}
);
this.connection.onGroupDeleted((groupId: number) => {
this.connection.groupDeleteMessageStream.subscribe((message) => {
try {
this.deleteGroup(groupId);
this.deleteGroup(message.groupId);
} catch (e) {
console.error(e);
}
@@ -760,7 +759,7 @@ export class GameScene extends DirtyScene {
this.createSuccessorGameScene(true, true);
});
this.connection.onActionableEvent((message) => {
this.connection.itemEventMessageStream.subscribe((message) => {
const item = this.actionableItems.get(message.itemId);
if (item === undefined) {
console.warn(
@@ -773,18 +772,29 @@ export class GameScene extends DirtyScene {
item.fire(message.event, message.state, message.parameters);
});
this.connection.onPlayerDetailsUpdated((message) => {
this.connection.playerDetailsUpdatedMessageStream.subscribe((message) => {
if (message.details === undefined) {
throw new Error("Malformed message. Missing details in PlayerDetailsUpdatedMessage");
}
this.pendingEvents.enqueue({
type: "PlayerDetailsUpdated",
details: message,
details: {
userId: message.userId,
outlineColor: message.details.outlineColor,
removeOutlineColor: message.details.removeOutlineColor,
},
});
});
/**
* Triggered when we receive the JWT token to connect to Jitsi
*/
this.connection.onStartJitsiRoom((jwt, room) => {
this.startJitsi(room, jwt);
this.connection.sendJitsiJwtMessageStream.subscribe((message) => {
this.startJitsi(message.jitsiRoom, message.jwt);
});
this.messageSubscription = this.connection.worldFullMessageStream.subscribe((message) => {
this.showWorldFullError(message);
});
// When connection is performed, let's connect SimplePeer
@@ -859,6 +869,8 @@ export class GameScene extends DirtyScene {
});
});
this.emoteManager = new EmoteManager(this, this.connection);
// this.gameMap.onLeaveLayer((layers) => {
// layers.forEach((layer) => {
// iframeListener.sendLeaveLayerEvent(layer.name);
@@ -1121,9 +1133,33 @@ export class GameScene extends DirtyScene {
);
this.iframeSubscriptionList.push(
iframeListener.stopSoundStream.subscribe((stopSoundEvent) => {
const url = new URL(stopSoundEvent.url, this.MapUrlFile);
soundManager.stopSound(this.sound, url.toString());
iframeListener.trackCameraUpdateStream.subscribe(() => {
if (!this.firstCameraUpdateSent) {
this.cameras.main.on("followupdate", (camera: Camera) => {
const cameraEvent: WasCameraUpdatedEvent = {
x: camera.worldView.x,
y: camera.worldView.y,
width: camera.worldView.width,
height: camera.worldView.height,
zoom: camera.scaleManager.zoom,
};
if (
this.lastCameraEvent?.x == cameraEvent.x &&
this.lastCameraEvent?.y == cameraEvent.y &&
this.lastCameraEvent?.width == cameraEvent.width &&
this.lastCameraEvent?.height == cameraEvent.height &&
this.lastCameraEvent?.zoom == cameraEvent.zoom
) {
return;
}
this.lastCameraEvent = cameraEvent;
iframeListener.sendCameraUpdated(cameraEvent);
this.firstCameraUpdateSent = true;
});
iframeListener.sendCameraUpdated(this.cameras.main);
}
})
);
@@ -1186,6 +1222,12 @@ export class GameScene extends DirtyScene {
})
);
this.iframeSubscriptionList.push(
iframeListener.setPropertyStream.subscribe((setProperty) => {
this.setPropertyLayer(setProperty.layerName, setProperty.propertyName, setProperty.propertyValue);
})
);
iframeListener.registerAnswerer("openCoWebsite", async (openCoWebsite, source) => {
if (!source) {
throw new Error("Unknown query source");
@@ -1261,6 +1303,7 @@ export class GameScene extends DirtyScene {
roomId: this.roomUrl,
tags: this.connection ? this.connection.getAllTags() : [],
variables: this.sharedVariablesManager.variables,
playerVariables: localUserStore.getAllUserProperties(),
userRoomToken: this.connection ? this.connection.userRoomToken : "",
};
});
@@ -1358,6 +1401,22 @@ export class GameScene extends DirtyScene {
})
);
iframeListener.registerAnswerer("setVariable", (event, source) => {
switch (event.target) {
case "global": {
this.sharedVariablesManager.setVariable(event, source);
break;
}
case "player": {
localUserStore.setUserProperty(event.key, event.value);
break;
}
default: {
const _exhaustiveCheck: never = event.target;
}
}
});
iframeListener.registerAnswerer("removeActionMessage", (message) => {
layoutManagerActionStore.removeAction(message.uuid);
});
@@ -1376,6 +1435,13 @@ export class GameScene extends DirtyScene {
this.CurrentPlayer.removeOutlineColor();
this.connection?.emitPlayerOutlineColor(null);
});
iframeListener.registerAnswerer("getPlayerPosition", () => {
return {
x: this.CurrentPlayer.x,
y: this.CurrentPlayer.y,
};
});
}
private setPropertyLayer(
@@ -1500,6 +1566,7 @@ export class GameScene extends DirtyScene {
iframeListener.unregisterAnswerer("openCoWebsite");
iframeListener.unregisterAnswerer("getCoWebsites");
iframeListener.unregisterAnswerer("setPlayerOutline");
iframeListener.unregisterAnswerer("setVariable");
this.sharedVariablesManager?.close();
this.embeddedWebsiteManager?.close();
@@ -1978,6 +2045,7 @@ export class GameScene extends DirtyScene {
this.loader.resize();
}
private getObjectLayerData(objectName: string): ITiledMapObject | undefined {
for (const layer of this.mapFile.layers) {
if (layer.type === "objectgroup" && layer.name === "floorLayer") {
@@ -1990,6 +2058,7 @@ export class GameScene extends DirtyScene {
}
return undefined;
}
private reposition(): void {
// Recompute camera offset if needed
biggestAvailableAreaStore.recompute();
+37 -36
View File
@@ -3,6 +3,7 @@ import { iframeListener } from "../../Api/IframeListener";
import type { GameMap } from "./GameMap";
import type { ITiledMapLayer, ITiledMapObject } from "../Map/ITiledMap";
import { GameMapProperties } from "./GameMapProperties";
import type { SetVariableEvent } from "../../Api/Events/SetVariableEvent";
interface Variable {
defaultValue: unknown;
@@ -41,58 +42,58 @@ export class SharedVariablesManager {
this._variables.set(name, value);
}
roomConnection.onSetVariable((name, value) => {
roomConnection.variableMessageStream.subscribe(({ name, value }) => {
this._variables.set(name, value);
// On server change, let's notify the iframes
iframeListener.setVariable({
key: name,
value: value,
target: "global",
});
});
}
// When a variable is modified from an iFrame
iframeListener.registerAnswerer("setVariable", (event, source) => {
const key = event.key;
public setVariable(event: SetVariableEvent, source: MessageEventSource | null): void {
const key = event.key;
const object = this.variableObjects.get(key);
const object = this.variableObjects.get(key);
if (object === undefined) {
const errMsg =
'A script is trying to modify variable "' +
key +
'" but this variable is not defined in the map.' +
'There should be an object in the map whose name is "' +
key +
'" and whose type is "variable"';
console.error(errMsg);
throw new Error(errMsg);
}
if (object === undefined) {
const errMsg =
'A script is trying to modify variable "' +
key +
'" but this variable is not defined in the map.' +
'There should be an object in the map whose name is "' +
key +
'" and whose type is "variable"';
console.error(errMsg);
throw new Error(errMsg);
}
if (object.writableBy && !this.roomConnection.hasTag(object.writableBy)) {
const errMsg =
'A script is trying to modify variable "' +
key +
'" but this variable is only writable for users with tag "' +
object.writableBy +
'".';
console.error(errMsg);
throw new Error(errMsg);
}
if (object.writableBy && !this.roomConnection.hasTag(object.writableBy)) {
const errMsg =
'A script is trying to modify variable "' +
key +
'" but this variable is only writable for users with tag "' +
object.writableBy +
'".';
console.error(errMsg);
throw new Error(errMsg);
}
// Let's stop any propagation of the value we set is the same as the existing value.
if (JSON.stringify(event.value) === JSON.stringify(this._variables.get(key))) {
return;
}
// Let's stop any propagation of the value we set is the same as the existing value.
if (JSON.stringify(event.value) === JSON.stringify(this._variables.get(key))) {
return;
}
this._variables.set(key, event.value);
this._variables.set(key, event.value);
// Dispatch to the room connection.
this.roomConnection.emitSetVariableEvent(key, event.value);
// Dispatch to the room connection.
this.roomConnection.emitSetVariableEvent(key, event.value);
// Dispatch to other iframes
iframeListener.dispatchVariableToOtherIframes(key, event.value, source);
});
// Dispatch to other iframes
iframeListener.dispatchVariableToOtherIframes(key, event.value, source);
}
private static findVariablesInMap(gameMap: GameMap): Map<string, Variable> {
+12 -6
View File
@@ -100,10 +100,6 @@ export class Player extends Character {
return [xMovement, yMovement];
}
public enableFollowing() {
followStateStore.set("active");
}
public moveUser(delta: number): void {
const activeEvents = this.userInputManager.getEventListForGameTick();
const state = get(followStateStore);
@@ -111,8 +107,7 @@ export class Player extends Character {
if (activeEvents.get(UserInputEvent.Follow)) {
if (state === "off" && this.scene.groups.size > 0) {
followStateStore.set("requesting");
followRoleStore.set("leader");
this.sendFollowRequest();
} else if (state === "active") {
followStateStore.set("ending");
}
@@ -125,4 +120,15 @@ export class Player extends Character {
}
this.inputStep(activeEvents, x, y);
}
public sendFollowRequest() {
this.scene.connection?.emitFollowRequest();
followRoleStore.set("leader");
followStateStore.set("active");
}
public startFollowing() {
followStateStore.set("active");
this.scene.connection?.emitFollowConfirmation();
}
}
@@ -31,6 +31,10 @@ export class WaScaleManager {
height: height * devicePixelRatio,
});
if (gameSize.width == 0) {
return;
}
this.actualZoom = realSize.width / gameSize.width / devicePixelRatio;
this.scaleManager.setZoom(realSize.width / gameSize.width / devicePixelRatio);