Documentation
¶
Index ¶
- Constants
- func AutoCreateFirstProfile(input *storage.InputConfig, pads []PadInfo) bool
- func FireCHTRumbleEvents(events []CHTRumbleEvent, scales [maxPlayers]float64)
- func FireMotorStates(states []rumble.MotorState, scales [maxPlayers]float64, active map[int]bool) map[int]bool
- func GenerateBaselineMapping(sdlID, name string, buttonCount int, restingAxes []float64) string
- func IsReservedKey(k ebiten.Key) bool
- func KeyToName(k ebiten.Key) (string, bool)
- func PadToName(b ebiten.StandardGamepadButton) (string, bool)
- func ParseKey(name string) (ebiten.Key, bool)
- func ParsePad(name string) (ebiten.StandardGamepadButton, bool)
- func PollButtons(mapping InputMapping, gamepadID ebiten.GamepadID, ...) uint32
- func PollGamepadButtons(mapping InputMapping, gamepadID ebiten.GamepadID, disableAnalog bool) uint32
- func ResolveKeyDisplay(buttonName string, defaultKey string, overrides map[string]string) string
- func ResolvePadDisplay(buttonName string, defaultPad string, overrides map[string]string) string
- func Run(factory coreif.CoreFactory) error
- func RunDirect(factory coreif.CoreFactory, romPath string, options map[string]string, ...) error
- func SetAppIcon(data []byte)
- type AchievementOverlay
- func (o *AchievementOverlay) Draw(screen *ebiten.Image)
- func (o *AchievementOverlay) Hide()
- func (o *AchievementOverlay) InitForGame()
- func (o *AchievementOverlay) IsVisible() bool
- func (o *AchievementOverlay) Reset()
- func (o *AchievementOverlay) Show()
- func (o *AchievementOverlay) Update(nav UINavigation)
- type App
- func (a *App) Draw(screen *ebiten.Image)
- func (a *App) Exit()
- func (a *App) GetExtensions() []string
- func (a *App) GetMD5ByCRC32(crc32 uint32) string
- func (a *App) GetMissingArtImageData() []byte
- func (a *App) GetPlaceholderImageData() []byte
- func (a *App) GetWindowConfig() (width, height int, x, y *int, fullscreen bool)
- func (a *App) GetWindowWidth() int
- func (a *App) LaunchGame(gameCRC string, resume bool, discIndex int)
- func (a *App) Layout(outsideWidth, outsideHeight int) (int, int)
- func (a *App) RequestRebuild()
- func (a *App) SaveAndClose()
- func (a *App) ShowNotification(msg string)
- func (a *App) SwitchToDetail(gameCRC string)
- func (a *App) SwitchToLibrary()
- func (a *App) SwitchToScanProgress(rescanAll bool)
- func (a *App) SwitchToSettings()
- func (a *App) Update() error
- type AppState
- type AssignEvent
- type AudioPlayer
- type AudioRingBuffer
- type CHTRumbleEngine
- type CHTRumbleEntry
- type CHTRumbleEvent
- type EmuControl
- type FramebufferRenderer
- func (r *FramebufferRenderer) DrawFramebuffer(screen *ebiten.Image, pixels []byte, stride, activeHeight int)
- func (r *FramebufferRenderer) GetFramebufferImage(pixels []byte, stride, activeHeight int) *ebiten.Image
- func (r *FramebufferRenderer) SetAspectRatioMode(mode string)
- func (r *FramebufferRenderer) SetPAR(par float64)
- type GameplayManager
- func (gm *GameplayManager) CurrentGameCRC() string
- func (gm *GameplayManager) Draw(screen *ebiten.Image)
- func (gm *GameplayManager) DrawAchievementOverlay(screen *ebiten.Image)
- func (gm *GameplayManager) DrawFramebuffer() (*ebiten.Image, float64)
- func (gm *GameplayManager) DrawPauseMenu(screen *ebiten.Image)
- func (gm *GameplayManager) Exit(saveResume bool)
- func (gm *GameplayManager) IsPaused() bool
- func (gm *GameplayManager) IsPlaying() bool
- func (gm *GameplayManager) Launch(gameCRC string, resume bool, discIndex int) bool
- func (gm *GameplayManager) Resume()
- func (gm *GameplayManager) SetConfig(config *storage.Config)
- func (gm *GameplayManager) SetLibrary(library *storage.Library)
- func (gm *GameplayManager) Update() (pauseMenuOpened bool, err error)
- type InputManager
- type InputMapping
- type Notification
- func (n *Notification) Clear()
- func (n *Notification) Close()
- func (n *Notification) Draw(screen *ebiten.Image)
- func (n *Notification) IsVisible() bool
- func (n *Notification) PlaySound(soundData []byte)
- func (n *Notification) SetBadge(badge *ebiten.Image)
- func (n *Notification) Show(message string, duration time.Duration)
- func (n *Notification) ShowAchievementWithBadge(title, description string, badge *ebiten.Image)
- func (n *Notification) ShowDefault(message string)
- func (n *Notification) ShowShort(message string)
- type NotificationType
- type PadInfo
- type PauseMenu
- type PauseMenuOption
- type PlayTimeTracker
- type PlayerAssignment
- type RewindBuffer
- func (rb *RewindBuffer) Capacity() int
- func (rb *RewindBuffer) Capture(saveStater coreif.SaveStater) error
- func (rb *RewindBuffer) Count() int
- func (rb *RewindBuffer) IsRewinding() bool
- func (rb *RewindBuffer) Reset()
- func (rb *RewindBuffer) Rewind(emu coreif.Emulator, saveStater coreif.SaveStater, count int) bool
- func (rb *RewindBuffer) SetRewinding(v bool)
- type SaveStateManager
- func (m *SaveStateManager) GetCurrentSlot() int
- func (m *SaveStateManager) HasResumeState() bool
- func (m *SaveStateManager) Load(saveStater coreif.SaveStater) error
- func (m *SaveStateManager) LoadResume(saveStater coreif.SaveStater) error
- func (m *SaveStateManager) LoadSRAM(batterySaver coreif.BatterySaver) error
- func (m *SaveStateManager) NextSlot()
- func (m *SaveStateManager) PreviousSlot()
- func (m *SaveStateManager) Save(saveStater coreif.SaveStater) error
- func (m *SaveStateManager) SaveResume(saveStater coreif.SaveStater) error
- func (m *SaveStateManager) SaveResumeData(state []byte) error
- func (m *SaveStateManager) SaveSRAM(batterySaver coreif.BatterySaver) error
- func (m *SaveStateManager) SetGame(gameCRC string)
- func (m *SaveStateManager) SetLibrary(library *storage.Library)
- type ScanManager
- type ScreenshotManager
- type SearchOverlay
- type SharedFramebuffer
- type SharedInput
- type TurboState
- type UINavigation
Constants ¶
const Version = "0.4.6"
Standalone UI version
Variables ¶
This section is empty.
Functions ¶
func AutoCreateFirstProfile ¶ added in v0.5.0
func AutoCreateFirstProfile(input *storage.InputConfig, pads []PadInfo) bool
AutoCreateFirstProfile creates a profile for the first connected pad and assigns it to player 1. This happens exactly once: only when no controller profiles of any kind exist and no player has an assignment. All other profile creation is explicit through settings. Returns true if the config was modified (caller must save).
func FireCHTRumbleEvents ¶ added in v0.5.0
func FireCHTRumbleEvents(events []CHTRumbleEvent, scales [maxPlayers]float64)
FireCHTRumbleEvents sends rumble events to gamepads via Ebiten. Intensity is the authored magnitude multiplied by the rumble scale of each target player's controller profile, clamped to 1.0. A player whose scale is 0 (or who has no profile) gets no rumble. Duration is used as authored. Minimum thresholds ensure any non-zero rumble is perceptible.
func FireMotorStates ¶ added in v0.5.0
func FireMotorStates(states []rumble.MotorState, scales [maxPlayers]float64, active map[int]bool) map[int]bool
FireMotorStates applies the rumble engine's per-frame motor levels to the gamepads, scaled by each player's profile rumble scale. Levels are applied as authored with no minimum floors. A player whose scale is 0 (or who has no profile) gets no rumble. active is the set of players vibrating from the previous frame; players absent from states are stopped. Returns the new active set. Must run on the Ebiten thread.
func GenerateBaselineMapping ¶ added in v0.5.0
GenerateBaselineMapping builds a standard-layout mapping line for a controller with the given SDL GUID, display name, raw button count, and per-axis resting values. Axes resting at -1 are assigned as triggers, the rest as stick axes in leftx/lefty/rightx/righty order. Raw buttons fill the remaining standard slots in order. The d-pad is mapped to hat 0 with the conventional direction bits, since raw hats are not observable. Returns "" if sdlID is empty.
func IsReservedKey ¶
IsReservedKey returns true if the key is reserved for UI functions.
func KeyToName ¶
KeyToName converts an ebiten.Key to its name string. Returns the name and true if the key has a name, or "" and false otherwise.
func PadToName ¶
func PadToName(b ebiten.StandardGamepadButton) (string, bool)
PadToName converts an ebiten.StandardGamepadButton to its name string. Returns the name and true if the button has a name, or "" and false otherwise.
func ParseKey ¶
ParseKey converts a key name string to an ebiten.Key. Returns the key and true if the name is valid, or 0 and false otherwise.
func ParsePad ¶
func ParsePad(name string) (ebiten.StandardGamepadButton, bool)
ParsePad converts a gamepad button name string to an ebiten.StandardGamepadButton. Returns the button and true if the name is valid, or 0 and false otherwise.
func PollButtons ¶
func PollButtons(mapping InputMapping, gamepadID ebiten.GamepadID, hasGamepad, disableAnalog bool) uint32
PollButtons reads P1 input from keyboard and gamepad (including D-pad and analog stick). All buttons including D-pad are in the mapping. When disableAnalog is true, the analog stick is not polled. Returns a button bitmask.
func PollGamepadButtons ¶
func PollGamepadButtons(mapping InputMapping, gamepadID ebiten.GamepadID, disableAnalog bool) uint32
PollGamepadButtons reads P2 input from gamepad only (D-pad + analog stick + mapped buttons). No keyboard since that belongs to P1. When disableAnalog is true, the analog stick is not polled. All D-pad buttons are expected in the mapping.
func ResolveKeyDisplay ¶
ResolveKeyDisplay returns the display string for a button's current keyboard binding, checking overrides first then falling back to the provided default.
func ResolvePadDisplay ¶
ResolvePadDisplay returns the display string for a button's current controller binding, checking overrides first then falling back to the provided default.
func Run ¶
func Run(factory coreif.CoreFactory) error
Run is the public entry point for the standalone UI. It initializes storage, configures the window, creates the app, and starts the Ebiten game loop.
func RunDirect ¶
func RunDirect(factory coreif.CoreFactory, romPath string, options map[string]string, bios map[string][]byte) error
RunDirect loads a ROM and runs it directly without the full UI. The options map is applied to the emulator via SetOption. The bios map provides BIOS data keyed by BIOSOption.Key (may be nil).
func SetAppIcon ¶ added in v0.4.3
func SetAppIcon(data []byte)
SetAppIcon sets the PNG-encoded application icon. A core calls this before Run (or RunDirect) with its embedded icon. If never called the About section shows only the name and version and the default window icon is used.
Types ¶
type AchievementOverlay ¶
type AchievementOverlay struct {
// contains filtered or unexported fields
}
AchievementOverlay shows achievements during gameplay
func NewAchievementOverlay ¶
func NewAchievementOverlay(manager *achievements.Manager) *AchievementOverlay
NewAchievementOverlay creates a new achievement overlay
func (*AchievementOverlay) Draw ¶
func (o *AchievementOverlay) Draw(screen *ebiten.Image)
Draw renders the overlay
func (*AchievementOverlay) Hide ¶
func (o *AchievementOverlay) Hide()
Hide hides the achievement overlay
func (*AchievementOverlay) InitForGame ¶
func (o *AchievementOverlay) InitForGame()
InitForGame prepares the overlay for a new game session. The manager already caches achievements on LoadGame, so this just resets overlay state.
func (*AchievementOverlay) IsVisible ¶
func (o *AchievementOverlay) IsVisible() bool
IsVisible returns whether the overlay is visible
func (*AchievementOverlay) Reset ¶
func (o *AchievementOverlay) Reset()
Reset clears session state when the game ends
func (*AchievementOverlay) Show ¶
func (o *AchievementOverlay) Show()
Show displays the achievement overlay
func (*AchievementOverlay) Update ¶
func (o *AchievementOverlay) Update(nav UINavigation)
Update handles input for the overlay. Navigation (keyboard arrows, D-pad, left analog stick) and close (ESC/B/Start) come from the shared InputManager via nav. Page/Home/End and the mouse wheel are handled directly since they are not part of UINavigation.
type App ¶
type App struct {
// contains filtered or unexported fields
}
App is the main application struct that implements ebiten.Game
func (*App) GetExtensions ¶
GetExtensions returns the file extensions for the core's content: the disc image formats for a disc core, or the declared ROM extensions otherwise.
func (*App) GetMD5ByCRC32 ¶
GetMD5ByCRC32 returns the MD5 hash for a game by CRC32 from loaded RDBs
func (*App) GetMissingArtImageData ¶
GetMissingArtImageData returns the raw embedded missing-art image data shown for games that have no artwork file.
func (*App) GetPlaceholderImageData ¶
GetPlaceholderImageData returns the raw embedded placeholder image data used as the loading indicator while artwork is being loaded asynchronously.
func (*App) GetWindowConfig ¶
GetWindowConfig returns the saved window dimensions, position, and fullscreen state from config. This should be called before RunGame to set the initial window size.
func (*App) GetWindowWidth ¶
GetWindowWidth returns the current window width for responsive layouts
func (*App) LaunchGame ¶
LaunchGame starts the emulator with the specified game. discIndex selects the disc of a multi-disc game; -1 uses the remembered SelectedDisc. Ignored for single-disc and cartridge games.
func (*App) RequestRebuild ¶
func (a *App) RequestRebuild()
RequestRebuild triggers a UI rebuild for the current screen. This is safe to call from goroutines - the rebuild happens on the main thread. Focus restoration is handled in the Update loop after ui.Update()
func (*App) SaveAndClose ¶
func (a *App) SaveAndClose()
SaveAndClose saves config and library before exit
func (*App) ShowNotification ¶
ShowNotification shows a brief notification message
func (*App) SwitchToDetail ¶
SwitchToDetail transitions to the detail screen
func (*App) SwitchToLibrary ¶
func (a *App) SwitchToLibrary()
SwitchToLibrary transitions to the library screen
func (*App) SwitchToScanProgress ¶
SwitchToScanProgress transitions to the scan progress screen
func (*App) SwitchToSettings ¶
func (a *App) SwitchToSettings()
SwitchToSettings transitions to the settings screen
type AppState ¶
type AppState int
AppState represents the current state of the application
const ( // StateLibrary is the main library screen showing all games StateLibrary AppState = iota // StateDetail shows information about a selected game StateDetail // StateSettings shows application settings StateSettings // StateScanProgress shows ROM scanning progress StateScanProgress // StateError shows a startup error (corrupted config) StateError // StatePlaying is active gameplay StatePlaying )
type AssignEvent ¶ added in v0.5.0
type AssignEvent struct {
Player int // player slot index (0-based)
Controller string // controller display name
Bound bool // true = controller bound, false = unbound
}
AssignEvent reports a change to a player's controller binding.
type AudioPlayer ¶
type AudioPlayer struct {
// contains filtered or unexported fields
}
AudioPlayer is audio output only: it converts int16 stereo samples to bytes, writes them into a ring buffer that oto pulls from, and runs a silent fallback when no device is available. It does NOT pace the emulation loop - the framePacer does that, reading Buffered() as its rate-lock reference. The ring's block-on-full path remains as a backpressure safety net against pathological over-production.
When the host has no usable audio device (headless, permission denied, device busy) oto initialization fails and a timer-driven drain goroutine pulls bytes at the nominal rate a real device would, so the ring still drains and the producer's writes do not block indefinitely.
func NewAudioPlayer ¶
func NewAudioPlayer(volume float64, ringCapacity, silentFrameBytes int) *AudioPlayer
NewAudioPlayer creates audio output with a ring of ringCapacity bytes and a silent-pad frame of silentFrameBytes (both supplied by the framePacer, which owns the rate-derived sizing). volume sets the initial volume before playback starts, preventing audio pops when muted.
If the audio device is unavailable, a silent fallback drains the ring on a timer instead of the hardware clock. The returned player is always usable.
func (*AudioPlayer) Buffered ¶ added in v0.4.4
func (a *AudioPlayer) Buffered() int
Buffered returns the current ring fill in bytes. The framePacer reads this as its rate-lock reference.
func (*AudioPlayer) ClearQueue ¶
func (a *AudioPlayer) ClearQueue()
ClearQueue flushes all buffered audio from the ring buffer. Used across state transitions (rewind enter, save state load) to prevent stale audio from playing once the new state takes over. Callers must pause the emulation goroutine first so no producer write races the clear.
func (*AudioPlayer) QueueSamples ¶
func (a *AudioPlayer) QueueSamples(samples []int16)
QueueSamples converts int16 stereo samples to bytes and writes them to the ring buffer for oto to consume. Blocks when the ring is full as a backpressure safety net; real-time pacing comes from the framePacer, not from this Write.
Empty input is replaced with one frame of silence so oto always has bytes to drain and does not underrun on cold-start frames where the core produces no audio. Short non-empty frames are passed through unchanged - only zero-length input is padded.
func (*AudioPlayer) SetVolume ¶
func (a *AudioPlayer) SetVolume(vol float64)
SetVolume sets the playback volume (0.0 = silent, 1.0 = normal, 2.0 = max). Values are clamped to [0.0, 2.0]. No-op on the silent fallback.
type AudioRingBuffer ¶
type AudioRingBuffer struct {
// contains filtered or unexported fields
}
AudioRingBuffer is a thread-safe ring buffer implementing io.Reader. The emulation goroutine writes samples via Write(), and oto's player reads them via Read(). Write blocks when the buffer is full until Read frees space. Read never blocks, returning silence on underrun.
func NewAudioRingBuffer ¶
func NewAudioRingBuffer(capacity int) *AudioRingBuffer
NewAudioRingBuffer creates a ring buffer with the given capacity in bytes.
func (*AudioRingBuffer) Buffered ¶
func (rb *AudioRingBuffer) Buffered() int
Buffered returns the number of bytes currently in the buffer.
func (*AudioRingBuffer) Clear ¶
func (rb *AudioRingBuffer) Clear()
Clear resets the buffer, discarding all data. Any writer parked on a full ring is woken so it can complete its Write against the now-empty buffer.
func (*AudioRingBuffer) Close ¶
func (rb *AudioRingBuffer) Close()
Close signals shutdown. Subsequent Reads return io.EOF when the buffer is empty. Unblocks any goroutines waiting in Read or Write.
func (*AudioRingBuffer) Read ¶
func (rb *AudioRingBuffer) Read(p []byte) (int, error)
Read implements io.Reader. It never blocks: on underrun (the ring is open but empty) it returns a full buffer of silence. because the Returns io.EOF only when the buffer is closed and empty.
func (*AudioRingBuffer) Write ¶
func (rb *AudioRingBuffer) Write(p []byte)
Write copies data into the buffer, blocking on a full ring until Read frees space. If the input is larger than the buffer's capacity the leading portion is dropped and only the tail is written, because the audio device would only ever consume the most recent samples anyway.
type CHTRumbleEngine ¶ added in v0.5.0
type CHTRumbleEngine struct {
// contains filtered or unexported fields
}
CHTRumbleEngine evaluates rumble entries each frame and produces rumble events.
func NewCHTRumbleEngine ¶ added in v0.5.0
func NewCHTRumbleEngine(entries []CHTRumbleEntry, systemBigEndian bool) *CHTRumbleEngine
NewCHTRumbleEngine creates a new rumble engine from parsed entries. systemBigEndian should match SystemInfo.BigEndianMemory for the core. Byte swapping is determined per-entry by comparing the CHT entry's big_endian field against the system endianness.
func (*CHTRumbleEngine) Evaluate ¶ added in v0.5.0
func (re *CHTRumbleEngine) Evaluate(mi coreif.Memory) []CHTRumbleEvent
Evaluate reads memory for each entry, checks conditions, and returns rumble events.
func (*CHTRumbleEngine) Reset ¶ added in v0.5.0
func (re *CHTRumbleEngine) Reset()
Reset clears engine state (for save state loads or rewind).
type CHTRumbleEntry ¶ added in v0.5.0
type CHTRumbleEntry struct {
Address uint32
MemorySearchSize int // 0=1bit, 1=2bit, 2=4bit, 3=8bit, 4=16bit, 5=32bit
RumbleType int // 0-10 (0 treated as 1/changes)
RumbleValue uint32 // comparison value for types 5-10
RumblePort int // 0-15 specific, else all
BigEndian bool // CHT entry's big_endian field
PrimaryStrength uint16 // 0-65535
PrimaryDuration int // milliseconds
SecondaryStrength uint16 // 0-65535
SecondaryDuration int // milliseconds
}
CHTRumbleEntry represents a single rumble definition from a CHT file.
func ParseCHTRumbleFile ¶ added in v0.5.0
func ParseCHTRumbleFile(path string) ([]CHTRumbleEntry, error)
ParseCHTRumbleFile reads a CHT rumble file and returns the parsed entries.
type CHTRumbleEvent ¶ added in v0.5.0
type CHTRumbleEvent struct {
Port int
StrongMagnitude float64
WeakMagnitude float64
StrongDurationMs int
WeakDurationMs int
}
CHTRumbleEvent represents a rumble command to send to a gamepad.
type EmuControl ¶
type EmuControl struct {
// contains filtered or unexported fields
}
EmuControl manages pause/resume/stop coordination between the Ebiten thread and the emulation goroutine.
func NewEmuControl ¶
func NewEmuControl() *EmuControl
NewEmuControl creates a new emulation control.
func (*EmuControl) CheckPause ¶
func (ec *EmuControl) CheckPause() bool
CheckPause is called by the emulation goroutine between frames. If a pause has been requested, it sends an acknowledgment and spins until resumed or stopped. Returns false if the goroutine should exit.
func (*EmuControl) IsPaused ¶
func (ec *EmuControl) IsPaused() bool
IsPaused returns true if the emulation goroutine is currently paused.
func (*EmuControl) RequestPause ¶
func (ec *EmuControl) RequestPause()
RequestPause asks the emulation goroutine to pause and blocks until it acknowledges the pause.
func (*EmuControl) RequestResume ¶
func (ec *EmuControl) RequestResume()
RequestResume tells the emulation goroutine to resume.
func (*EmuControl) ShouldRun ¶
func (ec *EmuControl) ShouldRun() bool
ShouldRun returns true if the goroutine should continue running.
func (*EmuControl) Stop ¶
func (ec *EmuControl) Stop()
Stop signals the emulation goroutine to exit.
type FramebufferRenderer ¶
type FramebufferRenderer struct {
// contains filtered or unexported fields
}
FramebufferRenderer owns the ebiten offscreen buffer and handles pixel rendering with scaling. Replaces the emulator-specific DrawCachedFramebuffer/GetCachedFramebufferImage methods that were previously on the bridge emulator.
func NewFramebufferRenderer ¶
func NewFramebufferRenderer(screenWidth int, par float64) *FramebufferRenderer
NewFramebufferRenderer creates a renderer for the given native screen width and pixel aspect ratio.
func (*FramebufferRenderer) DrawFramebuffer ¶
func (r *FramebufferRenderer) DrawFramebuffer(screen *ebiten.Image, pixels []byte, stride, activeHeight int)
DrawFramebuffer renders pixel data to the screen with PAR-corrected aspect ratio scaling.
func (*FramebufferRenderer) GetFramebufferImage ¶
func (r *FramebufferRenderer) GetFramebufferImage(pixels []byte, stride, activeHeight int) *ebiten.Image
GetFramebufferImage returns pixel data as an ebiten.Image at native resolution. Used for shader processing.
func (*FramebufferRenderer) SetAspectRatioMode ¶
func (r *FramebufferRenderer) SetAspectRatioMode(mode string)
SetAspectRatioMode sets the aspect ratio scaling mode ("dar", "4:3", "1:1", "stretch").
func (*FramebufferRenderer) SetPAR ¶ added in v0.3.0
func (r *FramebufferRenderer) SetPAR(par float64)
SetPAR updates the pixel aspect ratio used for "dar" scaling. Called per frame with the value delivered alongside the framebuffer so cores whose PAR changes with video mode render correctly.
type GameplayManager ¶
type GameplayManager struct {
// contains filtered or unexported fields
}
GameplayManager handles all gameplay-related state and logic. This includes emulator control, input handling, save states, play time tracking, and the pause menu.
The emulator runs on a dedicated goroutine paced by the framePacer: an absolute-deadline timer at the frame interval, slowly corrected from the audio ring fill so long-term rate stays locked to the device. The Ebiten thread handles UI, input polling, and reads the shared framebuffer.
func NewGameplayManager ¶
func NewGameplayManager( factory coreif.CoreFactory, systemInfo coreif.SystemInfo, inputManager *InputManager, assignment *PlayerAssignment, saveStateManager *SaveStateManager, screenshotManager *ScreenshotManager, notification *Notification, library *storage.Library, config *storage.Config, achievementManager *achievements.Manager, metadata *metadata.MetadataManager, onExitToLibrary func(), onExitApp func(), ) *GameplayManager
NewGameplayManager creates a new gameplay manager
func (*GameplayManager) CurrentGameCRC ¶
func (gm *GameplayManager) CurrentGameCRC() string
CurrentGameCRC returns the CRC of the currently loaded game, or empty string if none
func (*GameplayManager) Draw ¶
func (gm *GameplayManager) Draw(screen *ebiten.Image)
Draw renders the gameplay screen from the shared framebuffer.
func (*GameplayManager) DrawAchievementOverlay ¶
func (gm *GameplayManager) DrawAchievementOverlay(screen *ebiten.Image)
DrawAchievementOverlay draws the achievement overlay
func (*GameplayManager) DrawFramebuffer ¶
func (gm *GameplayManager) DrawFramebuffer() (*ebiten.Image, float64)
DrawFramebuffer returns the native-resolution framebuffer and the pixel aspect ratio delivered with that frame, for the effects pipeline. Reads from the shared framebuffer rather than directly from the emulator.
func (*GameplayManager) DrawPauseMenu ¶
func (gm *GameplayManager) DrawPauseMenu(screen *ebiten.Image)
DrawPauseMenu draws the pause menu overlay
func (*GameplayManager) Exit ¶
func (gm *GameplayManager) Exit(saveResume bool)
Exit cleans up when exiting gameplay
func (*GameplayManager) IsPaused ¶
func (gm *GameplayManager) IsPaused() bool
IsPaused returns whether the pause menu is visible
func (*GameplayManager) IsPlaying ¶
func (gm *GameplayManager) IsPlaying() bool
IsPlaying returns true if a game is currently being played
func (*GameplayManager) Launch ¶
func (gm *GameplayManager) Launch(gameCRC string, resume bool, discIndex int) bool
Launch starts the emulator with the specified game. discIndex selects which disc of a multi-disc game to launch; -1 uses the entry's remembered SelectedDisc. Ignored for single-disc and cartridge games.
func (*GameplayManager) Resume ¶
func (gm *GameplayManager) Resume()
Resume resumes gameplay after the pause menu.
func (*GameplayManager) SetConfig ¶
func (gm *GameplayManager) SetConfig(config *storage.Config)
SetConfig updates the config reference and rebuilds the input mappings
func (*GameplayManager) SetLibrary ¶
func (gm *GameplayManager) SetLibrary(library *storage.Library)
SetLibrary updates the library reference
func (*GameplayManager) Update ¶
func (gm *GameplayManager) Update() (pauseMenuOpened bool, err error)
Update handles the gameplay update loop. Returns true if pause menu was opened. This runs on the Ebiten thread — it polls input and manages UI state. The emulator itself runs on a separate goroutine.
type InputManager ¶
type InputManager struct {
// contains filtered or unexported fields
}
InputManager handles all input for UI navigation. It tracks gamepad state, handles repeat navigation, and provides a clean interface for UI code to query input state.
func NewInputManager ¶
func NewInputManager() *InputManager
NewInputManager creates a new input manager
func (*InputManager) GetUINavigation ¶
func (im *InputManager) GetUINavigation() UINavigation
GetUINavigation returns the current UI navigation state. This handles keyboard arrow keys and gamepad D-pad/analog stick with repeat navigation, and A/B/Start button presses.
func (*InputManager) Update ¶
func (im *InputManager) Update() (screenshotRequested, fullscreenToggle bool)
Update polls input state. Should be called once per frame. Returns global key states: F12 screenshot and F11 fullscreen toggle.
type InputMapping ¶
type InputMapping struct {
Keys map[int]ebiten.Key // bit ID -> keyboard key
Gamepad map[int]ebiten.StandardGamepadButton // bit ID -> gamepad button
}
InputMapping maps button bit IDs to ebiten input types. Keyed by the Button.ID (bit position in the uint32 bitmask).
func BuildDefaultMapping ¶
func BuildDefaultMapping(buttons []coreif.Button) InputMapping
BuildDefaultMapping creates an InputMapping from the given button definitions. It includes D-pad defaults (WASD keyboard, D-pad controller) plus adaptor buttons. Keys that conflict with reserved standalone UI keys are skipped.
func BuildMappingFromConfig ¶
func BuildMappingFromConfig(buttons []coreif.Button, kbOverrides, padOverrides map[string]string) InputMapping
BuildMappingFromConfig creates an InputMapping using config overrides with adaptor defaults as fallback. D-pad defaults are WASD (keyboard) and DpadUp/Down/Left/Right (controller). For each button, the override map is checked first; if absent or invalid, the adaptor default is used.
type Notification ¶
type Notification struct {
// contains filtered or unexported fields
}
Notification displays temporary messages on screen
func NewNotification ¶
func NewNotification() *Notification
NewNotification creates a new notification system
func (*Notification) Draw ¶
func (n *Notification) Draw(screen *ebiten.Image)
Draw renders the notification
func (*Notification) IsVisible ¶
func (n *Notification) IsVisible() bool
IsVisible returns whether the notification is currently visible
func (*Notification) PlaySound ¶
func (n *Notification) PlaySound(soundData []byte)
PlaySound plays sound data through a one-shot oto player. Sound data should be 48kHz stereo S16LE format.
func (*Notification) SetBadge ¶
func (n *Notification) SetBadge(badge *ebiten.Image)
SetBadge updates the badge image for the current notification (thread-safe)
func (*Notification) Show ¶
func (n *Notification) Show(message string, duration time.Duration)
Show displays a notification message
func (*Notification) ShowAchievementWithBadge ¶
func (n *Notification) ShowAchievementWithBadge(title, description string, badge *ebiten.Image)
ShowAchievementWithBadge displays a prominent achievement notification with a badge image
func (*Notification) ShowDefault ¶
func (n *Notification) ShowDefault(message string)
ShowDefault displays a notification with default 3 second duration
func (*Notification) ShowShort ¶
func (n *Notification) ShowShort(message string)
ShowShort displays a notification with 1 second duration (for gameplay)
type NotificationType ¶
type NotificationType int
NotificationType determines the visual style of the notification
const ( NotificationTypeDefault NotificationType = iota // Small, bottom-right NotificationTypeAchievement // Large, top-center, prominent )
type PadInfo ¶ added in v0.5.0
PadInfo identifies a connected gamepad for player assignment.
func SnapshotPads ¶ added in v0.5.0
func SnapshotPads() []PadInfo
SnapshotPads returns the currently connected gamepads in ID order.
type PauseMenu ¶
type PauseMenu struct {
// contains filtered or unexported fields
}
PauseMenu handles the in-game pause menu
func NewPauseMenu ¶
func NewPauseMenu(onResume, onLibrary, onExit func()) *PauseMenu
NewPauseMenu creates a new pause menu
func (*PauseMenu) Update ¶
func (m *PauseMenu) Update(nav UINavigation)
Update handles input for the pause menu. Navigation (keyboard arrows, gamepad D-pad, and left analog stick) and the activate/back/start actions are supplied by the shared InputManager via nav, keeping behavior identical to the rest of the UI. Mouse and keyboard Enter/Space are handled directly.
type PauseMenuOption ¶
type PauseMenuOption int
PauseMenuOption represents a menu option
const ( PauseMenuResume PauseMenuOption = iota PauseMenuLibrary PauseMenuExit PauseMenuOptionCount )
type PlayTimeTracker ¶
type PlayTimeTracker struct {
// contains filtered or unexported fields
}
PlayTimeTracker tracks play time during gameplay
type PlayerAssignment ¶ added in v0.5.0
type PlayerAssignment struct {
// contains filtered or unexported fields
}
PlayerAssignment tracks which connected gamepad is bound to each player slot. Pads are matched to players by the controller model key (SDL ID + name) of the player's assigned profile. Identity is model-level only, so with two identical controllers connection order decides which unit fills which slot.
func NewPlayerAssignment ¶ added in v0.5.0
func NewPlayerAssignment(players int) *PlayerAssignment
NewPlayerAssignment creates an assignment tracker for the given number of player slots, clamped to [1, maxPlayers].
func (*PlayerAssignment) PadFor ¶ added in v0.5.0
func (pa *PlayerAssignment) PadFor(player int) (ebiten.GamepadID, bool)
PadFor returns the gamepad bound to the player slot, if any.
func (*PlayerAssignment) Update ¶ added in v0.5.0
func (pa *PlayerAssignment) Update(pads []PadInfo, input *storage.InputConfig) []AssignEvent
Update reconciles player bindings with the currently connected pads and the player profile assignments in input. pads must be in ebiten gamepad ID order so startup binding follows enumeration order and later binds follow connection order. Returns bind/unbind events for notifications.
type RewindBuffer ¶
type RewindBuffer struct {
// contains filtered or unexported fields
}
RewindBuffer stores serialized emulator states in a ring buffer for rewinding gameplay. States are captured every frameStep frames and can be popped in reverse order (LIFO) to step backwards.
func NewRewindBuffer ¶
func NewRewindBuffer(bufferSizeMB, frameStep, stateSize int) *RewindBuffer
NewRewindBuffer allocates a ring buffer sized to fit bufferSizeMB worth of serialized states, each stateSize bytes.
func (*RewindBuffer) Capacity ¶
func (rb *RewindBuffer) Capacity() int
Capacity returns the maximum number of entries the buffer can hold.
func (*RewindBuffer) Capture ¶
func (rb *RewindBuffer) Capture(saveStater coreif.SaveStater) error
Capture serializes the emulator state and stores it in the ring buffer. Only captures every frameStep frames. Should be called after RunFrame.
func (*RewindBuffer) Count ¶
func (rb *RewindBuffer) Count() int
Count returns the number of valid entries in the buffer.
func (*RewindBuffer) IsRewinding ¶
func (rb *RewindBuffer) IsRewinding() bool
IsRewinding returns whether the buffer is currently in rewind mode.
func (*RewindBuffer) Reset ¶
func (rb *RewindBuffer) Reset()
Reset clears the buffer. Call on game launch or save state load.
func (*RewindBuffer) Rewind ¶
func (rb *RewindBuffer) Rewind(emu coreif.Emulator, saveStater coreif.SaveStater, count int) bool
Rewind pops count states from the buffer and deserializes the last one. After deserializing, RunFrame is called to regenerate the framebuffer since the serialized state doesn't include rendered pixels. Returns false if the buffer is empty.
func (*RewindBuffer) SetRewinding ¶
func (rb *RewindBuffer) SetRewinding(v bool)
SetRewinding sets the rewind mode flag.
type SaveStateManager ¶
type SaveStateManager struct {
// contains filtered or unexported fields
}
SaveStateManager handles save state operations
func NewSaveStateManager ¶
func NewSaveStateManager(notification *Notification) *SaveStateManager
NewSaveStateManager creates a new save state manager
func (*SaveStateManager) GetCurrentSlot ¶
func (m *SaveStateManager) GetCurrentSlot() int
GetCurrentSlot returns the current save slot
func (*SaveStateManager) HasResumeState ¶
func (m *SaveStateManager) HasResumeState() bool
HasResumeState checks if a resume state exists
func (*SaveStateManager) Load ¶
func (m *SaveStateManager) Load(saveStater coreif.SaveStater) error
Load loads the state from the current slot
func (*SaveStateManager) LoadResume ¶
func (m *SaveStateManager) LoadResume(saveStater coreif.SaveStater) error
LoadResume loads the resume state
func (*SaveStateManager) LoadSRAM ¶
func (m *SaveStateManager) LoadSRAM(batterySaver coreif.BatterySaver) error
LoadSRAM loads the cartridge SRAM
func (*SaveStateManager) NextSlot ¶
func (m *SaveStateManager) NextSlot()
NextSlot cycles to the next save slot
func (*SaveStateManager) PreviousSlot ¶
func (m *SaveStateManager) PreviousSlot()
PreviousSlot cycles to the previous save slot
func (*SaveStateManager) Save ¶
func (m *SaveStateManager) Save(saveStater coreif.SaveStater) error
Save saves the current state to the current slot
func (*SaveStateManager) SaveResume ¶
func (m *SaveStateManager) SaveResume(saveStater coreif.SaveStater) error
SaveResume saves the resume state
func (*SaveStateManager) SaveResumeData ¶
func (m *SaveStateManager) SaveResumeData(state []byte) error
SaveResumeData saves pre-serialized state data as the resume state. Used by the auto-save system where the emu goroutine caches serialized state.
func (*SaveStateManager) SaveSRAM ¶
func (m *SaveStateManager) SaveSRAM(batterySaver coreif.BatterySaver) error
SaveSRAM saves the cartridge SRAM
func (*SaveStateManager) SetGame ¶
func (m *SaveStateManager) SetGame(gameCRC string)
SetGame sets the current game for save states Restores the last-used slot from the game's settings
func (*SaveStateManager) SetLibrary ¶
func (m *SaveStateManager) SetLibrary(library *storage.Library)
SetLibrary sets the library reference for slot persistence
type ScanManager ¶
type ScanManager struct {
// contains filtered or unexported fields
}
ScanManager handles ROM scanning orchestration. This includes creating and running scanners, tracking progress, and merging results into the library.
func NewScanManager ¶
func NewScanManager( library *storage.Library, scanScreen *screens.ScanProgressScreen, extensions []string, md *metadata.MetadataManager, defaultConsoleID int, disc bool, discID coreif.DiscIdentifier, onProgress func(), onComplete func(msg string), ) *ScanManager
NewScanManager creates a new scan manager
func (*ScanManager) IsScanning ¶
func (sm *ScanManager) IsScanning() bool
IsScanning returns true if a scan is in progress
func (*ScanManager) SetLibrary ¶
func (sm *ScanManager) SetLibrary(library *storage.Library)
SetLibrary updates the library reference
func (*ScanManager) SetScanScreen ¶
func (sm *ScanManager) SetScanScreen(screen *screens.ScanProgressScreen)
SetScanScreen updates the scan screen reference
func (*ScanManager) Start ¶
func (sm *ScanManager) Start(rescanAll bool)
Start begins a new scan operation
func (*ScanManager) Update ¶
func (sm *ScanManager) Update()
Update polls for scan progress and completion. Should be called each frame while scanning.
type ScreenshotManager ¶
type ScreenshotManager struct {
// contains filtered or unexported fields
}
ScreenshotManager handles taking and saving screenshots
func NewScreenshotManager ¶
func NewScreenshotManager(notification *Notification) *ScreenshotManager
NewScreenshotManager creates a new screenshot manager
func (*ScreenshotManager) TakeScreenshot ¶
func (m *ScreenshotManager) TakeScreenshot(screen *ebiten.Image, gameCRC string) error
TakeScreenshot captures and saves a screenshot Per design: silent capture with no notification
type SearchOverlay ¶
type SearchOverlay struct {
// contains filtered or unexported fields
}
SearchOverlay displays a search filter at the bottom-left of the screen
func NewSearchOverlay ¶
func NewSearchOverlay(onChanged func(text string)) *SearchOverlay
NewSearchOverlay creates a new search overlay with the given change callback
func (*SearchOverlay) Activate ¶
func (s *SearchOverlay) Activate()
Activate starts capturing keyboard input
func (*SearchOverlay) Clear ¶
func (s *SearchOverlay) Clear()
Clear removes all search text and deactivates
func (*SearchOverlay) Draw ¶
func (s *SearchOverlay) Draw(screen *ebiten.Image)
Draw renders the search overlay at bottom-left
func (*SearchOverlay) HandleInput ¶
func (s *SearchOverlay) HandleInput() bool
HandleInput processes keyboard input when active. Returns true if input was handled (should not propagate to navigation).
func (*SearchOverlay) IsActive ¶
func (s *SearchOverlay) IsActive() bool
IsActive returns true if the overlay is capturing keyboard input
func (*SearchOverlay) IsVisible ¶
func (s *SearchOverlay) IsVisible() bool
IsVisible returns true if the search has text (overlay should be shown)
type SharedFramebuffer ¶
type SharedFramebuffer struct {
// contains filtered or unexported fields
}
SharedFramebuffer holds pixel data written by the emulation goroutine and read by Ebiten's Draw() method. Uses separate write and read buffers so the emu goroutine can write new data while Draw uses the read copy.
func NewSharedFramebuffer ¶
func NewSharedFramebuffer(width, height int) *SharedFramebuffer
NewSharedFramebuffer creates a pre-allocated framebuffer sized for the given screen dimensions (width and height in pixels, 4 bytes per pixel).
func (*SharedFramebuffer) Read ¶
func (sf *SharedFramebuffer) Read() (pixels []byte, stride, activeHeight int, par float64)
Read returns a snapshot of the current framebuffer state. Copies the write buffer into the read buffer under the lock, then returns the read buffer which is safe to use without holding the lock.
type SharedInput ¶
type SharedInput struct {
// contains filtered or unexported fields
}
SharedInput holds controller state as button bitmasks written by the Ebiten thread and read by the emulation goroutine.
func (*SharedInput) Read ¶
func (si *SharedInput) Read() [maxPlayers]uint32
Read returns the current button bitmasks for all players.
func (*SharedInput) Set ¶
func (si *SharedInput) Set(player int, buttons uint32)
Set updates button bitmask for a player from the Ebiten thread.
type TurboState ¶
type TurboState struct {
// contains filtered or unexported fields
}
TurboState holds fast-forward state shared between the Ebiten thread (which sets it from key input) and the emulation goroutine (which reads it).
func (*TurboState) CycleMultiplier ¶
func (ts *TurboState) CycleMultiplier() int
CycleMultiplier advances through Off(1) → 2x → 3x → Off(1), returning the new value. Called from the Ebiten thread.
func (*TurboState) Read ¶
func (ts *TurboState) Read() int
Read returns the current multiplier. Called from the emulation goroutine.
type UINavigation ¶
type UINavigation struct {
}
UINavigation represents the result of UI input polling
Source Files
¶
- aboutmenu_other.go
- achievementoverlay.go
- app.go
- appicon.go
- assets.go
- audio.go
- audiobuffer.go
- directrun.go
- emuthread.go
- framepacer.go
- gameplay.go
- input.go
- inputmap.go
- inputsettings_init.go
- notification.go
- padmapping.go
- pausemenu.go
- playerassign.go
- renderer.go
- rewind.go
- rumble.go
- rumble_cht.go
- savestate.go
- scan_manager.go
- screenshot.go
- search.go
- state.go
- turbo.go
- version.go