Client-side support for private rooms

This commit is contained in:
thepaperpilot 2023-02-23 22:23:25 -06:00
parent ff76c6d53a
commit 2e964e4117
6 changed files with 41 additions and 70 deletions

View file

@ -5,25 +5,24 @@
</template>
<template v-slot:body>
<component :is="settingFieldsComponent" />
<Text title="Private room name" v-model="privateRoomName" />
<Text title="Private room PW" :password="true" v-model="privateRoomPassword" />
<div>Currently in: {{room ? room : "Public lobby"}}.</div>
<button class="button" style="padding: 1em" v-if="room !== privateRoomName" @click="joinRoom">Connect to {{privateRoomName || "Public Lobby"}}</button>
<div style="color: red" v-if="roomConnectionError">{{ roomConnectionError }}</div>
</template>
</Modal>
</template>
<script setup lang="tsx">
import Modal from "components/Modal.vue";
import projInfo from "data/projInfo.json";
import { save } from "util/save";
import rawThemes from "data/themes";
import { emit, room, roomConnectionError } from "data/socket";
import { jsx } from "features/feature";
import Tooltip from "features/tooltips/Tooltip.vue";
import player from "game/player";
import settings, { settingFields } from "game/settings";
import { camelToTitle, Direction } from "util/common";
import { save } from "util/save";
import { coerceComponent, render } from "util/vue";
import { computed, ref, toRefs } from "vue";
import Select from "./fields/Select.vue";
import Toggle from "./fields/Toggle.vue";
import FeedbackButton from "./fields/FeedbackButton.vue";
import Text from "./fields/Text.vue";
const isOpen = ref(false);
const currentTab = ref("behaviour");
@ -45,68 +44,16 @@ defineExpose({
}
});
const themes = Object.keys(rawThemes).map(theme => ({
label: camelToTitle(theme),
value: theme
}));
const settingFieldsComponent = computed(() => {
return coerceComponent(jsx(() => (<>{settingFields.map(render)}</>)));
});
const { showTPS, theme, unthrottled, alignUnits } = toRefs(settings);
const { autosave, offlineProd } = toRefs(player);
const isPaused = computed({
get() {
return player.devSpeed === 0;
},
set(value: boolean) {
player.devSpeed = value ? 0 : null;
}
});
const { privateRoomName, privateRoomPassword } = toRefs(settings);
const unthrottledTitle = jsx(() => (
<span class="option-title">
Unthrottled
<desc>Allow the game to run as fast as possible. Not battery friendly.</desc>
</span>
));
const offlineProdTitle = jsx(() => (
<span class="option-title">
Offline Production<Tooltip display="Save-specific" direction={Direction.Right}>*</Tooltip>
<desc>Simulate production that occurs while the game is closed.</desc>
</span>
));
const autosaveTitle = jsx(() => (
<span class="option-title">
Autosave<Tooltip display="Save-specific" direction={Direction.Right}>*</Tooltip>
<desc>Automatically save the game every second or when the game is closed.</desc>
</span>
));
const isPausedTitle = jsx(() => (
<span class="option-title">
Pause game<Tooltip display="Save-specific" direction={Direction.Right}>*</Tooltip>
<desc>Stop everything from moving.</desc>
</span>
));
const themeTitle = jsx(() => (
<span class="option-title">
Theme
<desc>How the game looks.</desc>
</span>
));
const showTPSTitle = jsx(() => (
<span class="option-title">
Show TPS
<desc>Show TPS meter at the bottom-left corner of the page.</desc>
</span>
));
const alignModifierUnitsTitle = jsx(() => (
<span class="option-title">
Align modifier units
<desc>Align numbers to the beginning of the unit in modifier view.</desc>
</span>
));
function joinRoom() {
roomConnectionError.value = "";
emit("change room", settings.privateRoomName, settings.privateRoomPassword);
}
</script>
<style>

View file

@ -14,7 +14,7 @@
/>
<input
v-else
type="text"
:type="password == true ? 'password' : 'text'"
v-model="value"
:placeholder="placeholder"
:class="{ fullWidth: !title }"
@ -39,6 +39,7 @@ const props = defineProps<{
placeholder?: string;
maxHeight?: number;
submitOnBlur?: boolean;
password?: boolean;
}>();
const emit = defineEmits<{
(e: "update:modelValue", value: string): void;

View file

@ -2,7 +2,7 @@ import Text from "components/fields/Text.vue";
import projInfo from "data/projInfo.json";
import { jsx, setDefault } from "features/feature";
import { globalBus } from "game/events";
import { registerSettingField } from "game/settings";
import settings, { registerSettingField } from "game/settings";
import satisfies from "semver/functions/satisfies";
import { io, Socket } from "socket.io-client";
import { ref, watch } from "vue";
@ -13,6 +13,8 @@ import { BattleOutcome, Character, ClientToServerEvents, ServerToClientEvents }
export const connected = ref<boolean>(false);
export const nickname = ref<string>("");
export const room = ref<string>("");
export const roomConnectionError = ref<string>("");
const toast = useToast();
@ -93,6 +95,11 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
connectionError.value = "";
connected.value = true;
main.reset.reset();
room.value = "";
roomConnectionError.value = "";
if (settings.privateRoomName) {
socket.emit("change room", settings.privateRoomName, settings.privateRoomPassword);
}
});
socket.on("connect_error", error => {
connectionError.value = `${error.name}: ${error.message}`;
@ -223,6 +230,15 @@ function setupSocket(socket: Socket<ServerToClientEvents, ClientToServerEvents>)
main.frozen.value.push(index);
}
});
socket.on("room", r => {
main.reset.reset();
room.value = r;
roomConnectionError.value = "";
});
socket.on("room failed", err => {
room.value = "";
roomConnectionError.value = err;
});
}
function startStream(

View file

@ -110,7 +110,7 @@ export default {
"--highlighted": "#434c5e",
"--bought": "#fff7f6",
"--danger": "#D08770",
"--link": "#412323",
"--link": "#8423a9",
"--outline": "#551842",
"--accent1": "#dc7d71",
"--accent2": "#8423a9",

3
src/data/types.d.ts vendored
View file

@ -42,6 +42,8 @@ interface ServerToClientEvents {
) => void;
freeze: (index: number) => void;
sell: (index: number) => void;
room: (room: string) => void;
"room failed": (err: string) => void;
}
interface ClientToServerEvents {
@ -53,4 +55,5 @@ interface ClientToServerEvents {
reroll: () => void;
stream: () => void;
newTurn: () => void;
"change room": (room: string, password: string) => void;
}

View file

@ -23,6 +23,8 @@ export interface Settings {
autoplay: boolean;
fast: boolean;
showTutorial: boolean;
privateRoomName: string;
privateRoomPassword: string;
}
const state = reactive<Partial<Settings>>({
@ -34,7 +36,9 @@ const state = reactive<Partial<Settings>>({
alignUnits: false,
autoplay: false,
fast: false,
showTutorial: true
showTutorial: true,
privateRoomName: "",
privateRoomPassword: ""
});
watch(