feat: 배치 엔티티 재사용 로직 개선 및 README 업데이트
- `place_entity` 함수에서 인벤토리 아이템 유무를 확인하기 전에 기존 엔티티를 탐색하여 재사용(`REUSED`) 처리하도록 로직 개선 - 요청 좌표 주변 `±1 타일` 및 반경 `3` 타일 내에서 기존 엔티티를 찾아 재사용할 수 있도록 확장 - `stone-furnace`의 재사용 시 자동 부트스트랩 기능이 정상 작동하도록 보장 - README.md에 변경 사항 및 새로운 동작 설명 추가 - `tests/test_place_entity_reuse.py`에 대한 단위 테스트 추가
This commit is contained in:
@@ -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"배치 불가"
|
||||
|
||||
Reference in New Issue
Block a user