Live location tracking and playback for the game "manhunt"
at ben/frontend 427 lines 14 kB view raw
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}