feat: 인벤토리 캐시 및 JSON 인코더 추가

- 인벤토리 캐시 기능을 추가하여, RCON으로 인벤토리를 읽지 못할 경우 이전에 성공적으로 읽은 데이터를 활용
- Lua에서 JSON 인코딩을 위한 간단한 함수 추가, 일부 Factorio 버전에서 `game.table_to_json`이 없을 경우 대체
- `README.md`에 인벤토리 캐시 및 JSON 인코더 사용에 대한 설명 추가
- `scan_resources()`와 `mine_resource`의 반경을 확장하여 자원 탐색 실패를 줄임
This commit is contained in:
21in7
2026-03-25 23:03:08 +09:00
parent e98d08bb44
commit 8c90e80582
14 changed files with 573 additions and 123 deletions

View File

@@ -109,9 +109,9 @@ if ok then rcon.print(data) else rcon.print("ERROR") end
last_pos = pos_str
if stuck_count >= 3:
self.rcon.lua(P + "p.walking_state = {walking = false, direction = defines.direction.north}")
return False, f"장애물에 막힘 ({pos_str}) 다른 방향 시도"
return False, f"장애물에 막힘 ({pos_str}) - 다른 방향 시도"
self.rcon.lua(P + "p.walking_state = {walking = false, direction = defines.direction.north}")
return False, f"{direction} 방향 자원 미발견 다른 방향 시도"
return False, f"{direction} 방향 자원 미발견 - 다른 방향 시도"
# ── 이동 ─────────────────────────────────────────────────────────
def move(self, x: int, y: int) -> tuple[bool, str]:
@@ -175,7 +175,7 @@ rcon.print("WALK:" .. string.format("%.1f", dist))
find_result = self.rcon.lua(P + f"""
{exclude_lua}
local res = p.surface.find_entities_filtered{{position = p.position, radius = 80, name = "{ore}"}}
local res = p.surface.find_entities_filtered{{position = p.position, radius = 250, name = "{ore}"}}
if #res == 0 then rcon.print("NOT_FOUND") return end
-- 거리순 정렬
local pos = p.position
@@ -204,11 +204,11 @@ rcon.print("ALL_EXCLUDED")
if find_result == "NOT_FOUND":
if total_mined > 0:
return True, f"{ore} {total_mined}개 채굴 (주변 광석 소진)"
return False, f"반경 80 내 {ore} 없음 explore로 다른 광맥 찾기"
return False, f"반경 250 내 {ore} 없음 - explore로 다른 광맥 찾기"
if find_result == "ALL_EXCLUDED":
if total_mined > 0:
return True, f"{ore} {total_mined}개 채굴 (접근 가능 타일 모두 시도)"
return False, f"{ore} 근처 타일 {len(failed_positions)}개 모두 접근 불가 다른 위치로 이동 필요"
return False, f"{ore} 근처 타일 {len(failed_positions)}개 모두 접근 불가 - 다른 위치로 이동 필요"
try:
find_result = find_result.strip()
@@ -290,7 +290,7 @@ p.mining_state = {{mining = true, position = {{x = {mine_x}, y = {mine_y}}}}}
if not mined_this_tile:
# 이 타일에서 한 개도 못 캤음 → 접근 불가
failed_positions.add((ox, oy))
print(f" [채굴] ({ox:.0f},{oy:.0f}) 접근 불가 제외 목록 추가 (총 {len(failed_positions)}개)")
print(f" [채굴] ({ox:.0f},{oy:.0f}) 접근 불가 -> 제외 목록 추가 (총 {len(failed_positions)}개)")
else:
# 채굴 됐지만 타일 고갈
print(f" [채굴] ({ox:.0f},{oy:.0f}) 고갈/중단. 현재 {total_mined}개 채굴됨")
@@ -302,7 +302,7 @@ p.mining_state = {{mining = true, position = {{x = {mine_x}, y = {mine_y}}}}}
# 모든 라운드 후
if total_mined > 0:
return True, f"{ore} {total_mined}개 채굴 (목표 {count}개 중 일부)"
return False, f"{ore} 채굴 실패 {len(failed_positions)}개 타일 접근 불가"
return False, f"{ore} 채굴 실패 - {len(failed_positions)}개 타일 접근 불가"
# ── 제작/배치/삽입/레시피/연구/대기 ──────────────────────────────
def craft_item(self, item: str, count: int = 1) -> tuple[bool, str]:
@@ -341,7 +341,7 @@ if built then rcon.print("OK") else rcon.print("BLOCKED") end
if not result or result in ("NO_PLAYER", "NO_CHARACTER"): return False, result or "플레이어 없음"
if result == "OK": return True, f"{name} 배치 ({x},{y})"
elif result == "NO_ITEM": return False, f"인벤토리에 {name} 없음"
elif result.startswith("TOO_FAR"): return False, f"너무 멀음 move 먼저"
elif result.startswith("TOO_FAR"): return False, f"너무 멀음 - move 먼저"
elif result == "BLOCKED": return False, f"배치 불가"
return False, f"배치 실패: {result}"