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