mirror of
https://github.com/JackHopkins/factorio-learning-environment.git
synced 2025-09-06 13:23:58 +00:00
item-on-ground, grouped entities
This commit is contained in:
2
fle/env/tools/admin/request_path/server.lua
vendored
2
fle/env/tools/admin/request_path/server.lua
vendored
@@ -94,7 +94,6 @@ end
|
||||
--end)
|
||||
|
||||
script.on_event(defines.events.on_script_path_request_finished, function(event)
|
||||
game.print("Path request finished for ID: " .. event.id)
|
||||
local request_data = global.path_requests[event.id]
|
||||
if not request_data then
|
||||
game.print("No request data found for ID: " .. event.id)
|
||||
@@ -109,7 +108,6 @@ script.on_event(defines.events.on_script_path_request_finished, function(event)
|
||||
|
||||
if event.path then
|
||||
global.paths[event.id] = event.path
|
||||
game.print("Path found for request ID: " .. event.id)
|
||||
elseif event.try_again_later then
|
||||
global.paths[event.id] = "busy"
|
||||
game.print("Pathfinder busy for request ID: " .. event.id)
|
||||
|
27
fle/env/tools/agent/connect_entities/client.py
vendored
27
fle/env/tools/agent/connect_entities/client.py
vendored
@@ -109,6 +109,33 @@ class ConnectEntities(Tool):
|
||||
)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
"""Wrapper method with retry logic for specific Lua errors."""
|
||||
max_retries = 2
|
||||
retry_count = 0
|
||||
|
||||
while retry_count <= max_retries:
|
||||
try:
|
||||
return self.__call_impl__(*args, **kwargs)
|
||||
except Exception as e:
|
||||
error_message = str(e)
|
||||
# Check if the error contains the specific Lua error we want to retry on
|
||||
if "attempt to index field ? (a nil value)" in error_message:
|
||||
retry_count += 1
|
||||
if retry_count <= max_retries:
|
||||
print(
|
||||
f"ConnectEntities retry {retry_count}/{max_retries} due to Lua indexing error: {error_message}"
|
||||
)
|
||||
continue
|
||||
else:
|
||||
print(
|
||||
f"ConnectEntities failed after {max_retries} retries: {error_message}"
|
||||
)
|
||||
raise
|
||||
else:
|
||||
# For any other error, don't retry - just re-raise immediately
|
||||
raise
|
||||
|
||||
def __call_impl__(self, *args, **kwargs):
|
||||
connection_types = set()
|
||||
waypoints = []
|
||||
if "connection_type" in kwargs:
|
||||
|
@@ -543,6 +543,13 @@ def agglomerate_groupable_entities(
|
||||
if not connected_entities:
|
||||
return []
|
||||
|
||||
# Check if entities are already grouped - if so, return them as-is
|
||||
if hasattr(connected_entities[0], "__class__") and connected_entities[
|
||||
0
|
||||
].__class__.__name__ in ["BeltGroup", "PipeGroup", "ElectricityGroup", "WallGroup"]:
|
||||
# Entities are already grouped, return them directly
|
||||
return connected_entities
|
||||
|
||||
if hasattr(connected_entities[0], "prototype"):
|
||||
prototype = connected_entities[0].prototype
|
||||
|
||||
|
46
fle/env/tools/agent/get_entities/client.py
vendored
46
fle/env/tools/agent/get_entities/client.py
vendored
@@ -38,7 +38,7 @@ class GetEntities(Tool):
|
||||
|
||||
for entity in entities:
|
||||
if entity == Prototype.BeltGroup:
|
||||
# For belt groups, search for all belt types
|
||||
# For belt groups, search for all belt types and group them
|
||||
belt_types = {
|
||||
Prototype.TransportBelt,
|
||||
Prototype.FastTransportBelt,
|
||||
@@ -50,12 +50,12 @@ class GetEntities(Tool):
|
||||
expanded_entities.update(belt_types)
|
||||
group_requests.add(Prototype.BeltGroup)
|
||||
elif entity == Prototype.PipeGroup:
|
||||
# For pipe groups, search for pipe types
|
||||
# For pipe groups, search for pipe types and group them
|
||||
pipe_types = {Prototype.Pipe, Prototype.UndergroundPipe}
|
||||
expanded_entities.update(pipe_types)
|
||||
group_requests.add(Prototype.PipeGroup)
|
||||
elif entity == Prototype.ElectricityGroup:
|
||||
# For electricity groups, search for pole types
|
||||
# For electricity groups, search for pole types and group them
|
||||
pole_types = {
|
||||
Prototype.SmallElectricPole,
|
||||
Prototype.MediumElectricPole,
|
||||
@@ -117,8 +117,12 @@ class GetEntities(Tool):
|
||||
)
|
||||
continue
|
||||
|
||||
# Apply standard filtering
|
||||
if entities and matching_prototype not in entities:
|
||||
# Apply standard filtering - check against expanded entities too
|
||||
if (
|
||||
entities
|
||||
and matching_prototype not in entities
|
||||
and matching_prototype not in expanded_entities
|
||||
):
|
||||
continue
|
||||
|
||||
metaclass = matching_prototype.value[1]
|
||||
@@ -167,9 +171,6 @@ class GetEntities(Tool):
|
||||
or (
|
||||
entities and position is not None
|
||||
) # Individual entities with position filter = group for convenience
|
||||
or any(
|
||||
proto in pole_types for proto in entities
|
||||
) # Individual pole entities - always group
|
||||
)
|
||||
|
||||
if should_group:
|
||||
@@ -231,15 +232,11 @@ class GetEntities(Tool):
|
||||
filtered_entities = []
|
||||
for entity in entities_list:
|
||||
# Check entity prototype or group type
|
||||
if hasattr(entity, "prototype") and entity.prototype in entities:
|
||||
# Exclude power poles from individual handling - they should be handled as groups
|
||||
pole_types = {
|
||||
Prototype.SmallElectricPole,
|
||||
Prototype.MediumElectricPole,
|
||||
Prototype.BigElectricPole,
|
||||
}
|
||||
if entity.prototype not in pole_types:
|
||||
filtered_entities.append(entity)
|
||||
if hasattr(entity, "prototype") and (
|
||||
entity.prototype in entities
|
||||
or entity.prototype in expanded_entities
|
||||
):
|
||||
filtered_entities.append(entity)
|
||||
elif hasattr(entity, "__class__"):
|
||||
# Handle group entities
|
||||
if entity.__class__.__name__ == "ElectricityGroup":
|
||||
@@ -272,17 +269,10 @@ class GetEntities(Tool):
|
||||
):
|
||||
# Individual pipes requested with position - return group for convenience
|
||||
filtered_entities.append(entity)
|
||||
elif (
|
||||
any(pipe_type in entities for pipe_type in pipe_types)
|
||||
and position is None
|
||||
):
|
||||
# Individual pipes requested without position - extract individual pipes from group
|
||||
for pipe in entity.pipes:
|
||||
if (
|
||||
hasattr(pipe, "prototype")
|
||||
and pipe.prototype in entities
|
||||
):
|
||||
filtered_entities.append(pipe)
|
||||
elif any(pipe_type in entities for pipe_type in pipe_types):
|
||||
# Individual pipes requested - return group (restores original behavior)
|
||||
# Pipes are inherently networked, so groups are more useful than individuals
|
||||
filtered_entities.append(entity)
|
||||
elif entity.__class__.__name__ == "BeltGroup":
|
||||
belt_types = {
|
||||
Prototype.TransportBelt,
|
||||
|
1
fle/env/tools/agent/move_to/server.lua
vendored
1
fle/env/tools/agent/move_to/server.lua
vendored
@@ -25,7 +25,6 @@ end
|
||||
global.actions.move_to = function(player_index, path_handle, trailing_entity, is_trailing)
|
||||
--local player = global.agent_characters[player_index]
|
||||
local player = global.agent_characters[player_index]
|
||||
game.print("Moving to path with handle: " .. path_handle)
|
||||
local path = global.paths[path_handle]
|
||||
local surface = player.surface
|
||||
|
||||
|
@@ -382,6 +382,21 @@ global.actions.place_entity_next_to = function(player_index, entity, ref_x, ref_
|
||||
local is_belt = is_transport_belt(entity)
|
||||
|
||||
local new_position = calculate_position(direction, ref_position, ref_entity, gap, is_belt, entity)
|
||||
|
||||
-- Helper function to clear item-on-ground entities at a position
|
||||
local function clear_items_on_ground(position, radius)
|
||||
local items = player.surface.find_entities_filtered{
|
||||
position = position,
|
||||
radius = radius or 0.5,
|
||||
name = "item-on-ground"
|
||||
}
|
||||
for _, item in ipairs(items) do
|
||||
item.destroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- Clear any item-on-ground entities at the target position before collision check
|
||||
clear_items_on_ground(new_position)
|
||||
|
||||
local function player_collision(player, target_area)
|
||||
local character_box = {
|
||||
@@ -435,6 +450,9 @@ global.actions.place_entity_next_to = function(player_index, entity, ref_x, ref_
|
||||
alt_pos.x = math.ceil(alt_pos.x * 2) / 2
|
||||
alt_pos.y = math.ceil(alt_pos.y * 2) / 2
|
||||
|
||||
-- Clear items at alternative position before checking if it's clear
|
||||
clear_items_on_ground(alt_pos)
|
||||
|
||||
-- Check if this position is clear
|
||||
local alt_nearby_entities = player.surface.find_entities_filtered({
|
||||
position = alt_pos,
|
||||
@@ -556,10 +574,9 @@ global.actions.place_entity_next_to = function(player_index, entity, ref_x, ref_
|
||||
player.teleport(new_player_position)
|
||||
end
|
||||
|
||||
-- First clean up any items-on-ground at the target position
|
||||
local area = {{new_position.x - entity_width / 2, new_position.y - entity_height / 2}, {new_position.x + entity_width / 2, new_position.y + entity_height / 2}}
|
||||
|
||||
-- Show bounding box
|
||||
-- Show bounding box for debugging
|
||||
rendering.draw_rectangle({
|
||||
only_in_alt_mode=true,
|
||||
color = {r = 0, g = 1, b = 0},
|
||||
@@ -588,15 +605,6 @@ global.actions.place_entity_next_to = function(player_index, entity, ref_x, ref_
|
||||
time_to_live = 60000
|
||||
})
|
||||
|
||||
|
||||
local items = player.surface.find_entities_filtered{
|
||||
area = area,
|
||||
name = "item-on-ground"
|
||||
}
|
||||
for _, item in ipairs(items) do
|
||||
item.destroy()
|
||||
end
|
||||
|
||||
global.utils.avoid_entity(player_index, entity, new_position, direction)
|
||||
|
||||
local can_build = player.surface.can_place_entity({
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"env_id": "steel_plate_throughput",
|
||||
"model": "claude-4-opus-20250514"
|
||||
"model": "claude-sonnet-4-20250514"
|
||||
}
|
||||
]
|
Reference in New Issue
Block a user