diff --git a/TODO.md b/TODO.md
index 13ba85b..d5bc337 100644
--- a/TODO.md
+++ b/TODO.md
@@ -20,5 +20,6 @@
- [x] Signaling: All of it
- [x] Backend : Better transport error handling
- [ ] Backend : Abstract lobby? Separate crate?
+- [x] Transport : Handle transport cancellation better
- [x] Backend : Add checks for when the `powerup_locations` field is an empty array in settings
- [ ] Backend : More tests
diff --git a/backend/src/game/mod.rs b/backend/src/game/mod.rs
index 10743e6..f3462b0 100644
--- a/backend/src/game/mod.rs
+++ b/backend/src/game/mod.rs
@@ -117,7 +117,7 @@ impl Game {
}
}
- async fn consume_event(&self, state: &mut GameState, event: GameEvent) -> Result {
+ async fn consume_event(&self, state: &mut GameState, event: GameEvent) -> Result {
if !state.game_ended() {
state.event_history.push((Utc::now(), event.clone()));
}
@@ -126,7 +126,7 @@ impl Game {
GameEvent::Ping(player_ping) => state.add_ping(player_ping),
GameEvent::ForcePing(target, display) => {
if target != state.id {
- return Ok(());
+ return Ok(false);
}
let ping = if let Some(display) = display {
@@ -149,7 +149,7 @@ impl Game {
state.remove_player(id);
}
GameEvent::TransportDisconnect => {
- bail!("Transport disconnected");
+ return Ok(true);
}
GameEvent::TransportError(err) => {
bail!("Transport error: {err}");
@@ -161,7 +161,7 @@ impl Game {
self.state_update_sender.send_update();
- Ok(())
+ Ok(false)
}
/// Perform a tick for a specific moment in time
@@ -253,7 +253,7 @@ impl Game {
}
/// Main loop of the game, handles ticking and receiving messages from [Transport].
- pub async fn main_loop(&self) -> Result {
+ pub async fn main_loop(&self) -> Result
)}
Quit
diff --git a/frontend/src/components/LobbyScreen.tsx b/frontend/src/components/LobbyScreen.tsx
index 9309fc4..6a568c6 100644
--- a/frontend/src/components/LobbyScreen.tsx
+++ b/frontend/src/components/LobbyScreen.tsx
@@ -1,19 +1,13 @@
import React from "react";
import { commands } from "@/bindings";
-import { useTauriEvent } from "@/lib/hooks";
+import { sharedSwrConfig, useTauriEvent } from "@/lib/hooks";
import useSWR from "swr";
-import { unwrapResult } from "@/lib/result";
export default function LobbyScreen() {
const { data: lobbyState, mutate } = useSWR(
"fetch-lobby-state",
- async () => {
- return unwrapResult(await commands.getLobbyState());
- },
- {
- suspense: true,
- dedupingInterval: 100
- }
+ commands.getLobbyState,
+ sharedSwrConfig
);
useTauriEvent("lobbyStateUpdate", () => {
@@ -21,15 +15,15 @@ export default function LobbyScreen() {
});
const setSeeker = async (seeker: boolean) => {
- unwrapResult(await commands.switchTeams(seeker));
+ await commands.switchTeams(seeker);
};
const startGame = async () => {
- unwrapResult(await commands.hostStartGame());
+ await commands.hostStartGame();
};
const quit = async () => {
- unwrapResult(await commands.quitToMenu());
+ await commands.quitToMenu();
};
if (lobbyState.self_id === null) {
diff --git a/frontend/src/components/MenuScreen.tsx b/frontend/src/components/MenuScreen.tsx
index 0c1438d..5e1156f 100644
--- a/frontend/src/components/MenuScreen.tsx
+++ b/frontend/src/components/MenuScreen.tsx
@@ -1,6 +1,7 @@
import { commands, GameSettings } from "@/bindings";
-import { unwrapResult } from "@/lib/result";
+import { sharedSwrConfig } from "@/lib/hooks";
import React from "react";
+import useSWR from "swr";
// Temp settings for now.
const settings: GameSettings = {
@@ -20,23 +21,25 @@ const settings: GameSettings = {
]
};
-function MainMenu({
- profilePromise,
- historyPromise
-}: {
- profilePromise: ReturnType;
- historyPromise: ReturnType;
-}) {
- const initialProfile = unwrapResult(React.use(profilePromise));
- const gameHistory = unwrapResult(React.use(historyPromise));
- const [profile, setProfile] = React.useState(initialProfile);
- const [newName, setName] = React.useState(initialProfile.display_name);
+export default function MenuScreen() {
const [roomCode, setRoomCode] = React.useState("");
+ const [newName, setName] = React.useState("");
+
+ const { data: profile, mutate: setProfile } = useSWR(
+ "fetch-profile",
+ commands.getProfile,
+ sharedSwrConfig
+ );
+ const { data: gameHistory } = useSWR(
+ "list-game-history",
+ commands.listGameHistories,
+ sharedSwrConfig
+ );
const onStartGame = async (code: string | null) => {
if (code) {
try {
- const validCode = unwrapResult(await commands.checkRoomCode(code));
+ const validCode = await commands.checkRoomCode(code);
if (!validCode) {
window.alert("Invalid Join Code");
return;
@@ -50,10 +53,8 @@ function MainMenu({
};
const onSaveProfile = async () => {
- unwrapResult(await commands.updateProfile({ ...profile, display_name: newName }));
- setProfile((p) => {
- return { ...p, display_name: newName };
- });
+ await commands.updateProfile({ ...profile, display_name: newName });
+ setProfile({ ...profile, display_name: newName });
};
return (
@@ -77,7 +78,11 @@ function MainMenu({
Edit Profile
- setName(e.target.value)} />
+ setName(e.target.value)}
+ />
Previous Games
@@ -89,14 +94,3 @@ function MainMenu({
>
);
}
-
-export default function MenuScreen() {
- const profilePromise = commands.getProfile();
- const previousGamesPromise = commands.listGameHistories();
-
- return (
- Loading profile}>
-
-
- );
-}
diff --git a/frontend/src/components/SetupScreen.tsx b/frontend/src/components/SetupScreen.tsx
index f04a813..9bbba8e 100644
--- a/frontend/src/components/SetupScreen.tsx
+++ b/frontend/src/components/SetupScreen.tsx
@@ -1,13 +1,12 @@
import React from "react";
import { commands, PlayerProfile } from "@/bindings";
-import { unwrapResult } from "@/lib/result";
export default function SetupScreen() {
const [displayName, setName] = React.useState("User");
const onSave = async () => {
const profile = { display_name: displayName, pfp_base64: null } as PlayerProfile;
- unwrapResult(await commands.completeSetup(profile));
+ await commands.completeSetup(profile);
};
return (
diff --git a/frontend/src/lib/hooks.ts b/frontend/src/lib/hooks.ts
index 8bc6627..28b2038 100644
--- a/frontend/src/lib/hooks.ts
+++ b/frontend/src/lib/hooks.ts
@@ -1,17 +1,22 @@
import { useEffect } from "react";
import { events } from "@/bindings";
+import { SWRConfiguration } from "swr";
type ExtractCallback = (
payload: Parameters[0]>[0]["payload"]
) => void;
+type SWRConfigTyp = { suspense: true } & SWRConfiguration;
+
+export const sharedSwrConfig: SWRConfigTyp = { suspense: true, dedupingInterval: 100 };
+
/**
* Convenience hook that does useEffect for a Tauri event and handles unsubscribing on unmount
*/
-export const useTauriEvent = (
+export function useTauriEvent(
tauriEvent: E,
cb: ExtractCallback
-) => {
+) {
useEffect(() => {
const unlisten = events[tauriEvent].listen((e) => {
cb(e.payload);
@@ -21,4 +26,4 @@ export const useTauriEvent = (
unlisten.then((f) => f());
};
}, [tauriEvent, cb]);
-};
+}
diff --git a/frontend/src/lib/result.ts b/frontend/src/lib/result.ts
deleted file mode 100644
index e192cc7..0000000
--- a/frontend/src/lib/result.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Result } from "@/bindings.ts";
-
-export const unwrapResult = (res: Result): T => {
- switch (res.status) {
- case "ok":
- return res.data;
- case "error":
- throw res.error;
- }
-};
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
index 913f447..cf00766 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -3,6 +3,25 @@ import ReactDOM from "react-dom/client";
const App = React.lazy(() => import("@/components/App"));
+import { warn, debug, trace, info, error } from "@tauri-apps/plugin-log";
+
+function forwardConsole(
+ fnName: "log" | "debug" | "info" | "warn" | "error",
+ logger: (message: string) => Promise
+) {
+ const original = console[fnName];
+ console[fnName] = (message) => {
+ original(message);
+ logger(message);
+ };
+}
+
+forwardConsole("log", trace);
+forwardConsole("debug", debug);
+forwardConsole("info", info);
+forwardConsole("warn", warn);
+forwardConsole("error", error);
+
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index 2fad73d..fb4ae69 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -4,7 +4,7 @@ import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";
-const host = process.env.TAURI_DEV_HOST;
+const host = process.env.HOST_OVERRIDE || process.env.TAURI_DEV_HOST;
export default defineConfig(async () => ({
plugins: [react()],