Initial commit — Elden Ring RL agent

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Cametendo
2026-04-28 19:49:21 +02:00
commit b4a3914794
8 changed files with 461 additions and 0 deletions

78
vision_agent.py Normal file
View File

@@ -0,0 +1,78 @@
import cv2
import numpy as np
from collections import deque
import threading
import time
class EldenVision:
def __init__(self, device_index=2, stack_size=4):
self.cap = cv2.VideoCapture(device_index, cv2.CAP_V4L2)
self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
self.frame_rgb = None
self.frame_hsv = None
self.stopped = False
self.lock = threading.Lock()
# PRESERVED USER CONFIGS
self.player_hp_roi = (158, 164, 48, 329)
self.player_fp_roi = (163, 169, 49, 160)
self.player_sp_roi = (169, 176, 48, 216)
self.boss_hp_roi = (427, 437, 149, 488)
self.stack_size = stack_size
self.frame_stack = deque(maxlen=stack_size)
threading.Thread(target=self.update, args=(), daemon=True).start()
while self.frame_rgb is None: time.sleep(0.1)
def update(self):
while not self.stopped:
ret, frame = self.cap.read()
if ret and frame is not None:
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
with self.lock:
self.frame_rgb = rgb
self.frame_hsv = hsv
else:
time.sleep(0.001)
def detect_fog(self, frame_hsv=None):
"""Detects the bright white/gold glow of a fog gate in center screen."""
if frame_hsv is None:
with self.lock: frame_hsv = self.frame_hsv.copy()
# Center ROI where fog usually appears
center_crop = frame_hsv[250:450, 200:440]
# Fog is very bright (High Value) and low saturation (White)
white_mask = cv2.inRange(center_crop, np.array([0, 0, 200]), np.array([180, 50, 255]))
return np.sum(white_mask > 0) > 5000 # Threshold for 'significant' fog
def get_bar_percent(self, hsv_frame, roi, color_type='red'):
y1, y2, x1, x2 = roi
crop = hsv_frame[y1:y2, x1:x2]
if crop.size == 0: return 100.0
if color_type == 'red':
mask = cv2.inRange(crop, np.array([0, 120, 70]), np.array([10, 255, 255]))
elif color_type == 'blue':
mask = cv2.inRange(crop, np.array([100, 120, 70]), np.array([130, 255, 255]))
elif color_type == 'green':
mask = cv2.inRange(crop, np.array([40, 100, 50]), np.array([80, 255, 255]))
count = np.sum(mask > 0)
if count < 5: return 100.0 if color_type != 'boss' else 0.0
return (count / mask.size) * 100
def get_state(self):
with self.lock:
fr_rgb = self.frame_rgb.copy()
fr_hsv = self.frame_hsv.copy()
p_hp = self.get_bar_percent(fr_hsv, self.player_hp_roi, 'red')
p_fp = self.get_bar_percent(fr_hsv, self.player_fp_roi, 'blue')
p_sp = self.get_bar_percent(fr_hsv, self.player_sp_roi, 'green')
b_hp = self.get_bar_percent(fr_hsv, self.boss_hp_roi, 'red')
self.frame_stack.append(fr_rgb)
while len(self.frame_stack) < self.stack_size: self.frame_stack.append(fr_rgb)
return np.concatenate(list(self.frame_stack), axis=-1), p_hp, p_fp, p_sp, b_hp
def stop(self): self.stopped = True