diff --git a/main.py b/main.py index 8ba5792..7dad349 100644 --- a/main.py +++ b/main.py @@ -1,35 +1,74 @@ """ main.py — 순수 AI 플레이 버전 -치트 없이 실제 게임 메커닉으로 플레이. -걷기/채굴/제작에 실제 시간이 걸리므로 ACTION_DELAY를 줄임. +치트 없이 실제 게임 메커니즘으로 플레이. +걷기/채굴/제작에 실제 시간이 걸리므로 ACTION_DELAY를 설정. + +핵심 변경: +- 시작 시 플레이어 접속 여부 확인 +- game.player → game.players[1] (RCON 호환) +- JSON 파싱 실패 시 재시도 (ai_planner 내부) """ import time import os import json -from factorio_rcon import FactorioRCON -from state_reader import StateReader -from context_compressor import ContextCompressor -from ai_planner import AIPlanner -from action_executor import ActionExecutor +from factorio_rcon import FactorioRCON +from state_reader import StateReader +from context_compressor import ContextCompressor +from ai_planner import AIPlanner +from action_executor import ActionExecutor RCON_HOST = os.getenv("FACTORIO_HOST", "127.0.0.1") RCON_PORT = int(os.getenv("FACTORIO_PORT", "25575")) RCON_PASSWORD = os.getenv("FACTORIO_PASSWORD", "factorio_ai") -ACTION_DELAY = 0.2 # 행동 자체에 시간이 걸리므로 간격 짧게 +ACTION_DELAY = 0.2 LOG_FILE = "agent_log.jsonl" # 건물 N개 이상이면 압축 모드로 전환 COMPRESS_THRESHOLD = 50 +def check_player(rcon: FactorioRCON) -> bool: + """서버에 접속한 플레이어가 있는지 확인하고 안내""" + print("\n[초기화] 플레이어 접속 확인 중...") + + for attempt in range(30): # 최대 30초 대기 + result = rcon.check_player() + if result: + info = rcon.lua(""" +local p = game.players[1] +if p then + rcon.print(p.name .. " @ " .. string.format("%.0f, %.0f", p.position.x, p.position.y)) +end +""") + print(f"[초기화] ✅ 플레이어 발견: {info}") + return True + + if attempt == 0: + print("[초기화] ⚠️ 접속한 플레이어가 없습니다!") + print("[초기화] 팩토리오 클라이언트로 이 서버에 접속하세요.") + print(f"[초기화] 서버 주소: {RCON_HOST}") + print(f"[초기화] 대기 중... (최대 30초)") + + time.sleep(1) + + print("[오류] 30초 내에 플레이어가 접속하지 않았습니다.") + print("[오류] 팩토리오 클라이언트로 서버에 접속한 후 다시 실행하세요.") + return False + + def run(): print("=" * 60) print(" 팩토리오 순수 AI 에이전트 (치트 없음)") print(" - 실제 걷기 / 실제 채굴 / 실제 제작 / 건설 거리 제한") + print(" - RCON 호환: game.players[1] 사용") print("=" * 60) with FactorioRCON(RCON_HOST, RCON_PORT, RCON_PASSWORD) as rcon: + # ── 플레이어 접속 확인 ── + if not check_player(rcon): + return + reader = StateReader(rcon) compressor = ContextCompressor(rcon) planner = AIPlanner() @@ -45,7 +84,7 @@ def run(): print(f"\n{'='*50}") print(f"[재계획] 총 {total_actions}개 실행 완료") - # ── 압축 레벨 자동 선택 ────────────────────── + # ── 압축 레벨 자동 선택 ── if entity_count < COMPRESS_THRESHOLD: print("[상태] 초반 모드 — 상세 상태 수집") state = reader.get_full_state() @@ -64,14 +103,14 @@ def run(): global_info = compressor._get_global_summary() entity_count = global_info.get("total_entities", entity_count) - # ── AI 계획 ────────────────────────────────── + # ── AI 계획 ── queue = planner.decide(summary) if not queue: print("[경고] AI가 행동 반환 안 함. 10초 후 재시도") time.sleep(10) continue - # ── 행동 실행 ───────────────────────────────────── + # ── 행동 실행 ── action = queue.pop(0) total_actions += 1 act = action.get("action", "")