Actions menu api (#1862)
* wip * wip * random action on click * removing actions * register single key per command use * change removeActionsMenu action name * fixed actions menu not hiding content properly: * actions menu fix * added mock Block Player action * ActionsMenu buttons styling * added displaying priority for menu actions * moved utils actionMenu features to the UI * import as a type: * more object oriented style for API * removed registered actions from RemotePlayer instance * readme update * Fixing typos / Improving wording * added instructions on AlterActionsMenu test map Co-authored-by: Hanusiak Piotr <piotr@ltmp.co> Co-authored-by: David Négrier <d.negrier@thecodingmachine.com>
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
export const isActionsMenuActionClickedEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
id: tg.isNumber,
|
||||
actionName: tg.isString,
|
||||
})
|
||||
.get();
|
||||
|
||||
export type ActionsMenuActionClickedEvent = tg.GuardedType<typeof isActionsMenuActionClickedEvent>;
|
||||
|
||||
export type ActionsMenuActionClickedEventCallback = (event: ActionsMenuActionClickedEvent) => void;
|
||||
@@ -0,0 +1,12 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
export const isAddActionsMenuKeyToRemotePlayerEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
id: tg.isNumber,
|
||||
actionKey: tg.isString,
|
||||
})
|
||||
.get();
|
||||
|
||||
export type AddActionsMenuKeyToRemotePlayerEvent = tg.GuardedType<typeof isAddActionsMenuKeyToRemotePlayerEvent>;
|
||||
|
||||
export type AddActionsMenuKeyToRemotePlayerEventCallback = (event: AddActionsMenuKeyToRemotePlayerEvent) => void;
|
||||
@@ -36,6 +36,10 @@ import type { CameraFollowPlayerEvent } from "./CameraFollowPlayerEvent";
|
||||
import { isColorEvent } from "./ColorEvent";
|
||||
import { isMovePlayerToEventConfig } from "./MovePlayerToEvent";
|
||||
import { isMovePlayerToEventAnswer } from "./MovePlayerToEventAnswer";
|
||||
import type { RemotePlayerClickedEvent } from "./RemotePlayerClickedEvent";
|
||||
import type { AddActionsMenuKeyToRemotePlayerEvent } from "./AddActionsMenuKeyToRemotePlayerEvent";
|
||||
import type { ActionsMenuActionClickedEvent } from "./ActionsMenuActionClickedEvent";
|
||||
import type { RemoveActionsMenuKeyFromRemotePlayerEvent } from "./RemoveActionsMenuKeyFromRemotePlayerEvent";
|
||||
|
||||
export interface TypedMessageEvent<T> extends MessageEvent {
|
||||
data: T;
|
||||
@@ -45,6 +49,8 @@ export interface TypedMessageEvent<T> extends MessageEvent {
|
||||
* List event types sent from an iFrame to WorkAdventure
|
||||
*/
|
||||
export type IframeEventMap = {
|
||||
addActionsMenuKeyToRemotePlayer: AddActionsMenuKeyToRemotePlayerEvent;
|
||||
removeActionsMenuKeyFromRemotePlayer: RemoveActionsMenuKeyFromRemotePlayerEvent;
|
||||
loadPage: LoadPageEvent;
|
||||
chat: ChatEvent;
|
||||
cameraFollowPlayer: CameraFollowPlayerEvent;
|
||||
@@ -58,6 +64,7 @@ export type IframeEventMap = {
|
||||
displayBubble: null;
|
||||
removeBubble: null;
|
||||
onPlayerMove: undefined;
|
||||
onOpenActionMenu: undefined;
|
||||
onCameraUpdate: undefined;
|
||||
showLayer: LayerEvent;
|
||||
hideLayer: LayerEvent;
|
||||
@@ -90,6 +97,8 @@ export interface IframeResponseEventMap {
|
||||
enterZoneEvent: ChangeZoneEvent;
|
||||
leaveZoneEvent: ChangeZoneEvent;
|
||||
buttonClickedEvent: ButtonClickedEvent;
|
||||
remotePlayerClickedEvent: RemotePlayerClickedEvent;
|
||||
actionsMenuActionClickedEvent: ActionsMenuActionClickedEvent;
|
||||
hasPlayerMoved: HasPlayerMovedEvent;
|
||||
wasCameraUpdated: WasCameraUpdatedEvent;
|
||||
menuItemClicked: MenuItemClickedEvent;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
// TODO: Change for player Clicked, add all neccessary data
|
||||
export const isRemotePlayerClickedEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
id: tg.isNumber,
|
||||
})
|
||||
.get();
|
||||
|
||||
/**
|
||||
* A message sent from the game to the iFrame when RemotePlayer is clicked.
|
||||
*/
|
||||
export type RemotePlayerClickedEvent = tg.GuardedType<typeof isRemotePlayerClickedEvent>;
|
||||
|
||||
export type RemotePlayerClickedEventCallback = (event: RemotePlayerClickedEvent) => void;
|
||||
@@ -0,0 +1,16 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
export const isRemoveActionsMenuKeyFromRemotePlayerEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
id: tg.isNumber,
|
||||
actionKey: tg.isString,
|
||||
})
|
||||
.get();
|
||||
|
||||
export type RemoveActionsMenuKeyFromRemotePlayerEvent = tg.GuardedType<
|
||||
typeof isRemoveActionsMenuKeyFromRemotePlayerEvent
|
||||
>;
|
||||
|
||||
export type RemoveActionsMenuKeyFromRemotePlayerEventCallback = (
|
||||
event: RemoveActionsMenuKeyFromRemotePlayerEvent
|
||||
) => void;
|
||||
@@ -34,6 +34,16 @@ import type { WasCameraUpdatedEvent } from "./Events/WasCameraUpdatedEvent";
|
||||
import type { ChangeZoneEvent } from "./Events/ChangeZoneEvent";
|
||||
import { CameraSetEvent, isCameraSetEvent } from "./Events/CameraSetEvent";
|
||||
import { CameraFollowPlayerEvent, isCameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent";
|
||||
import type { RemotePlayerClickedEvent } from "./Events/RemotePlayerClickedEvent";
|
||||
import {
|
||||
AddActionsMenuKeyToRemotePlayerEvent,
|
||||
isAddActionsMenuKeyToRemotePlayerEvent,
|
||||
} from "./Events/AddActionsMenuKeyToRemotePlayerEvent";
|
||||
import type { ActionsMenuActionClickedEvent } from "./Events/ActionsMenuActionClickedEvent";
|
||||
import {
|
||||
isRemoveActionsMenuKeyFromRemotePlayerEvent,
|
||||
RemoveActionsMenuKeyFromRemotePlayerEvent,
|
||||
} from "./Events/RemoveActionsMenuKeyFromRemotePlayerEvent";
|
||||
|
||||
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
||||
query: IframeQueryMap[T]["query"],
|
||||
@@ -63,6 +73,15 @@ class IframeListener {
|
||||
private readonly _cameraFollowPlayerStream: Subject<CameraFollowPlayerEvent> = new Subject();
|
||||
public readonly cameraFollowPlayerStream = this._cameraFollowPlayerStream.asObservable();
|
||||
|
||||
private readonly _addActionsMenuKeyToRemotePlayerStream: Subject<AddActionsMenuKeyToRemotePlayerEvent> =
|
||||
new Subject();
|
||||
public readonly addActionsMenuKeyToRemotePlayerStream = this._addActionsMenuKeyToRemotePlayerStream.asObservable();
|
||||
|
||||
private readonly _removeActionsMenuKeyFromRemotePlayerEvent: Subject<RemoveActionsMenuKeyFromRemotePlayerEvent> =
|
||||
new Subject();
|
||||
public readonly removeActionsMenuKeyFromRemotePlayerEvent =
|
||||
this._removeActionsMenuKeyFromRemotePlayerEvent.asObservable();
|
||||
|
||||
private readonly _enablePlayerControlStream: Subject<void> = new Subject();
|
||||
public readonly enablePlayerControlStream = this._enablePlayerControlStream.asObservable();
|
||||
|
||||
@@ -241,6 +260,16 @@ class IframeListener {
|
||||
this._removeBubbleStream.next();
|
||||
} else if (payload.type == "onPlayerMove") {
|
||||
this.sendPlayerMove = true;
|
||||
} else if (
|
||||
payload.type == "addActionsMenuKeyToRemotePlayer" &&
|
||||
isAddActionsMenuKeyToRemotePlayerEvent(payload.data)
|
||||
) {
|
||||
this._addActionsMenuKeyToRemotePlayerStream.next(payload.data);
|
||||
} else if (
|
||||
payload.type == "removeActionsMenuKeyFromRemotePlayer" &&
|
||||
isRemoveActionsMenuKeyFromRemotePlayerEvent(payload.data)
|
||||
) {
|
||||
this._removeActionsMenuKeyFromRemotePlayerEvent.next(payload.data);
|
||||
} else if (payload.type == "onCameraUpdate") {
|
||||
this._trackCameraUpdateStream.next();
|
||||
} else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) {
|
||||
@@ -439,6 +468,20 @@ class IframeListener {
|
||||
}
|
||||
}
|
||||
|
||||
sendRemotePlayerClickedEvent(event: RemotePlayerClickedEvent) {
|
||||
this.postMessage({
|
||||
type: "remotePlayerClickedEvent",
|
||||
data: event,
|
||||
});
|
||||
}
|
||||
|
||||
sendActionsMenuActionClickedEvent(event: ActionsMenuActionClickedEvent) {
|
||||
this.postMessage({
|
||||
type: "actionsMenuActionClickedEvent",
|
||||
data: event,
|
||||
});
|
||||
}
|
||||
|
||||
sendCameraUpdated(event: WasCameraUpdatedEvent) {
|
||||
this.postMessage({
|
||||
type: "wasCameraUpdated",
|
||||
|
||||
+113
-5
@@ -8,6 +8,12 @@ import { ActionMessage } from "./Ui/ActionMessage";
|
||||
import { isMessageReferenceEvent } from "../Events/ui/TriggerActionMessageEvent";
|
||||
import { Menu } from "./Ui/Menu";
|
||||
import type { RequireOnlyOne } from "../types";
|
||||
import { isRemotePlayerClickedEvent, RemotePlayerClickedEvent } from "../Events/RemotePlayerClickedEvent";
|
||||
import {
|
||||
ActionsMenuActionClickedEvent,
|
||||
isActionsMenuActionClickedEvent,
|
||||
} from "../Events/ActionsMenuActionClickedEvent";
|
||||
import { Observable, Subject } from "rxjs";
|
||||
|
||||
let popupId = 0;
|
||||
const popups: Map<number, Popup> = new Map<number, Popup>();
|
||||
@@ -42,7 +48,77 @@ export interface ActionMessageOptions {
|
||||
callback: () => void;
|
||||
}
|
||||
|
||||
export interface RemotePlayerInterface {
|
||||
addAction(key: string, callback: Function): void;
|
||||
}
|
||||
|
||||
export class RemotePlayer implements RemotePlayerInterface {
|
||||
private id: number;
|
||||
|
||||
private actions: Map<string, ActionsMenuAction> = new Map<string, ActionsMenuAction>();
|
||||
|
||||
constructor(id: number) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public addAction(key: string, callback: Function): ActionsMenuAction {
|
||||
const newAction = new ActionsMenuAction(this, key, callback);
|
||||
this.actions.set(key, newAction);
|
||||
sendToWorkadventure({
|
||||
type: "addActionsMenuKeyToRemotePlayer",
|
||||
data: { id: this.id, actionKey: key },
|
||||
});
|
||||
return newAction;
|
||||
}
|
||||
|
||||
public callAction(key: string): void {
|
||||
const action = this.actions.get(key);
|
||||
if (action) {
|
||||
action.call();
|
||||
}
|
||||
}
|
||||
|
||||
public removeAction(key: string): void {
|
||||
this.actions.delete(key);
|
||||
sendToWorkadventure({
|
||||
type: "removeActionsMenuKeyFromRemotePlayer",
|
||||
data: { id: this.id, actionKey: key },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ActionsMenuAction {
|
||||
private remotePlayer: RemotePlayer;
|
||||
private key: string;
|
||||
private callback: Function;
|
||||
|
||||
constructor(remotePlayer: RemotePlayer, key: string, callback: Function) {
|
||||
this.remotePlayer = remotePlayer;
|
||||
this.key = key;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public call(): void {
|
||||
this.callback();
|
||||
}
|
||||
|
||||
public remove(): void {
|
||||
this.remotePlayer.removeAction(this.key);
|
||||
}
|
||||
}
|
||||
|
||||
export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventureUiCommands> {
|
||||
public readonly _onRemotePlayerClicked: Subject<RemotePlayerInterface>;
|
||||
public readonly onRemotePlayerClicked: Observable<RemotePlayerInterface>;
|
||||
|
||||
private currentlyClickedRemotePlayer?: RemotePlayer;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._onRemotePlayerClicked = new Subject<RemotePlayerInterface>();
|
||||
this.onRemotePlayerClicked = this._onRemotePlayerClicked.asObservable();
|
||||
}
|
||||
|
||||
callbacks = [
|
||||
apiCallback({
|
||||
type: "buttonClickedEvent",
|
||||
@@ -82,9 +158,38 @@ export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventure
|
||||
}
|
||||
},
|
||||
}),
|
||||
apiCallback({
|
||||
type: "remotePlayerClickedEvent",
|
||||
typeChecker: isRemotePlayerClickedEvent,
|
||||
callback: (payloadData: RemotePlayerClickedEvent) => {
|
||||
this.currentlyClickedRemotePlayer = new RemotePlayer(payloadData.id);
|
||||
this._onRemotePlayerClicked.next(this.currentlyClickedRemotePlayer);
|
||||
},
|
||||
}),
|
||||
apiCallback({
|
||||
type: "actionsMenuActionClickedEvent",
|
||||
typeChecker: isActionsMenuActionClickedEvent,
|
||||
callback: (payloadData: ActionsMenuActionClickedEvent) => {
|
||||
this.currentlyClickedRemotePlayer?.callAction(payloadData.actionName);
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup {
|
||||
public addActionsMenuKeyToRemotePlayer(id: number, actionKey: string): void {
|
||||
sendToWorkadventure({
|
||||
type: "addActionsMenuKeyToRemotePlayer",
|
||||
data: { id, actionKey },
|
||||
});
|
||||
}
|
||||
|
||||
public removeActionsMenuKeyFromRemotePlayer(id: number, actionKey: string): void {
|
||||
sendToWorkadventure({
|
||||
type: "removeActionsMenuKeyFromRemotePlayer",
|
||||
data: { id, actionKey },
|
||||
});
|
||||
}
|
||||
|
||||
public openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup {
|
||||
popupId++;
|
||||
const popup = new Popup(popupId);
|
||||
const btnMap = new Map<number, () => void>();
|
||||
@@ -119,7 +224,10 @@ export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventure
|
||||
return popup;
|
||||
}
|
||||
|
||||
registerMenuCommand(commandDescriptor: string, options: MenuOptions | ((commandDescriptor: string) => void)): Menu {
|
||||
public registerMenuCommand(
|
||||
commandDescriptor: string,
|
||||
options: MenuOptions | ((commandDescriptor: string) => void)
|
||||
): Menu {
|
||||
const menu = new Menu(commandDescriptor);
|
||||
|
||||
if (typeof options === "function") {
|
||||
@@ -168,15 +276,15 @@ export class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventure
|
||||
return menu;
|
||||
}
|
||||
|
||||
displayBubble(): void {
|
||||
public displayBubble(): void {
|
||||
sendToWorkadventure({ type: "displayBubble", data: null });
|
||||
}
|
||||
|
||||
removeBubble(): void {
|
||||
public removeBubble(): void {
|
||||
sendToWorkadventure({ type: "removeBubble", data: null });
|
||||
}
|
||||
|
||||
displayActionMessage(actionMessageOptions: ActionMessageOptions): ActionMessage {
|
||||
public displayActionMessage(actionMessageOptions: ActionMessageOptions): ActionMessage {
|
||||
const actionMessage = new ActionMessage(actionMessageOptions, () => {
|
||||
actionMessages.delete(actionMessage.uuid);
|
||||
});
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
import { actionsMenuStore } from "../../Stores/ActionsMenuStore";
|
||||
import { onDestroy } from "svelte";
|
||||
|
||||
import type { ActionsMenuAction } from "../../Stores/ActionsMenuStore";
|
||||
import type { Unsubscriber } from "svelte/store";
|
||||
import type { ActionsMenuData } from "../../Stores/ActionsMenuStore";
|
||||
|
||||
let actionsMenuData: ActionsMenuData | undefined;
|
||||
let sortedActions: ActionsMenuAction[] | undefined;
|
||||
|
||||
let actionsMenuStoreUnsubscriber: Unsubscriber | null;
|
||||
|
||||
@@ -21,6 +23,20 @@
|
||||
|
||||
actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value) => {
|
||||
actionsMenuData = value;
|
||||
if (actionsMenuData) {
|
||||
sortedActions = [...actionsMenuData.actions.values()].sort((a, b) => {
|
||||
const ap = a.priority ?? 0;
|
||||
const bp = b.priority ?? 0;
|
||||
if (ap > bp) {
|
||||
return -1;
|
||||
}
|
||||
if (ap < bp) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
@@ -37,15 +53,15 @@
|
||||
<button type="button" class="nes-btn is-error close" on:click={closeActionsMenu}>×</button>
|
||||
<h2>{actionsMenuData.playerName}</h2>
|
||||
<div class="actions">
|
||||
{#each [...actionsMenuData.actions] as { actionName, callback }}
|
||||
{#each sortedActions ?? [] as action}
|
||||
<button
|
||||
type="button"
|
||||
class="nes-btn"
|
||||
class="nes-btn {action.style ?? ''}"
|
||||
on:click|preventDefault={() => {
|
||||
callback();
|
||||
action.callback();
|
||||
}}
|
||||
>
|
||||
{actionName}
|
||||
{action.actionName}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
@@ -68,7 +84,7 @@
|
||||
color: whitesmoke;
|
||||
|
||||
.actions {
|
||||
max-height: calc(100% - 50px);
|
||||
max-height: 30vh;
|
||||
width: 100%;
|
||||
display: block;
|
||||
overflow-x: hidden;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { requestVisitCardsStore } from "../../Stores/GameStore";
|
||||
import { ActionsMenuData, actionsMenuStore } from "../../Stores/ActionsMenuStore";
|
||||
import { ActionsMenuAction, ActionsMenuData, actionsMenuStore } from "../../Stores/ActionsMenuStore";
|
||||
import { Character } from "../Entity/Character";
|
||||
import type { GameScene } from "../Game/GameScene";
|
||||
import type { PointInterface } from "../../Connexion/ConnexionModels";
|
||||
@@ -8,21 +8,28 @@ import type { Unsubscriber } from "svelte/store";
|
||||
import type { ActivatableInterface } from "../Game/ActivatableInterface";
|
||||
import type CancelablePromise from "cancelable-promise";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import { blackListManager } from "../../WebRtc/BlackListManager";
|
||||
import { showReportScreenStore } from "../../Stores/ShowReportScreenStore";
|
||||
|
||||
export enum RemotePlayerEvent {
|
||||
Clicked = "Clicked",
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing the sprite of a remote player (a player that plays on another computer)
|
||||
*/
|
||||
export class RemotePlayer extends Character implements ActivatableInterface {
|
||||
public userId: number;
|
||||
public readonly userId: number;
|
||||
public readonly userUuid: string;
|
||||
public readonly activationRadius: number;
|
||||
|
||||
private registeredActions: { actionName: string; callback: Function }[];
|
||||
private visitCardUrl: string | null;
|
||||
private isActionsMenuInitialized: boolean = false;
|
||||
private actionsMenuStoreUnsubscriber: Unsubscriber;
|
||||
|
||||
constructor(
|
||||
userId: number,
|
||||
userUuid: string,
|
||||
Scene: GameScene,
|
||||
x: number,
|
||||
y: number,
|
||||
@@ -39,10 +46,9 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
||||
|
||||
//set data
|
||||
this.userId = userId;
|
||||
this.userUuid = userUuid;
|
||||
this.visitCardUrl = visitCardUrl;
|
||||
this.registeredActions = [];
|
||||
this.registerDefaultActionsMenuActions();
|
||||
this.setClickable(this.registeredActions.length > 0);
|
||||
this.setClickable(this.getDefaultActionsMenuActions().length > 0);
|
||||
this.activationRadius = activationRadius ?? 96;
|
||||
this.actionsMenuStoreUnsubscriber = actionsMenuStore.subscribe((value: ActionsMenuData | undefined) => {
|
||||
this.isActionsMenuInitialized = value ? true : false;
|
||||
@@ -63,17 +69,19 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
||||
}
|
||||
}
|
||||
|
||||
public registerActionsMenuAction(action: { actionName: string; callback: Function }): void {
|
||||
this.registeredActions.push(action);
|
||||
this.updateIsClickable();
|
||||
public registerActionsMenuAction(action: ActionsMenuAction): void {
|
||||
actionsMenuStore.addAction({
|
||||
...action,
|
||||
priority: action.priority ?? 0,
|
||||
callback: () => {
|
||||
action.callback();
|
||||
actionsMenuStore.clear();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public unregisterActionsMenuAction(actionName: string) {
|
||||
const index = this.registeredActions.findIndex((action) => action.actionName === actionName);
|
||||
if (index !== -1) {
|
||||
this.registeredActions.splice(index, 1);
|
||||
}
|
||||
this.updateIsClickable();
|
||||
actionsMenuStore.removeAction(actionName);
|
||||
}
|
||||
|
||||
public activate(): void {
|
||||
@@ -90,37 +98,52 @@ export class RemotePlayer extends Character implements ActivatableInterface {
|
||||
return this.isClickable();
|
||||
}
|
||||
|
||||
private updateIsClickable(): void {
|
||||
this.setClickable(this.registeredActions.length > 0);
|
||||
}
|
||||
|
||||
private toggleActionsMenu(): void {
|
||||
if (this.isActionsMenuInitialized) {
|
||||
actionsMenuStore.clear();
|
||||
return;
|
||||
}
|
||||
actionsMenuStore.initialize(this.playerName);
|
||||
for (const action of this.registeredActions) {
|
||||
actionsMenuStore.addAction(action.actionName, action.callback);
|
||||
for (const action of this.getDefaultActionsMenuActions()) {
|
||||
actionsMenuStore.addAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
private registerDefaultActionsMenuActions(): void {
|
||||
private getDefaultActionsMenuActions(): ActionsMenuAction[] {
|
||||
const actions: ActionsMenuAction[] = [];
|
||||
if (this.visitCardUrl) {
|
||||
this.registeredActions.push({
|
||||
actions.push({
|
||||
actionName: LL.woka.menu.businessCard(),
|
||||
protected: true,
|
||||
priority: 1,
|
||||
callback: () => {
|
||||
requestVisitCardsStore.set(this.visitCardUrl);
|
||||
actionsMenuStore.clear();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
actions.push({
|
||||
actionName: blackListManager.isBlackListed(this.userUuid)
|
||||
? LL.report.block.unblock()
|
||||
: LL.report.block.block(),
|
||||
protected: true,
|
||||
priority: -1,
|
||||
style: "is-error",
|
||||
callback: () => {
|
||||
showReportScreenStore.set({ userId: this.userId, userName: this.name });
|
||||
actionsMenuStore.clear();
|
||||
},
|
||||
});
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
private bindEventHandlers(): void {
|
||||
this.on(Phaser.Input.Events.POINTER_DOWN, (event: Phaser.Input.Pointer) => {
|
||||
if (event.downElement.nodeName === "CANVAS" && event.leftButtonDown()) {
|
||||
this.toggleActionsMenu();
|
||||
this.emit(RemotePlayerEvent.Clicked);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import { localUserStore } from "../../Connexion/LocalUserStore";
|
||||
import { HtmlUtils } from "../../WebRtc/HtmlUtils";
|
||||
import { SimplePeer } from "../../WebRtc/SimplePeer";
|
||||
import { Loader } from "../Components/Loader";
|
||||
import { RemotePlayer } from "../Entity/RemotePlayer";
|
||||
import { RemotePlayer, RemotePlayerEvent } from "../Entity/RemotePlayer";
|
||||
import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene";
|
||||
import { PlayerAnimationDirections } from "../Player/Animation";
|
||||
import { hasMovedEventName, Player, requestEmoteEventName } from "../Player/Player";
|
||||
@@ -1108,6 +1108,23 @@ ${escapedMessage}
|
||||
})
|
||||
);
|
||||
|
||||
this.iframeSubscriptionList.push(
|
||||
iframeListener.addActionsMenuKeyToRemotePlayerStream.subscribe((data) => {
|
||||
this.MapPlayersByKey.get(data.id)?.registerActionsMenuAction({
|
||||
actionName: data.actionKey,
|
||||
callback: () => {
|
||||
iframeListener.sendActionsMenuActionClickedEvent({ actionName: data.actionKey, id: data.id });
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
this.iframeSubscriptionList.push(
|
||||
iframeListener.removeActionsMenuKeyFromRemotePlayerEvent.subscribe((data) => {
|
||||
this.MapPlayersByKey.get(data.id)?.unregisterActionsMenuAction(data.actionKey);
|
||||
})
|
||||
);
|
||||
|
||||
this.iframeSubscriptionList.push(
|
||||
iframeListener.trackCameraUpdateStream.subscribe(() => {
|
||||
if (!this.firstCameraUpdateSent) {
|
||||
@@ -1893,6 +1910,7 @@ ${escapedMessage}
|
||||
const texturesPromise = lazyLoadPlayerCharacterTextures(this.load, addPlayerData.characterLayers);
|
||||
const player = new RemotePlayer(
|
||||
addPlayerData.userId,
|
||||
addPlayerData.userUuid,
|
||||
this,
|
||||
addPlayerData.position.x,
|
||||
addPlayerData.position.y,
|
||||
@@ -1920,6 +1938,10 @@ ${escapedMessage}
|
||||
this.activatablesManager.handlePointerOutActivatableObject();
|
||||
this.markDirty();
|
||||
});
|
||||
|
||||
player.on(RemotePlayerEvent.Clicked, () => {
|
||||
iframeListener.sendRemotePlayerClickedEvent({ id: player.userId });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
export type ActionsMenuAction = {
|
||||
actionName: string;
|
||||
callback: Function;
|
||||
protected?: boolean;
|
||||
priority?: number;
|
||||
style?: "is-success" | "is-error" | "is-primary";
|
||||
};
|
||||
export interface ActionsMenuData {
|
||||
playerName: string;
|
||||
actions: { actionName: string; callback: Function }[];
|
||||
actions: Map<string, ActionsMenuAction>;
|
||||
}
|
||||
|
||||
function createActionsMenuStore() {
|
||||
@@ -13,21 +20,18 @@ function createActionsMenuStore() {
|
||||
initialize: (playerName: string) => {
|
||||
set({
|
||||
playerName,
|
||||
actions: [],
|
||||
actions: new Map<string, ActionsMenuAction>(),
|
||||
});
|
||||
},
|
||||
addAction: (actionName: string, callback: Function) => {
|
||||
addAction: (action: ActionsMenuAction) => {
|
||||
update((data) => {
|
||||
data?.actions.push({ actionName, callback });
|
||||
data?.actions.set(action.actionName, action);
|
||||
return data;
|
||||
});
|
||||
},
|
||||
removeAction: (actionName: string) => {
|
||||
update((data) => {
|
||||
const actionIndex = data?.actions.findIndex((action) => action.actionName === actionName);
|
||||
if (actionIndex !== undefined && actionIndex != -1) {
|
||||
data?.actions.splice(actionIndex, 1);
|
||||
}
|
||||
data?.actions.delete(actionName);
|
||||
return data;
|
||||
});
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user