Change multiplayer menu
This commit is contained in:
parent
a598832dff
commit
066afc5dfe
3 changed files with 134 additions and 75 deletions
|
@ -7,7 +7,7 @@
|
||||||
<Draggable
|
<Draggable
|
||||||
:list="settings.saves"
|
:list="settings.saves"
|
||||||
handle=".handle"
|
handle=".handle"
|
||||||
v-if="shown"
|
v-if="shown && (!room || isHosting)"
|
||||||
:itemKey="(save: string) => save"
|
:itemKey="(save: string) => save"
|
||||||
>
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
|
@ -21,16 +21,18 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</Draggable>
|
</Draggable>
|
||||||
|
<div v-else>You are connected to a server - cannot change saves</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<Text
|
<Text
|
||||||
|
v-if="!room || isHosting"
|
||||||
v-model="saveToImport"
|
v-model="saveToImport"
|
||||||
title="Import Save"
|
title="Import Save"
|
||||||
placeholder="Paste your save here!"
|
placeholder="Paste your save here!"
|
||||||
:class="{ importingFailed }"
|
:class="{ importingFailed }"
|
||||||
/>
|
/>
|
||||||
<div class="field">
|
<div class="field" v-if="!room || isHosting">
|
||||||
<span class="field-title">Create Save</span>
|
<span class="field-title">Create Save</span>
|
||||||
<div class="field-buttons">
|
<div class="field-buttons">
|
||||||
<button class="button" @click="openSave(newSave().id)">New Game</button>
|
<button class="button" @click="openSave(newSave().id)">New Game</button>
|
||||||
|
@ -59,6 +61,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Modal from "components/Modal.vue";
|
import Modal from "components/Modal.vue";
|
||||||
import projInfo from "data/projInfo.json";
|
import projInfo from "data/projInfo.json";
|
||||||
|
import { isHosting, room } from "data/socket";
|
||||||
import type { PlayerData } from "game/player";
|
import type { PlayerData } from "game/player";
|
||||||
import player, { stringifySave } from "game/player";
|
import player, { stringifySave } from "game/player";
|
||||||
import settings from "game/settings";
|
import settings from "game/settings";
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
<button class="button open" @click="startConnecting">
|
<button class="button open" @click="startConnecting">
|
||||||
<h3>{{ room.name }}</h3>
|
<h3>{{ room.name }}</h3>
|
||||||
</button>
|
</button>
|
||||||
<span class="room-host">Hosted by {{ room.host }}</span
|
<div class="room-host">Hosted by {{ room.host }}</div>
|
||||||
><br />
|
<div class="room-host">{{ room.numContentPacks }} active content packs</div>
|
||||||
<div>{{ room.numContentPacks }} active content packs</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="details" style="display: flex">
|
<div v-else class="details" style="display: flex">
|
||||||
<span>Password:</span>
|
<span>Password:</span>
|
||||||
|
@ -108,7 +107,6 @@ function submitPassword() {
|
||||||
}
|
}
|
||||||
|
|
||||||
.room-host {
|
.room-host {
|
||||||
margin-left: 4px;
|
|
||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
<h3>Connected to {{ currentRoom }}</h3>
|
<h3>Connected to {{ currentRoom }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<h4>Connected Players</h4>
|
|
||||||
<ul class="players-list">
|
<ul class="players-list">
|
||||||
<div v-for="(nickname, i) in nicknames" :key="i" style="display: flex">
|
<div v-for="(nickname, i) in nicknames" :key="i" style="display: flex">
|
||||||
<span>{{ nickname }}</span>
|
<span>{{ nickname }}</span>
|
||||||
|
@ -31,30 +30,15 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<Room
|
|
||||||
v-for="(room, i) in rooms ?? []"
|
|
||||||
:key="i"
|
|
||||||
:room="room"
|
|
||||||
:isPrivate="false"
|
|
||||||
@connect="password => join(room.name, password)"
|
|
||||||
/>
|
|
||||||
<div v-if="rooms != null && rooms.length === 0" style="text-align: center">
|
|
||||||
No public rooms found
|
|
||||||
</div>
|
|
||||||
<div v-if="rooms == null" style="text-align: center">
|
|
||||||
Loading public rooms list...
|
|
||||||
</div>
|
|
||||||
<br />
|
<br />
|
||||||
<button
|
<button
|
||||||
class="button"
|
class="button large"
|
||||||
style="float: right; display: inline-block"
|
@click="() => host(hostRoomName, hostRoomPassword, hostPrivate)"
|
||||||
@click="refresh()"
|
|
||||||
>
|
>
|
||||||
Refresh
|
{{ isHosting ? "Close" : "Leave" }} room
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
<component v-else :is="render(tabs)" />
|
||||||
</template>
|
</template>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
Not connected to a server. Please set up networking in the options modal.
|
Not connected to a server. Please set up networking in the options modal.
|
||||||
|
@ -64,50 +48,8 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<div v-if="connected && !currentRoom">
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<div style="margin-top: 10px; margin-bottom: -10px">Direct Connect</div>
|
|
||||||
<div class="direct-connect field">
|
|
||||||
<Text v-model="directRoomName" placeholder="Room Name" />
|
|
||||||
<Text v-model="directRoomPassword" placeholder="Room Password" />
|
|
||||||
<div class="field-buttons">
|
|
||||||
<button
|
|
||||||
class="button"
|
|
||||||
@click="join(directRoomName, directRoomPassword)"
|
|
||||||
>
|
|
||||||
Connect
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style="margin-top: 10px; margin-bottom: -10px">Host current world</div>
|
|
||||||
<div class="direct-connect field">
|
|
||||||
<Text v-model="hostRoomName" placeholder="Room Name" />
|
|
||||||
<Text v-model="hostRoomPassword" placeholder="Room Password" />
|
|
||||||
<Toggle
|
|
||||||
v-model="hostPrivate"
|
|
||||||
title="Private"
|
|
||||||
style="width: 320px; margin-right: 10px"
|
|
||||||
/>
|
|
||||||
<div class="field-buttons">
|
|
||||||
<button
|
|
||||||
class="button"
|
|
||||||
@click="host(hostRoomName, hostRoomPassword, hostPrivate)"
|
|
||||||
>
|
|
||||||
Host
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div style="flex-grow: 1"></div>
|
<div style="flex-grow: 1"></div>
|
||||||
<button
|
|
||||||
v-if="currentRoom"
|
|
||||||
class="button modal-default-button"
|
|
||||||
@click="emitToServer('leave room')"
|
|
||||||
>
|
|
||||||
Leave room
|
|
||||||
</button>
|
|
||||||
<button class="button modal-default-button" @click="isOpen = false">
|
<button class="button modal-default-button" @click="isOpen = false">
|
||||||
Close
|
Close
|
||||||
</button>
|
</button>
|
||||||
|
@ -117,7 +59,7 @@
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="tsx">
|
||||||
import Text from "components/fields/Text.vue";
|
import Text from "components/fields/Text.vue";
|
||||||
import Toggle from "components/fields/Toggle.vue";
|
import Toggle from "components/fields/Toggle.vue";
|
||||||
import Modal from "components/Modal.vue";
|
import Modal from "components/Modal.vue";
|
||||||
|
@ -129,9 +71,12 @@ import {
|
||||||
nicknames,
|
nicknames,
|
||||||
room as currentRoom
|
room as currentRoom
|
||||||
} from "data/socket";
|
} from "data/socket";
|
||||||
|
import { jsx } from "features/feature";
|
||||||
|
import { createTabFamily } from "features/tabs/tabFamily";
|
||||||
import { globalBus } from "game/events";
|
import { globalBus } from "game/events";
|
||||||
import { PlayerData } from "game/player";
|
import player, { PlayerData } from "game/player";
|
||||||
import settings from "game/settings";
|
import settings from "game/settings";
|
||||||
|
import { render } from "util/vue";
|
||||||
import type { ComponentPublicInstance } from "vue";
|
import type { ComponentPublicInstance } from "vue";
|
||||||
import { ref, watch } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import { main } from "./projEntry";
|
import { main } from "./projEntry";
|
||||||
|
@ -155,9 +100,112 @@ const hostRoomName = ref("");
|
||||||
const hostRoomPassword = ref("");
|
const hostRoomPassword = ref("");
|
||||||
const hostPrivate = ref<boolean>(false);
|
const hostPrivate = ref<boolean>(false);
|
||||||
|
|
||||||
watch(isOpen, isOpen => {
|
const tabs = createTabFamily(
|
||||||
if (isOpen) {
|
{
|
||||||
|
roomList: () => ({
|
||||||
|
display: "Room List",
|
||||||
|
tab: jsx(() => (
|
||||||
|
<>
|
||||||
|
{(rooms.value ?? []).map(r => (
|
||||||
|
<Room
|
||||||
|
room={r}
|
||||||
|
isPrivate={false}
|
||||||
|
onConnect={password => join(r.name, password)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{rooms.value != null && rooms.value.length === 0 ? (
|
||||||
|
<div style="text-align: center">No public rooms found</div>
|
||||||
|
) : null}
|
||||||
|
{rooms.value == null ? (
|
||||||
|
<div style="text-align: center">Loading public rooms list...</div>
|
||||||
|
) : null}
|
||||||
|
<br />
|
||||||
|
<button class="button large" onClick={refresh}>
|
||||||
|
Refresh
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
direct: () => ({
|
||||||
|
display: "Private Room",
|
||||||
|
tab: jsx(() => (
|
||||||
|
<>
|
||||||
|
<div class="direct-connect">
|
||||||
|
<div class="field">
|
||||||
|
<Text
|
||||||
|
onUpdate:modelValue={value => (directRoomName.value = value)}
|
||||||
|
modelValue={directRoomName.value}
|
||||||
|
title="Room Name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<Text
|
||||||
|
onUpdate:modelValue={value => (directRoomPassword.value = value)}
|
||||||
|
modelValue={directRoomPassword.value}
|
||||||
|
title="Room Password"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="button large"
|
||||||
|
onClick={() => join(directRoomName.value, directRoomPassword.value)}
|
||||||
|
>
|
||||||
|
Connect
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
host: () => ({
|
||||||
|
display: "Host",
|
||||||
|
tab: jsx(() => (
|
||||||
|
<>
|
||||||
|
<div class="field">
|
||||||
|
<Text
|
||||||
|
onUpdate:modelValue={value => (hostRoomName.value = value)}
|
||||||
|
modelValue={hostRoomName.value}
|
||||||
|
title="Room Name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<Text
|
||||||
|
onUpdate:modelValue={value => (hostRoomPassword.value = value)}
|
||||||
|
modelValue={hostRoomPassword.value}
|
||||||
|
title="Room Password"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Toggle
|
||||||
|
onUpdate:modelValue={value => (hostPrivate.value = value)}
|
||||||
|
modelValue={hostPrivate.value}
|
||||||
|
title="Private"
|
||||||
|
/>
|
||||||
|
<div style="font-size: small">
|
||||||
|
You will host the currently active single player world, allowing other
|
||||||
|
players to join and modify your save. It is recommended to backup your save
|
||||||
|
frequently.
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button
|
||||||
|
class="button large"
|
||||||
|
onClick={() =>
|
||||||
|
host(hostRoomName.value, hostRoomPassword.value, hostPrivate.value)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Host
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
() => ({
|
||||||
|
style: "margin-left: 0; margin-right: 0; --layer-color: var(--link)"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
watch([isOpen, tabs.selected], ([isOpen, currentTab]) => {
|
||||||
|
if (isOpen && currentTab === "roomList") {
|
||||||
refresh();
|
refresh();
|
||||||
|
} else if (isOpen && currentTab === "host") {
|
||||||
|
hostRoomName.value = `${settings.nickname}'s ${player.name}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -165,7 +213,7 @@ watch(currentRoom, room => {
|
||||||
if (!room) {
|
if (!room) {
|
||||||
directRoomName.value = "";
|
directRoomName.value = "";
|
||||||
directRoomPassword.value = "";
|
directRoomPassword.value = "";
|
||||||
hostRoomName.value = "";
|
hostRoomName.value = `${settings.nickname}'s ${player.name}`;
|
||||||
hostRoomPassword.value = "";
|
hostRoomPassword.value = "";
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
@ -227,8 +275,18 @@ function host(room: string, password?: string, privateRoom?: boolean) {
|
||||||
.field-title {
|
.field-title {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
.direct-connect :deep(input[type="text"]) {
|
<style>
|
||||||
margin-right: 10px;
|
.large.button {
|
||||||
|
font-size: large;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--feature-background);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.large.button:hover {
|
||||||
|
background: var(--highlighted);
|
||||||
|
text-shadow: unset;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue