Rewrite to Go: engine, plugin system, D2R plugin, API, loot filter

This commit is contained in:
Hoid 2026-02-14 09:43:39 +00:00
parent e0282a7111
commit 3b363192f2
60 changed files with 1576 additions and 3407 deletions

86
pkg/engine/state/state.go Normal file
View file

@ -0,0 +1,86 @@
// Package state provides game state machine management with event callbacks.
package state
import (
"image"
"sync"
"time"
"git.cloonar.com/openclawd/iso-bot/pkg/plugin"
)
// Transition records a state change.
type Transition struct {
From plugin.GameState
To plugin.GameState
Timestamp time.Time
}
// Manager tracks game state and fires callbacks on transitions.
type Manager struct {
mu sync.RWMutex
current plugin.GameState
previous plugin.GameState
enterTime time.Time
history []Transition
callbacks map[plugin.GameState][]func(Transition)
detector plugin.GameDetector
}
// NewManager creates a state manager with the given detector.
func NewManager(detector plugin.GameDetector) *Manager {
return &Manager{
current: plugin.StateUnknown,
enterTime: time.Now(),
callbacks: make(map[plugin.GameState][]func(Transition)),
detector: detector,
}
}
// Update analyzes the current frame and updates state.
func (m *Manager) Update(frame image.Image) plugin.GameState {
newState := m.detector.DetectState(frame)
m.mu.Lock()
defer m.mu.Unlock()
if newState != m.current {
t := Transition{
From: m.current,
To: newState,
Timestamp: time.Now(),
}
m.history = append(m.history, t)
m.previous = m.current
m.current = newState
m.enterTime = time.Now()
// Fire callbacks outside lock? For simplicity, keep in lock for now.
for _, cb := range m.callbacks[newState] {
cb(t)
}
}
return m.current
}
// Current returns the current game state.
func (m *Manager) Current() plugin.GameState {
m.mu.RLock()
defer m.mu.RUnlock()
return m.current
}
// TimeInState returns how long we've been in the current state.
func (m *Manager) TimeInState() time.Duration {
m.mu.RLock()
defer m.mu.RUnlock()
return time.Since(m.enterTime)
}
// OnState registers a callback for entering a specific state.
func (m *Manager) OnState(state plugin.GameState, cb func(Transition)) {
m.mu.Lock()
defer m.mu.Unlock()
m.callbacks[state] = append(m.callbacks[state], cb)
}