Live location tracking and playback for the game "manhunt"
at main 420 lines 13 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) 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}