feat: 배치 엔티티 재사용 로직 개선 및 README 업데이트

- `place_entity` 함수에서 인벤토리 아이템 유무를 확인하기 전에 기존 엔티티를 탐색하여 재사용(`REUSED`) 처리하도록 로직 개선
- 요청 좌표 주변 `±1 타일` 및 반경 `3` 타일 내에서 기존 엔티티를 찾아 재사용할 수 있도록 확장
- `stone-furnace`의 재사용 시 자동 부트스트랩 기능이 정상 작동하도록 보장
- README.md에 변경 사항 및 새로운 동작 설명 추가
- `tests/test_place_entity_reuse.py`에 대한 단위 테스트 추가
This commit is contained in:
21in7
2026-03-26 00:36:05 +09:00
parent 9b3d26aa12
commit abd388fc1e
6 changed files with 145 additions and 10 deletions

View File

@@ -477,9 +477,6 @@ if crafted > 0 then rcon.print("CRAFTING:" .. crafted) else rcon.print("NO_INGRE
"east": "defines.direction.east", "west": "defines.direction.west"}
lua_dir = dir_map.get(direction, "defines.direction.north")
result = self.rcon.lua(P + f"""
local inv = p.get_main_inventory()
local have = inv.get_item_count("{name}")
if have < 1 then rcon.print("NO_ITEM") return end
local dist = math.sqrt(({x} - p.position.x)^2 + ({y} - p.position.y)^2)
if dist > p.build_distance + 2 then rcon.print("TOO_FAR:" .. string.format("%.1f", dist)) return end
@@ -492,6 +489,53 @@ local candidates = {{
{{ox+1, oy+1}}, {{ox-1, oy-1}}, {{ox+1, oy-1}}, {{ox-1, oy+1}}
}}
-- 배치 아이템이 없어도, 이미 같은 엔티티가 있으면 재사용으로 처리
for _, pos in ipairs(candidates) do
local cx, cy = pos[1], pos[2]
local existing = p.surface.find_entities_filtered{{
position = {{cx, cy}},
radius = 0.5,
name = "{name}",
}}
if existing and #existing > 0 then
rcon.print(string.format("REUSED:%.0f,%.0f", cx, cy))
return
end
end
-- 요청 좌표가 기존 엔티티와 약간 떨어져 있을 수 있으므로,
-- 더 넓은 반경 내에서도 같은 엔티티가 있으면 재사용 처리한다.
do
local nearby = p.surface.find_entities_filtered{{
position = {{ox, oy}},
radius = 3,
name = "{name}",
}}
if nearby and #nearby > 0 then
local best = nearby[1]
local best_d2 = math.huge
for _, e in ipairs(nearby) do
if e and e.valid then
local dx = e.position.x - ox
local dy = e.position.y - oy
local d2 = dx*dx + dy*dy
if d2 < best_d2 then
best = e
best_d2 = d2
end
end
end
rcon.print(string.format("REUSED:%.0f,%.0f", best.position.x, best.position.y))
return
end
end
-- 여기까지 왔는데 배치할 엔티티가 없다면,
-- 그 때서야 인벤토리에 아이템이 있는지 확인한다.
local inv = p.get_main_inventory()
local have = inv.get_item_count("{name}")
if have < 1 then rcon.print("NO_ITEM") return end
for _, pos in ipairs(candidates) do
local cx, cy = pos[1], pos[2]
local can = p.surface.can_place_entity{{name="{name}", position={{cx, cy}}, direction={lua_dir}}}
@@ -513,6 +557,9 @@ rcon.print("BLOCKED")
elif result.startswith("OK:"):
coords = result.split(":", 1)[1]
return True, f"{name} 배치 ({coords})"
elif result.startswith("REUSED:"):
coords = result.split(":", 1)[1]
return True, f"{name} 재사용 ({coords})"
elif result == "NO_ITEM": return False, f"인벤토리에 {name} 없음"
elif result.startswith("TOO_FAR"): return False, f"너무 멀음 - move 먼저"
elif result == "BLOCKED": return False, f"배치 불가"