// Package games serves emulated games: platform detection from the ROM file // and per-user save states. // // The emulator itself runs in the browser (EmulatorJS); the server's job is to // identify the platform, hand over the ROM, and keep each user's saves. package games import ( "strings" ) // Kind is the media kind this module owns. const Kind = "games" // Platform is what a ROM extension tells us. type Platform struct { // Name is the human label, e.g. "Super Nintendo". Name string // Core is the EmulatorJS core id, e.g. "snes". Empty when EmulatorJS has // no core for this platform, in which case the UI offers a download // instead of a player. Core string } // platforms maps a file extension to its platform. Extensions are the only // signal available without parsing ROM headers, and they are reliable enough // in practice because emulator collections are named consistently. var platforms = map[string]Platform{ ".nes": {"Nintendo Entertainment System", "nes"}, ".fds": {"Famicom Disk System", "nes"}, ".snes": {"Super Nintendo", "snes"}, ".sfc": {"Super Nintendo", "snes"}, ".smc": {"Super Nintendo", "snes"}, ".gba": {"Game Boy Advance", "gba"}, ".gb": {"Game Boy", "gb"}, ".gbc": {"Game Boy Color", "gb"}, ".n64": {"Nintendo 64", "n64"}, ".z64": {"Nintendo 64", "n64"}, ".v64": {"Nintendo 64", "n64"}, ".nds": {"Nintendo DS", "nds"}, ".3ds": {"Nintendo 3DS", ""}, ".cia": {"Nintendo 3DS", ""}, ".md": {"Sega Genesis", "segaMD"}, ".gen": {"Sega Genesis", "segaMD"}, ".smd": {"Sega Genesis", "segaMD"}, ".sms": {"Sega Master System", "segaMS"}, ".gg": {"Game Gear", "segaGG"}, ".pce": {"PC Engine", "pce"}, ".ngp": {"Neo Geo Pocket", "ngp"}, ".ngc": {"Neo Geo Pocket Color", "ngp"}, ".ws": {"WonderSwan", "ws"}, ".wsc": {"WonderSwan Color", "ws"}, ".a26": {"Atari 2600", "atari2600"}, ".a78": {"Atari 7800", "atari7800"}, ".lnx": {"Atari Lynx", "lynx"}, ".col": {"ColecoVision", "coleco"}, ".int": {"Intellivision", "intv"}, ".psx": {"PlayStation", "psx"}, ".ps1": {"PlayStation", "psx"}, ".cue": {"PlayStation", "psx"}, ".chd": {"PlayStation", "psx"}, ".pbp": {"PlayStation", "psx"}, } // PlatformFor returns the platform for a file path, or a zero Platform with // ok=false when the extension is unrecognised. func PlatformFor(path string) (Platform, bool) { ext := strings.ToLower(path) if i := strings.LastIndexByte(ext, '.'); i >= 0 { ext = ext[i:] } else { return Platform{}, false } p, ok := platforms[ext] return p, ok } // Playable reports whether EmulatorJS can run this platform in the browser. func (p Platform) Playable() bool { return p.Core != "" } // Extensions returns every ROM extension the module recognises, for tests and // diagnostics. func Extensions() []string { out := make([]string, 0, len(platforms)) for ext := range platforms { out = append(out, ext) } return out }