Implement follow request / confirmation UI
This commit is contained in:
parent
d6ef60a3d8
commit
0a410d289d
@ -14,6 +14,7 @@ import {
|
|||||||
SubToPusherRoomMessage,
|
SubToPusherRoomMessage,
|
||||||
VariableMessage,
|
VariableMessage,
|
||||||
VariableWithTagMessage,
|
VariableWithTagMessage,
|
||||||
|
ServerToClientMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils";
|
||||||
import { RoomSocket, ZoneSocket } from "src/RoomManager";
|
import { RoomSocket, ZoneSocket } from "src/RoomManager";
|
||||||
@ -95,10 +96,20 @@ export class GameRoom {
|
|||||||
return Array.from(this.groups.values());
|
return Array.from(this.groups.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getGroupIncludingUser(user: User): Group | undefined {
|
||||||
|
const foundGroups = this.getGroups().filter((grp) => grp.includes(user));
|
||||||
|
return foundGroups[0];
|
||||||
|
}
|
||||||
|
|
||||||
public getUsers(): Map<number, User> {
|
public getUsers(): Map<number, User> {
|
||||||
return this.users;
|
return this.users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getUserByName(name: string): User | undefined {
|
||||||
|
let foundUsers = Array.from(this.users.values());
|
||||||
|
foundUsers = foundUsers.filter((user: User) => user.name === name);
|
||||||
|
return foundUsers[0];
|
||||||
|
}
|
||||||
public getUserByUuid(uuid: string): User | undefined {
|
public getUserByUuid(uuid: string): User | undefined {
|
||||||
return this.usersByUuid.get(uuid);
|
return this.usersByUuid.get(uuid);
|
||||||
}
|
}
|
||||||
@ -226,6 +237,20 @@ export class GameRoom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sendToOthersInGroupIncludingUser(user: User, message: ServerToClientMessage): void {
|
||||||
|
this.getGroupIncludingUser(user)
|
||||||
|
?.getUsers()
|
||||||
|
.forEach((currentUser: User) => {
|
||||||
|
if (currentUser.name !== user.name) {
|
||||||
|
currentUser.socket.write(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public sendToUserWithName(name: string, message: ServerToClientMessage): void {
|
||||||
|
this.getUserByName(name)?.socket.write(message);
|
||||||
|
}
|
||||||
|
|
||||||
setSilent(user: User, silent: boolean) {
|
setSilent(user: User, silent: boolean) {
|
||||||
if (user.silent === silent) {
|
if (user.silent === silent) {
|
||||||
return;
|
return;
|
||||||
|
@ -8,7 +8,9 @@ import {
|
|||||||
BatchToPusherMessage,
|
BatchToPusherMessage,
|
||||||
BatchToPusherRoomMessage,
|
BatchToPusherRoomMessage,
|
||||||
EmotePromptMessage,
|
EmotePromptMessage,
|
||||||
FollowMeRequestMessage,
|
FollowRequestMessage,
|
||||||
|
FollowConfirmationMessage,
|
||||||
|
FollowAbortMessage,
|
||||||
EmptyMessage,
|
EmptyMessage,
|
||||||
ItemEventMessage,
|
ItemEventMessage,
|
||||||
JoinRoomMessage,
|
JoinRoomMessage,
|
||||||
@ -117,11 +119,23 @@ const roomManager: IRoomManagerServer = {
|
|||||||
user,
|
user,
|
||||||
message.getEmotepromptmessage() as EmotePromptMessage
|
message.getEmotepromptmessage() as EmotePromptMessage
|
||||||
);
|
);
|
||||||
} else if (message.hasFollowmerequestmessage()) {
|
} else if (message.hasFollowrequestmessage()) {
|
||||||
socketManager.handleFollowMeRequestMessage(
|
socketManager.handleFollowRequestMessage(
|
||||||
room,
|
room,
|
||||||
user,
|
user,
|
||||||
message.getFollowmerequestmessage() as FollowMeRequestMessage
|
message.getFollowrequestmessage() as FollowRequestMessage
|
||||||
|
);
|
||||||
|
} else if (message.hasFollowconfirmationmessage()) {
|
||||||
|
socketManager.handleFollowConfirmationMessage(
|
||||||
|
room,
|
||||||
|
user,
|
||||||
|
message.getFollowconfirmationmessage() as FollowConfirmationMessage
|
||||||
|
);
|
||||||
|
} else if (message.hasFollowabortmessage()) {
|
||||||
|
socketManager.handleFollowAbortMessage(
|
||||||
|
room,
|
||||||
|
user,
|
||||||
|
message.getFollowabortmessage() as FollowAbortMessage
|
||||||
);
|
);
|
||||||
} else if (message.hasSendusermessage()) {
|
} else if (message.hasSendusermessage()) {
|
||||||
const sendUserMessage = message.getSendusermessage();
|
const sendUserMessage = message.getSendusermessage();
|
||||||
|
@ -30,7 +30,9 @@ import {
|
|||||||
BanUserMessage,
|
BanUserMessage,
|
||||||
RefreshRoomMessage,
|
RefreshRoomMessage,
|
||||||
EmotePromptMessage,
|
EmotePromptMessage,
|
||||||
FollowMeRequestMessage,
|
FollowRequestMessage,
|
||||||
|
FollowConfirmationMessage,
|
||||||
|
FollowAbortMessage,
|
||||||
VariableMessage,
|
VariableMessage,
|
||||||
BatchToPusherRoomMessage,
|
BatchToPusherRoomMessage,
|
||||||
SubToPusherRoomMessage,
|
SubToPusherRoomMessage,
|
||||||
@ -835,24 +837,30 @@ export class SocketManager {
|
|||||||
room.emitEmoteEvent(user, emoteEventMessage);
|
room.emitEmoteEvent(user, emoteEventMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFollowMeRequestMessage(room: GameRoom, user: User, requestMessage: FollowMeRequestMessage) {
|
handleFollowRequestMessage(room: GameRoom, user: User, message: FollowRequestMessage) {
|
||||||
// Find group including the requesting user
|
|
||||||
let foundGroups = room.getGroups().filter((grp) => grp.includes(user));
|
|
||||||
if (!foundGroups[0]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let group = foundGroups[0];
|
|
||||||
|
|
||||||
// Send invitations to other group members
|
|
||||||
requestMessage.setPlayername(user.name);
|
|
||||||
const clientMessage = new ServerToClientMessage();
|
const clientMessage = new ServerToClientMessage();
|
||||||
clientMessage.setFollowmerequestmessage(requestMessage);
|
clientMessage.setFollowrequestmessage(message);
|
||||||
group.getUsers().forEach((currentUser: User) => {
|
room.sendToOthersInGroupIncludingUser(user, clientMessage);
|
||||||
if (user.name !== currentUser.name) {
|
}
|
||||||
console.log("Inviting " + currentUser.name + " to follow " + user.name);
|
|
||||||
currentUser.socket.write(clientMessage);
|
handleFollowConfirmationMessage(room: GameRoom, user: User, message: FollowConfirmationMessage) {
|
||||||
|
const clientMessage = new ServerToClientMessage();
|
||||||
|
clientMessage.setFollowconfirmationmessage(message);
|
||||||
|
room.sendToUserWithName(message.getLeader(), clientMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFollowAbortMessage(room: GameRoom, user: User, message: FollowAbortMessage) {
|
||||||
|
if (message.getRole() === "leader") {
|
||||||
|
const clientMessage = new ServerToClientMessage();
|
||||||
|
clientMessage.setFollowabortmessage(message);
|
||||||
|
room.sendToOthersInGroupIncludingUser(user, clientMessage);
|
||||||
|
} else {
|
||||||
|
const recipient = message.getPlayername();
|
||||||
|
message.setPlayername(user.name);
|
||||||
|
const clientMessage = new ServerToClientMessage();
|
||||||
|
clientMessage.setFollowabortmessage(message);
|
||||||
|
room.sendToUserWithName(recipient, clientMessage);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,8 @@
|
|||||||
import AudioManager from "./AudioManager/AudioManager.svelte";
|
import AudioManager from "./AudioManager/AudioManager.svelte";
|
||||||
import { showReportScreenStore, userReportEmpty } from "../Stores/ShowReportScreenStore";
|
import { showReportScreenStore, userReportEmpty } from "../Stores/ShowReportScreenStore";
|
||||||
import ReportMenu from "./ReportMenu/ReportMenu.svelte";
|
import ReportMenu from "./ReportMenu/ReportMenu.svelte";
|
||||||
|
import { followStateStore, followStates } from "../Stores/InteractStore";
|
||||||
|
import InteractMenu from "./InteractMenu/InteractMenu.svelte";
|
||||||
|
|
||||||
export let game: Game;
|
export let game: Game;
|
||||||
</script>
|
</script>
|
||||||
@ -102,6 +104,11 @@
|
|||||||
<ReportMenu />
|
<ReportMenu />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if $followStateStore !== followStates.off}
|
||||||
|
<div>
|
||||||
|
<InteractMenu />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if $menuIconVisiblilityStore}
|
{#if $menuIconVisiblilityStore}
|
||||||
<div>
|
<div>
|
||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
|
238
front/src/Components/InteractMenu/InteractMenu.svelte
Normal file
238
front/src/Components/InteractMenu/InteractMenu.svelte
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
<!--
|
||||||
|
vim: ft=typescript
|
||||||
|
-->
|
||||||
|
<script lang="ts">
|
||||||
|
import { onDestroy, onMount } from "svelte";
|
||||||
|
import type { Unsubscriber } from "svelte/store";
|
||||||
|
import { get } from "svelte/store";
|
||||||
|
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||||
|
|
||||||
|
import {
|
||||||
|
followStateStore,
|
||||||
|
followRoleStore,
|
||||||
|
followUsersStore,
|
||||||
|
followRoles,
|
||||||
|
followStates,
|
||||||
|
} from "../../Stores/InteractStore";
|
||||||
|
|
||||||
|
const gameScene = gameManager.getCurrentGameScene();
|
||||||
|
|
||||||
|
let followState: string;
|
||||||
|
let followRole: string;
|
||||||
|
let followUsers: string[];
|
||||||
|
let stateUnsubscriber: Unsubscriber;
|
||||||
|
let roleUnsubscriber: Unsubscriber;
|
||||||
|
let nameUnsubscriber: Unsubscriber;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
followState = get(followStateStore);
|
||||||
|
followRole = get(followRoleStore);
|
||||||
|
followUsers = get(followUsersStore);
|
||||||
|
stateUnsubscriber = followStateStore.subscribe((state) => {
|
||||||
|
followState = state;
|
||||||
|
});
|
||||||
|
roleUnsubscriber = followRoleStore.subscribe((role) => {
|
||||||
|
followRole = role;
|
||||||
|
});
|
||||||
|
nameUnsubscriber = followUsersStore.subscribe((users) => {
|
||||||
|
followUsers = users;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if (stateUnsubscriber) {
|
||||||
|
stateUnsubscriber();
|
||||||
|
}
|
||||||
|
if (roleUnsubscriber) {
|
||||||
|
roleUnsubscriber();
|
||||||
|
}
|
||||||
|
if (nameUnsubscriber) {
|
||||||
|
nameUnsubscriber();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function sendFollowRequest() {
|
||||||
|
gameScene.connection?.emitFollowRequest(gameManager.getPlayerName());
|
||||||
|
followStateStore.set(followStates.active);
|
||||||
|
}
|
||||||
|
|
||||||
|
function acceptFollowRequest() {
|
||||||
|
gameScene.CurrentPlayer.enableFollowing();
|
||||||
|
gameScene.connection?.emitFollowConfirmation(followUsers[0], gameManager.getPlayerName());
|
||||||
|
}
|
||||||
|
|
||||||
|
function abortEnding() {
|
||||||
|
followStateStore.set(followStates.active);
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
if (followRole === followRoles.leader && followUsers.length > 0) {
|
||||||
|
gameScene.connection?.emitFollowAbort(followRole, gameManager.getPlayerName());
|
||||||
|
} else {
|
||||||
|
gameScene.connection?.emitFollowAbort(followRole, followUsers[0]);
|
||||||
|
}
|
||||||
|
followStateStore.set(followStates.off);
|
||||||
|
followRoleStore.set(followRoles.leader);
|
||||||
|
followUsersStore.set([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(e: KeyboardEvent) {
|
||||||
|
if (e.key === "Escape") {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:window on:keydown={onKeyDown} />
|
||||||
|
|
||||||
|
{#if followState === followStates.requesting}
|
||||||
|
<div class="interact-menu nes-container is-rounded">
|
||||||
|
<section class="interact-menu-title">
|
||||||
|
<h2>Interaction</h2>
|
||||||
|
</section>
|
||||||
|
{#if followRole === followRoles.follower}
|
||||||
|
<section class="interact-menu-question">
|
||||||
|
<p>Do you want to follow {followUsers[0]}?</p>
|
||||||
|
</section>
|
||||||
|
<section class="interact-menu-action">
|
||||||
|
<button type="button" class="accept" on:click|preventDefault={acceptFollowRequest}>Yes</button>
|
||||||
|
<button type="button" class="deny" on:click|preventDefault={reset}>No</button>
|
||||||
|
</section>
|
||||||
|
{:else if followRole === followRoles.leader}
|
||||||
|
<section class="interact-menu-question">
|
||||||
|
<p>Ask others to follow you?</p>
|
||||||
|
</section>
|
||||||
|
<section class="interact-menu-action">
|
||||||
|
<button type="button" class="accept" on:click|preventDefault={sendFollowRequest}>Yes</button>
|
||||||
|
<button type="button" class="deny" on:click|preventDefault={reset}>No</button>
|
||||||
|
</section>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if followState === followStates.ending}
|
||||||
|
<div class="interact-menu nes-container is-rounded">
|
||||||
|
<section class="interact-menu-title">
|
||||||
|
<h2>Interaction</h2>
|
||||||
|
</section>
|
||||||
|
{#if followRole === followRoles.follower}
|
||||||
|
<section class="interact-menu-question">
|
||||||
|
<p>Do you want to stop following {followUsers[0]}?</p>
|
||||||
|
</section>
|
||||||
|
{:else if followRole === followRoles.leader}
|
||||||
|
<section class="interact-menu-question">
|
||||||
|
<p>Do you want to stop leading the way?</p>
|
||||||
|
</section>
|
||||||
|
{/if}
|
||||||
|
<section class="interact-menu-action">
|
||||||
|
<button type="button" class="accept" on:click|preventDefault={reset}>Yes</button>
|
||||||
|
<button type="button" class="deny" on:click|preventDefault={abortEnding}>No</button>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if followState === followStates.active || followState === followStates.ending}
|
||||||
|
<div class="interact-status nes-container is-rounded">
|
||||||
|
<section class="interact-status">
|
||||||
|
{#if followRole === followRoles.follower}
|
||||||
|
<p>Following {followUsers[0]}</p>
|
||||||
|
{:else if followUsers.length === 0}
|
||||||
|
<p>Waiting for followers' confirmation</p>
|
||||||
|
{:else if followUsers.length === 1}
|
||||||
|
<p>{followUsers[0]} is following you</p>
|
||||||
|
{:else if followUsers.length === 2}
|
||||||
|
<p>{followUsers[0]} and {followUsers[1]} are following you</p>
|
||||||
|
{:else}
|
||||||
|
<p>{followUsers[0]}, {followUsers[1]} and {followUsers[2]} are following you</p>
|
||||||
|
{/if}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.nes-container {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.interact-status {
|
||||||
|
background-color: #333333;
|
||||||
|
color: whitesmoke;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
height: 2.7em;
|
||||||
|
width: 40vw;
|
||||||
|
top: 87vh;
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.interact-menu {
|
||||||
|
pointer-events: auto;
|
||||||
|
background-color: #333333;
|
||||||
|
color: whitesmoke;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
height: 19vh;
|
||||||
|
width: 60vw;
|
||||||
|
top: 60vh;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
section.interact-menu-title {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.interact-menu-question {
|
||||||
|
margin: 4px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 1.05em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section.interact-menu-action {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 50% 50%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 4px;
|
||||||
|
padding: 0px;
|
||||||
|
border: medium solid black;
|
||||||
|
font-weight: bold;
|
||||||
|
height: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accept {
|
||||||
|
background-color: #00ff0088;
|
||||||
|
}
|
||||||
|
.accept:hover {
|
||||||
|
background-color: #00ff00cc;
|
||||||
|
}
|
||||||
|
.deny {
|
||||||
|
background-color: #ff000088;
|
||||||
|
}
|
||||||
|
.deny:hover {
|
||||||
|
background-color: #ff0000cc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 800px) {
|
||||||
|
div.interact-status {
|
||||||
|
width: 100vw;
|
||||||
|
top: 78vh;
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.interact-menu {
|
||||||
|
height: 21vh;
|
||||||
|
width: 100vw;
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -30,7 +30,9 @@ import {
|
|||||||
PingMessage,
|
PingMessage,
|
||||||
EmoteEventMessage,
|
EmoteEventMessage,
|
||||||
EmotePromptMessage,
|
EmotePromptMessage,
|
||||||
FollowMeRequestMessage,
|
FollowRequestMessage,
|
||||||
|
FollowConfirmationMessage,
|
||||||
|
FollowAbortMessage,
|
||||||
SendUserMessage,
|
SendUserMessage,
|
||||||
BanUserMessage,
|
BanUserMessage,
|
||||||
VariableMessage,
|
VariableMessage,
|
||||||
@ -58,7 +60,15 @@ import { adminMessagesService } from "./AdminMessagesService";
|
|||||||
import { worldFullMessageStream } from "./WorldFullMessageStream";
|
import { worldFullMessageStream } from "./WorldFullMessageStream";
|
||||||
import { connectionManager } from "./ConnectionManager";
|
import { connectionManager } from "./ConnectionManager";
|
||||||
import { emoteEventStream } from "./EmoteEventStream";
|
import { emoteEventStream } from "./EmoteEventStream";
|
||||||
|
import { get } from "svelte/store";
|
||||||
import { warningContainerStore } from "../Stores/MenuStore";
|
import { warningContainerStore } from "../Stores/MenuStore";
|
||||||
|
import {
|
||||||
|
followStateStore,
|
||||||
|
followRoleStore,
|
||||||
|
followUsersStore,
|
||||||
|
followRoles,
|
||||||
|
followStates,
|
||||||
|
} from "../Stores/InteractStore";
|
||||||
|
|
||||||
const manualPingDelay = 20000;
|
const manualPingDelay = 20000;
|
||||||
|
|
||||||
@ -258,9 +268,32 @@ export class RoomConnection implements RoomConnection {
|
|||||||
warningContainerStore.activateWarningContainer();
|
warningContainerStore.activateWarningContainer();
|
||||||
} else if (message.hasRefreshroommessage()) {
|
} else if (message.hasRefreshroommessage()) {
|
||||||
//todo: implement a way to notify the user the room was refreshed.
|
//todo: implement a way to notify the user the room was refreshed.
|
||||||
} else if (message.hasFollowmerequestmessage()) {
|
} else if (message.hasFollowrequestmessage()) {
|
||||||
const requestMessage = message.getFollowmerequestmessage() as FollowMeRequestMessage;
|
const requestMessage = message.getFollowrequestmessage() as FollowRequestMessage;
|
||||||
console.log("Follow me request from " + requestMessage.getPlayername());
|
console.log("Got follow request from " + requestMessage.getPlayername());
|
||||||
|
followStateStore.set(followStates.requesting);
|
||||||
|
followRoleStore.set(followRoles.follower);
|
||||||
|
followUsersStore.set([requestMessage.getPlayername()]);
|
||||||
|
} else if (message.hasFollowconfirmationmessage()) {
|
||||||
|
const responseMessage = message.getFollowconfirmationmessage() as FollowConfirmationMessage;
|
||||||
|
console.log("Got follow response from " + responseMessage.getFollower());
|
||||||
|
followUsersStore.set([...get(followUsersStore), responseMessage.getFollower()]);
|
||||||
|
} else if (message.hasFollowabortmessage()) {
|
||||||
|
const abortMessage = message.getFollowabortmessage() as FollowAbortMessage;
|
||||||
|
console.log("Got follow abort message from", abortMessage.getRole());
|
||||||
|
if (abortMessage.getRole() === followRoles.leader) {
|
||||||
|
followStateStore.set(followStates.off);
|
||||||
|
followRoleStore.set(followRoles.leader);
|
||||||
|
followUsersStore.set([]);
|
||||||
|
} else {
|
||||||
|
let followers = get(followUsersStore);
|
||||||
|
followers = followers.filter((name) => name !== abortMessage.getPlayername());
|
||||||
|
followUsersStore.set(followers);
|
||||||
|
if (followers.length === 0) {
|
||||||
|
followStateStore.set(followStates.off);
|
||||||
|
followRoleStore.set(followRoles.leader);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (message.hasErrormessage()) {
|
} else if (message.hasErrormessage()) {
|
||||||
const errorMessage = message.getErrormessage() as ErrorMessage;
|
const errorMessage = message.getErrormessage() as ErrorMessage;
|
||||||
console.error("An error occurred server side: " + errorMessage.getMessage());
|
console.error("An error occurred server side: " + errorMessage.getMessage());
|
||||||
@ -716,11 +749,41 @@ export class RoomConnection implements RoomConnection {
|
|||||||
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public emitFollowMeRequest(): void {
|
public emitFollowRequest(user: string | null): void {
|
||||||
console.log("Emitting follow me request");
|
if (!user) {
|
||||||
const message = new FollowMeRequestMessage();
|
return;
|
||||||
|
}
|
||||||
|
console.log("Emitting follow request");
|
||||||
|
const message = new FollowRequestMessage();
|
||||||
|
message.setPlayername(user);
|
||||||
const clientToServerMessage = new ClientToServerMessage();
|
const clientToServerMessage = new ClientToServerMessage();
|
||||||
clientToServerMessage.setFollowmerequestmessage(message);
|
clientToServerMessage.setFollowrequestmessage(message);
|
||||||
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public emitFollowConfirmation(leader: string, follower: string | null): void {
|
||||||
|
if (!follower) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("Emitting follow confirmation");
|
||||||
|
const message = new FollowConfirmationMessage();
|
||||||
|
message.setLeader(leader);
|
||||||
|
message.setFollower(follower);
|
||||||
|
const clientToServerMessage = new ClientToServerMessage();
|
||||||
|
clientToServerMessage.setFollowconfirmationmessage(message);
|
||||||
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public emitFollowAbort(role: string, user: string | null): void {
|
||||||
|
if (!user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("Emitting follow abort");
|
||||||
|
const message = new FollowAbortMessage();
|
||||||
|
message.setRole(role);
|
||||||
|
message.setPlayername(user);
|
||||||
|
const clientToServerMessage = new ClientToServerMessage();
|
||||||
|
clientToServerMessage.setFollowabortmessage(message);
|
||||||
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
this.socket.send(clientToServerMessage.serializeBinary().buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,16 @@ import type { GameScene } from "../Game/GameScene";
|
|||||||
import { ActiveEventList, UserInputEvent, UserInputManager } from "../UserInput/UserInputManager";
|
import { ActiveEventList, UserInputEvent, UserInputManager } from "../UserInput/UserInputManager";
|
||||||
import { Character } from "../Entity/Character";
|
import { Character } from "../Entity/Character";
|
||||||
import type { RemotePlayer } from "../Entity/RemotePlayer";
|
import type { RemotePlayer } from "../Entity/RemotePlayer";
|
||||||
|
|
||||||
|
import { get } from "svelte/store";
|
||||||
import { userMovingStore } from "../../Stores/GameStore";
|
import { userMovingStore } from "../../Stores/GameStore";
|
||||||
|
import {
|
||||||
|
followStateStore,
|
||||||
|
followRoleStore,
|
||||||
|
followUsersStore,
|
||||||
|
followRoles,
|
||||||
|
followStates,
|
||||||
|
} from "../../Stores/InteractStore";
|
||||||
|
|
||||||
export const hasMovedEventName = "hasMoved";
|
export const hasMovedEventName = "hasMoved";
|
||||||
export const requestEmoteEventName = "requestEmote";
|
export const requestEmoteEventName = "requestEmote";
|
||||||
@ -156,44 +165,34 @@ export class Player extends Character {
|
|||||||
userMovingStore.set(moving);
|
userMovingStore.set(moving);
|
||||||
}
|
}
|
||||||
|
|
||||||
moveUser(delta: number): void {
|
public enableFollowing() {
|
||||||
const activeEvents = this.userInputManager.getEventListForGameTick();
|
Array.from(this.scene.MapPlayersByKey.values()).forEach((player) => {
|
||||||
|
if (player.PlayerValue !== get(followUsersStore)[0]) {
|
||||||
if (activeEvents.get(UserInputEvent.Interact)) {
|
return;
|
||||||
const sortedPlayers = Array.from(this.scene.MapPlayersByKey.values()).sort((p1, p2) => {
|
|
||||||
const sdistToP1 = Math.pow(p1.x - this.x, 2) + Math.pow(p1.y - this.y, 2);
|
|
||||||
const sdistToP2 = Math.pow(p2.x - this.x, 2) + Math.pow(p2.y - this.y, 2);
|
|
||||||
if (sdistToP1 > sdistToP2) {
|
|
||||||
return 1;
|
|
||||||
} else if (sdistToP1 < sdistToP2) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
const minFollowDist = 10000;
|
|
||||||
if (typeof sortedPlayers !== "undefined" && sortedPlayers.length > 0) {
|
|
||||||
const sdist = Math.pow(sortedPlayers[0].x - this.x, 2) + Math.pow(sortedPlayers[0].y - this.y, 2);
|
|
||||||
if (sdist < minFollowDist) {
|
|
||||||
this.follow = {
|
this.follow = {
|
||||||
followPlayer: sortedPlayers[0],
|
followPlayer: player,
|
||||||
direction: this.previousDirection,
|
direction: this.previousDirection,
|
||||||
};
|
};
|
||||||
|
followStateStore.set(followStates.active);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public moveUser(delta: number): void {
|
||||||
|
const activeEvents = this.userInputManager.getEventListForGameTick();
|
||||||
|
const state = get(followStateStore);
|
||||||
|
const role = get(followRoleStore);
|
||||||
|
|
||||||
|
if (activeEvents.get(UserInputEvent.Interact)) {
|
||||||
|
if (state === followStates.off && this.scene.groups.size > 0) {
|
||||||
|
followStateStore.set(followStates.requesting);
|
||||||
|
followRoleStore.set(followRoles.leader);
|
||||||
|
} else if (state === followStates.active) {
|
||||||
|
followStateStore.set(followStates.ending);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if ((state !== followStates.active && state !== followStates.ending) || role !== followRoles.follower) {
|
||||||
activeEvents.get(UserInputEvent.MoveUp) ||
|
|
||||||
activeEvents.get(UserInputEvent.MoveDown) ||
|
|
||||||
activeEvents.get(UserInputEvent.MoveLeft) ||
|
|
||||||
activeEvents.get(UserInputEvent.MoveRight)
|
|
||||||
) {
|
|
||||||
this.follow = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.follow === null) {
|
|
||||||
this.inputStep(activeEvents, delta);
|
this.inputStep(activeEvents, delta);
|
||||||
} else {
|
} else {
|
||||||
this.followStep(activeEvents, delta);
|
this.followStep(activeEvents, delta);
|
||||||
|
17
front/src/Stores/InteractStore.ts
Normal file
17
front/src/Stores/InteractStore.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export const followStates = {
|
||||||
|
off: "off",
|
||||||
|
requesting: "requesting",
|
||||||
|
active: "active",
|
||||||
|
ending: "ending",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const followRoles = {
|
||||||
|
leader: "leader",
|
||||||
|
follower: "follower",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const followStateStore = writable(followStates.off);
|
||||||
|
export const followRoleStore = writable(followRoles.leader);
|
||||||
|
export const followUsersStore = writable<string[]>([]);
|
@ -80,13 +80,18 @@ message QueryJitsiJwtMessage {
|
|||||||
string tag = 2; // FIXME: rather than reading the tag from the query, we should read it from the current map!
|
string tag = 2; // FIXME: rather than reading the tag from the query, we should read it from the current map!
|
||||||
}
|
}
|
||||||
|
|
||||||
message FollowMeRequestMessage {
|
message FollowRequestMessage {
|
||||||
string playerName = 1;
|
string playerName = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message FollowMeResponseMessage {
|
message FollowConfirmationMessage {
|
||||||
string playerName = 1;
|
string leader = 1;
|
||||||
bool accepted = 2;
|
string follower = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FollowAbortMessage {
|
||||||
|
string role = 1;
|
||||||
|
string playerName = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ClientToServerMessage {
|
message ClientToServerMessage {
|
||||||
@ -104,8 +109,9 @@ message ClientToServerMessage {
|
|||||||
QueryJitsiJwtMessage queryJitsiJwtMessage = 12;
|
QueryJitsiJwtMessage queryJitsiJwtMessage = 12;
|
||||||
EmotePromptMessage emotePromptMessage = 13;
|
EmotePromptMessage emotePromptMessage = 13;
|
||||||
VariableMessage variableMessage = 14;
|
VariableMessage variableMessage = 14;
|
||||||
FollowMeRequestMessage followMeRequestMessage = 15;
|
FollowRequestMessage followRequestMessage = 15;
|
||||||
FollowMeResponseMessage followMeResponseMessage = 16;
|
FollowConfirmationMessage followConfirmationMessage = 16;
|
||||||
|
FollowAbortMessage followAbortMessage = 17;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,8 +302,9 @@ message ServerToClientMessage {
|
|||||||
WorldConnexionMessage worldConnexionMessage = 18;
|
WorldConnexionMessage worldConnexionMessage = 18;
|
||||||
//EmoteEventMessage emoteEventMessage = 19;
|
//EmoteEventMessage emoteEventMessage = 19;
|
||||||
TokenExpiredMessage tokenExpiredMessage = 20;
|
TokenExpiredMessage tokenExpiredMessage = 20;
|
||||||
FollowMeRequestMessage followMeRequestMessage = 21;
|
FollowRequestMessage followRequestMessage = 21;
|
||||||
FollowMeResponseMessage followMeResponseMessage = 22;
|
FollowConfirmationMessage followConfirmationMessage = 22;
|
||||||
|
FollowAbortMessage followAbortMessage = 23;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,8 +385,9 @@ message PusherToBackMessage {
|
|||||||
BanUserMessage banUserMessage = 13;
|
BanUserMessage banUserMessage = 13;
|
||||||
EmotePromptMessage emotePromptMessage = 14;
|
EmotePromptMessage emotePromptMessage = 14;
|
||||||
VariableMessage variableMessage = 15;
|
VariableMessage variableMessage = 15;
|
||||||
FollowMeRequestMessage followMeRequestMessage = 16;
|
FollowRequestMessage followRequestMessage = 16;
|
||||||
FollowMeResponseMessage followMeResponseMessage = 17;
|
FollowConfirmationMessage followConfirmationMessage = 17;
|
||||||
|
FollowAbortMessage followAbortMessage = 18;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,9 @@ import {
|
|||||||
ServerToClientMessage,
|
ServerToClientMessage,
|
||||||
CompanionMessage,
|
CompanionMessage,
|
||||||
EmotePromptMessage,
|
EmotePromptMessage,
|
||||||
FollowMeRequestMessage,
|
FollowRequestMessage,
|
||||||
|
FollowConfirmationMessage,
|
||||||
|
FollowAbortMessage,
|
||||||
VariableMessage,
|
VariableMessage,
|
||||||
} from "../Messages/generated/messages_pb";
|
} from "../Messages/generated/messages_pb";
|
||||||
import { UserMovesMessage } from "../Messages/generated/messages_pb";
|
import { UserMovesMessage } from "../Messages/generated/messages_pb";
|
||||||
@ -470,11 +472,18 @@ export class IoSocketController {
|
|||||||
client,
|
client,
|
||||||
message.getEmotepromptmessage() as EmotePromptMessage
|
message.getEmotepromptmessage() as EmotePromptMessage
|
||||||
);
|
);
|
||||||
} else if (message.hasFollowmerequestmessage()) {
|
} else if (message.hasFollowrequestmessage()) {
|
||||||
socketManager.handleFollowMeRequest(
|
socketManager.handleFollowRequest(
|
||||||
client,
|
client,
|
||||||
message.getFollowmerequestmessage() as FollowMeRequestMessage
|
message.getFollowrequestmessage() as FollowRequestMessage
|
||||||
);
|
);
|
||||||
|
} else if (message.hasFollowconfirmationmessage()) {
|
||||||
|
socketManager.handleFollowConfirmation(
|
||||||
|
client,
|
||||||
|
message.getFollowconfirmationmessage() as FollowConfirmationMessage
|
||||||
|
);
|
||||||
|
} else if (message.hasFollowabortmessage()) {
|
||||||
|
socketManager.handleFollowAbort(client, message.getFollowabortmessage() as FollowAbortMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ok is false if backpressure was built up, wait for drain */
|
/* Ok is false if backpressure was built up, wait for drain */
|
||||||
|
@ -8,7 +8,9 @@ import {
|
|||||||
CharacterLayerMessage,
|
CharacterLayerMessage,
|
||||||
EmoteEventMessage,
|
EmoteEventMessage,
|
||||||
EmotePromptMessage,
|
EmotePromptMessage,
|
||||||
FollowMeRequestMessage,
|
FollowRequestMessage,
|
||||||
|
FollowConfirmationMessage,
|
||||||
|
FollowAbortMessage,
|
||||||
GroupDeleteMessage,
|
GroupDeleteMessage,
|
||||||
ItemEventMessage,
|
ItemEventMessage,
|
||||||
JoinRoomMessage,
|
JoinRoomMessage,
|
||||||
@ -270,9 +272,21 @@ export class SocketManager implements ZoneEventListener {
|
|||||||
this.handleViewport(client, viewport.toObject());
|
this.handleViewport(client, viewport.toObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFollowMeRequest(client: ExSocketInterface, requestMessage: FollowMeRequestMessage): void {
|
handleFollowRequest(client: ExSocketInterface, message: FollowRequestMessage): void {
|
||||||
const pusherToBackMessage = new PusherToBackMessage();
|
const pusherToBackMessage = new PusherToBackMessage();
|
||||||
pusherToBackMessage.setFollowmerequestmessage(requestMessage);
|
pusherToBackMessage.setFollowrequestmessage(message);
|
||||||
|
client.backConnection.write(pusherToBackMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFollowConfirmation(client: ExSocketInterface, message: FollowConfirmationMessage): void {
|
||||||
|
const pusherToBackMessage = new PusherToBackMessage();
|
||||||
|
pusherToBackMessage.setFollowconfirmationmessage(message);
|
||||||
|
client.backConnection.write(pusherToBackMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFollowAbort(client: ExSocketInterface, message: FollowAbortMessage): void {
|
||||||
|
const pusherToBackMessage = new PusherToBackMessage();
|
||||||
|
pusherToBackMessage.setFollowabortmessage(message);
|
||||||
client.backConnection.write(pusherToBackMessage);
|
client.backConnection.write(pusherToBackMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user