Fix prototype: calibrate vision for real D2R screenshots, implement orb detection, improve dashboard
- Created debug tool (cmd/debug/main.go) to analyze real D2R screenshots and calibrate HSV ranges - Fixed HSV color ranges for health/mana orbs based on real screenshot analysis (99.5% and 82% detection rates) - Replaced ReadBarPercentage with ReadOrbPercentage for circular orbs (not horizontal bars) - Added SetSource() method to capture Manager for hot-swapping capture sources - Fixed dashboard JavaScript null reference errors with proper array checks - Improved dashboard refresh rate from 100ms to 1000ms for better performance - Added proper error handling for empty/null API responses - Successfully detecting game state, health (99.5%), and mana (82%) from real D2R screenshot
This commit is contained in:
parent
4ebed5e3ab
commit
4f0b84ec31
10 changed files with 473 additions and 19 deletions
|
|
@ -252,9 +252,12 @@ func (s *Server) handleCaptureUpload(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO: Auto-switch capture source to uploaded file
|
||||
// For now, just inform user they need to restart with the new file
|
||||
response := map[string]string{
|
||||
"filename": filename,
|
||||
"message": "File uploaded successfully. Use /api/capture/source to switch to it.",
|
||||
"message": fmt.Sprintf("File uploaded to %s. Restart with --capture-file to use it.", filename),
|
||||
"autoSwitch": "false", // Feature not implemented yet
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
|
@ -277,10 +280,13 @@ func (s *Server) handleCaptureSource(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO: Switch capture source
|
||||
// This would require restarting the engine with a new source
|
||||
// Import capture backends to create new source
|
||||
// We'll need to import the backends package here
|
||||
log.Printf("Switching capture source to type=%s config=%+v", req.Type, req.Config)
|
||||
|
||||
response := map[string]string{
|
||||
"message": "Capture source switching not implemented yet",
|
||||
"message": fmt.Sprintf("Source switch requested: %s", req.Type),
|
||||
"status": "partial", // Implementation incomplete
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
|
|
|||
|
|
@ -107,3 +107,23 @@ func (m *Manager) Source() Source {
|
|||
func (m *Manager) Size() (width, height int) {
|
||||
return m.source.Size()
|
||||
}
|
||||
|
||||
// SetSource swaps the capture source.
|
||||
// This is useful for development when uploading new screenshots.
|
||||
func (m *Manager) SetSource(newSource Source) error {
|
||||
// Close the old source
|
||||
if m.source != nil {
|
||||
if err := m.source.Close(); err != nil {
|
||||
// Log but don't fail - we still want to switch sources
|
||||
// log.Printf("Warning: failed to close old capture source: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Switch to new source
|
||||
m.source = newSource
|
||||
|
||||
// Reset stats for the new source
|
||||
m.stats = Stats{}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,6 +201,14 @@ func (e *Engine) LootEngine() *loot.RuleEngine {
|
|||
return e.lootEngine
|
||||
}
|
||||
|
||||
// SetCaptureSource swaps the capture source (for development/testing).
|
||||
func (e *Engine) SetCaptureSource(newSource capture.Source) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
return e.captureManager.SetSource(newSource)
|
||||
}
|
||||
|
||||
// processFrame captures and analyzes a single frame.
|
||||
func (e *Engine) processFrame() error {
|
||||
// Capture frame
|
||||
|
|
|
|||
|
|
@ -174,6 +174,38 @@ func (p *Pipeline) ReadBarPercentage(frame image.Image, barRegion image.Rectangl
|
|||
return float64(filledPixels) / float64(totalPixels)
|
||||
}
|
||||
|
||||
// ReadOrbPercentage reads a circular orb's fill level by sampling the entire region.
|
||||
// This is better for D2R health/mana orbs which are circular, not horizontal bars.
|
||||
func (p *Pipeline) ReadOrbPercentage(frame image.Image, orbRegion image.Rectangle, filledColor ColorRange) float64 {
|
||||
bounds := orbRegion.Intersect(frame.Bounds())
|
||||
if bounds.Empty() {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
totalPixels := 0
|
||||
filledPixels := 0
|
||||
|
||||
// Sample every pixel in the orb region
|
||||
// For performance, we could sample every 2-3 pixels instead
|
||||
step := 2 // Sample every 2nd pixel for performance
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y += step {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x += step {
|
||||
c := frame.At(x, y)
|
||||
hsv := RGBToHSV(c)
|
||||
totalPixels++
|
||||
if p.colorInRange(hsv, filledColor) {
|
||||
filledPixels++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if totalPixels == 0 {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
return float64(filledPixels) / float64(totalPixels)
|
||||
}
|
||||
|
||||
// GetPixelColor returns the color at a specific pixel.
|
||||
func (p *Pipeline) GetPixelColor(frame image.Image, x, y int) color.Color {
|
||||
return frame.At(x, y)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue