Live location tracking and playback for the game "manhunt"
1/* eslint @typescript-eslint/no-unused-vars: 0 */
2/* eslint @typescript-eslint/no-explicit-any: 0 */
3// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually.
4
5/** user-defined commands **/
6
7export const commands = {
8 /**
9 * (Screen: Menu) Start/Join a new lobby, set `join_code` to `null` to be host,
10 * set it to a join code to be a client. This triggers a screen change to [AppScreen::Lobby]
11 */
12 async startLobby(joinCode: string | null, settings: GameSettings): Promise<null> {
13 return await TAURI_INVOKE("start_lobby", { joinCode, settings });
14 },
15 /**
16 * (Screen: Menu) Get the user's player profile
17 */
18 async getProfile(): Promise<PlayerProfile> {
19 return await TAURI_INVOKE("get_profile");
20 },
21 /**
22 * Quit a running game or leave a lobby
23 */
24 async quitToMenu(): Promise<null> {
25 return await TAURI_INVOKE("quit_to_menu");
26 },
27 /**
28 * Get the screen the app should currently be on, returns [AppScreen]
29 */
30 async getCurrentScreen(): Promise<AppScreen> {
31 return await TAURI_INVOKE("get_current_screen");
32 },
33 /**
34 * (Screen: Menu) Update the player's profile and persist it
35 */
36 async updateProfile(newProfile: PlayerProfile): Promise<null> {
37 return await TAURI_INVOKE("update_profile", { newProfile });
38 },
39 /**
40 * (Screen: Lobby) Get the current state of the lobby, call after receiving an update event
41 */
42 async getLobbyState(): Promise<LobbyState> {
43 return await TAURI_INVOKE("get_lobby_state");
44 },
45 /**
46 * (Screen: Lobby) HOST ONLY: Push new settings to everyone, does nothing on clients. Returns the
47 * new lobby state
48 */
49 async hostUpdateSettings(settings: GameSettings): Promise<null> {
50 return await TAURI_INVOKE("host_update_settings", { settings });
51 },
52 /**
53 * (Screen: Lobby) Switch teams between seekers and hiders, returns the new [LobbyState]
54 */
55 async switchTeams(seeker: boolean): Promise<null> {
56 return await TAURI_INVOKE("switch_teams", { seeker });
57 },
58 /**
59 * (Screen: Lobby) HOST ONLY: Start the game, stops anyone else from joining and switched screen
60 * to AppScreen::Game.
61 */
62 async hostStartGame(): Promise<null> {
63 return await TAURI_INVOKE("host_start_game");
64 },
65 /**
66 * (Screen: Game) Mark this player as caught, this player will become a seeker. Returns the new game state
67 */
68 async markCaught(): Promise<null> {
69 return await TAURI_INVOKE("mark_caught");
70 },
71 /**
72 * (Screen: Game) Grab a powerup on the map, this should be called when the user is *in range* of
73 * the powerup. Returns the new game state after rolling for the powerup
74 */
75 async grabPowerup(): Promise<null> {
76 return await TAURI_INVOKE("grab_powerup");
77 },
78 /**
79 * (Screen: Game) Use the currently held powerup in the player's held_powerup. Does nothing if the
80 * player has none. Returns the updated game state
81 */
82 async activatePowerup(): Promise<null> {
83 return await TAURI_INVOKE("activate_powerup");
84 },
85 /**
86 * (Screen: Menu) Check if a room code is valid to join, use this before starting a game
87 * for faster error checking.
88 */
89 async checkRoomCode(code: string): Promise<boolean> {
90 return await TAURI_INVOKE("check_room_code", { code });
91 },
92 /**
93 * (Screen: Game) Get all player profiles with display names and profile pictures for this game.
94 * This value will never change and is fairly expensive to clone, so please minimize calls to
95 * this command.
96 */
97 async getProfiles(): Promise<Partial<{ [key in string]: PlayerProfile }>> {
98 return await TAURI_INVOKE("get_profiles");
99 },
100 /**
101 * (Screen: Menu) Go to the game replay screen to replay the game history specified by id
102 */
103 async replayGame(id: string): Promise<null> {
104 return await TAURI_INVOKE("replay_game", { id });
105 },
106 /**
107 * (Screen: Menu) Get a list of all previously played games, returns of list of DateTimes that represent when
108 * each game started, use this as a key
109 */
110 async listGameHistories(): Promise<string[]> {
111 return await TAURI_INVOKE("list_game_histories");
112 },
113 /**
114 * (Screen: Replay) Get the game history that's currently being replayed. Try to limit calls to
115 * this
116 */
117 async getCurrentReplayHistory(): Promise<AppGameHistory> {
118 return await TAURI_INVOKE("get_current_replay_history");
119 },
120 /**
121 * (Screen: Game) Get the current settings for this game.
122 */
123 async getGameSettings(): Promise<GameSettings> {
124 return await TAURI_INVOKE("get_game_settings");
125 },
126 /**
127 * (Screen: Game) Get the current state of the game.
128 */
129 async getGameState(): Promise<GameUiState> {
130 return await TAURI_INVOKE("get_game_state");
131 },
132 /**
133 * (Screen: Setup) Complete user setup and go to the menu screen
134 */
135 async completeSetup(profile: PlayerProfile): Promise<null> {
136 return await TAURI_INVOKE("complete_setup", { profile });
137 }
138};
139
140/** user-defined events **/
141
142export const events = __makeEvents__<{
143 changeScreen: ChangeScreen;
144 gameStateUpdate: GameStateUpdate;
145 lobbyStateUpdate: LobbyStateUpdate;
146}>({
147 changeScreen: "change-screen",
148 gameStateUpdate: "game-state-update",
149 lobbyStateUpdate: "lobby-state-update"
150});
151
152/** user-defined constants **/
153
154/** user-defined types **/
155
156export type AppGameHistory = {
157 history: GameHistory;
158 profiles: Partial<{ [key in string]: PlayerProfile }>;
159 settings: GameSettings;
160};
161export type AppScreen = "Setup" | "Menu" | "Lobby" | "Game" | "Replay";
162/**
163 * The app is changing screens, contains the screen it's switching to
164 */
165export type ChangeScreen = AppScreen;
166/**
167 * An event used between players to update state
168 */
169export type GameEvent =
170 /**
171 * A player has been caught and is now a seeker, contains the ID of the caught player
172 */
173 | { PlayerCaught: string }
174 /**
175 * Public ping from a player revealing location
176 */
177 | { Ping: PlayerPing }
178 /**
179 * Force the player specified in `0` to ping, optionally display the ping as from the user
180 * specified in `1`.
181 */
182 | { ForcePing: [string, string | null] }
183 /**
184 * Force a powerup to despawn because a player got it, contains the player that got it.
185 */
186 | { PowerupDespawn: string }
187 /**
188 * Contains location history of the given player, used after the game to sync location
189 * histories
190 */
191 | { PostGameSync: [string, [string, Location][]] };
192export type GameHistory = {
193 my_id: string;
194 game_started: string;
195 game_ended: string;
196 events: [string, GameEvent][];
197 locations: [string, [string, Location][]][];
198};
199/**
200 * Settings for the game, host is the only person able to change these
201 */
202export type GameSettings = {
203 /**
204 * The random seed used for shared rng
205 */
206 random_seed: number;
207 /**
208 * The number of seconds to wait before seekers are allowed to go
209 */
210 hiding_time_seconds: number;
211 /**
212 * Condition to wait for global pings to begin
213 */
214 ping_start: PingStartCondition;
215 /**
216 * Time between pings after the condition is met (first ping is either after the interval or
217 * instantly after the condition is met depending on the condition)
218 */
219 ping_minutes_interval: number;
220 /**
221 * Condition for powerups to start spawning
222 */
223 powerup_start: PingStartCondition;
224 /**
225 * Chance every minute of a powerup spawning, out of 100
226 */
227 powerup_chance: number;
228 /**
229 * Hard cooldown between powerups spawning
230 */
231 powerup_minutes_cooldown: number;
232 /**
233 * Locations that powerups may spawn at
234 */
235 powerup_locations: Location[];
236};
237/**
238 * The state of the game has changed
239 */
240export type GameStateUpdate = null;
241/**
242 * Subset of [GameState] that is meant to be sent to a UI frontend
243 */
244export type GameUiState = {
245 /**
246 * ID of the local player
247 */
248 my_id: string;
249 /**
250 * A map of player IDs to whether that player is a seeker
251 */
252 caught_state: Partial<{ [key in string]: boolean }>;
253 /**
254 * A powerup that is available on the map
255 */
256 available_powerup: Location | null;
257 /**
258 * A map of player IDs to an active ping on them
259 */
260 pings: Partial<{ [key in string]: PlayerPing }>;
261 /**
262 * When the game was started **in UTC**
263 */
264 game_started: string;
265 /**
266 * When the game ended, when this is Option::Some, the game has ended
267 */
268 game_ended: string | null;
269 /**
270 * The last time all hiders were pinged **in UTC**
271 */
272 last_global_ping: string | null;
273 /**
274 * The last time a powerup was spawned **in UTC**
275 */
276 last_powerup_spawn: string | null;
277 /**
278 * The [PowerUpType] the local player is holding
279 */
280 held_powerup: PowerUpType | null;
281 /**
282 * When the seekers were allowed to start **in UTC**
283 */
284 seekers_started: string | null;
285};
286export type LobbyState = {
287 profiles: Partial<{ [key in string]: PlayerProfile }>;
288 join_code: string;
289 /**
290 * True represents seeker, false hider
291 */
292 teams: Partial<{ [key in string]: boolean }>;
293 self_id: string;
294 is_host: boolean;
295 settings: GameSettings;
296};
297/**
298 * The state of the lobby has changed
299 */
300export type LobbyStateUpdate = null;
301/**
302 * Some location in the world as gotten from a Geolocation API
303 */
304export type Location = {
305 /**
306 * Latitude
307 */
308 lat: number;
309 /**
310 * Longitude
311 */
312 long: number;
313 /**
314 * The bearing (float normalized from 0 to 1) optional as GPS can't always determine
315 */
316 heading: number | null;
317};
318/**
319 * The starting condition for global pings to begin
320 */
321export type PingStartCondition =
322 /**
323 * Wait For X players to be caught before beginning global pings
324 */
325 | { Players: number }
326 /**
327 * Wait for X minutes after game start to begin global pings
328 */
329 | { Minutes: number }
330 /**
331 * Don't wait at all, ping location after seekers are released
332 */
333 | "Instant";
334/**
335 * An on-map ping of a player
336 */
337export type PlayerPing = {
338 /**
339 * Location of the ping
340 */
341 loc: Location;
342 /**
343 * Time the ping happened
344 */
345 timestamp: string;
346 /**
347 * The player to display as
348 */
349 display_player: string;
350 /**
351 * The actual player that initialized this ping
352 */
353 real_player: string;
354};
355export type PlayerProfile = { display_name: string; pfp_base64: string | null };
356/**
357 * Type of powerup
358 */
359export type PowerUpType =
360 /**
361 * Ping a random seeker instead of a hider
362 */
363 | "PingSeeker"
364 /**
365 * Pings all seekers locations on the map for hiders
366 */
367 | "PingAllSeekers"
368 /**
369 * Ping another random hider instantly
370 */
371 | "ForcePingOther";
372
373/** tauri-specta globals **/
374
375import { invoke as TAURI_INVOKE, Channel as TAURI_CHANNEL } from "@tauri-apps/api/core";
376import * as TAURI_API_EVENT from "@tauri-apps/api/event";
377import { type WebviewWindow as __WebviewWindow__ } from "@tauri-apps/api/webviewWindow";
378
379type __EventObj__<T> = {
380 listen: (cb: TAURI_API_EVENT.EventCallback<T>) => ReturnType<typeof TAURI_API_EVENT.listen<T>>;
381 once: (cb: TAURI_API_EVENT.EventCallback<T>) => ReturnType<typeof TAURI_API_EVENT.once<T>>;
382 emit: null extends T
383 ? (payload?: T) => ReturnType<typeof TAURI_API_EVENT.emit>
384 : (payload: T) => ReturnType<typeof TAURI_API_EVENT.emit>;
385};
386
387export type Result<T, E> = { status: "ok"; data: T } | { status: "error"; error: E };
388
389function __makeEvents__<T extends Record<string, any>>(mappings: Record<keyof T, string>) {
390 return new Proxy(
391 {} as unknown as {
392 [K in keyof T]: __EventObj__<T[K]> & {
393 (handle: __WebviewWindow__): __EventObj__<T[K]>;
394 };
395 },
396 {
397 get: (_, event) => {
398 const name = mappings[event as keyof T];
399
400 return new Proxy((() => {}) as any, {
401 apply: (_, __, [window]: [__WebviewWindow__]) => ({
402 listen: (arg: any) => window.listen(name, arg),
403 once: (arg: any) => window.once(name, arg),
404 emit: (arg: any) => window.emit(name, arg)
405 }),
406 get: (_, command: keyof __EventObj__<any>) => {
407 switch (command) {
408 case "listen":
409 return (arg: any) => TAURI_API_EVENT.listen(name, arg);
410 case "once":
411 return (arg: any) => TAURI_API_EVENT.once(name, arg);
412 case "emit":
413 return (arg: any) => TAURI_API_EVENT.emit(name, arg);
414 }
415 }
416 });
417 }
418 }
419 );
420}