Первый фикс

Пачки некоторых позиций увеличены
This commit is contained in:
2024-03-01 20:53:32 +03:00
commit 7c9c708c92
23653 changed files with 767936 additions and 0 deletions

View File

@@ -0,0 +1,184 @@
--- Tools for working with entities.
-- @module Entity.Entity
-- @usage local Entity = require('__stdlib__/stdlib/entity/entity')
local Entity = {
__class = 'Entity',
__index = require('__stdlib__/stdlib/core')
}
setmetatable(Entity, Entity)
--- Tests whether an entity has access to a given field.
-- @tparam LuaEntity entity the entity to test the access to a field
-- @tparam string field_name the field name
-- @treturn boolean true if the entity has access to the field, false if the entity threw an exception when trying to access the field
function Entity.has(entity, field_name)
assert(entity, 'missing entity argument')
assert(field_name, 'missing field name argument')
local status =
pcall(
function()
return entity[field_name]
end
)
return status
end
--- Gets the user data that is associated with an entity.
-- The user data is stored in the global object and it persists between loads.
--> The user data will be removed from an entity when the entity becomes invalid.
-- @tparam LuaEntity entity the entity to look up
-- @treturn ?|nil|Mixed the user data, or nil if no data exists for the entity
function Entity.get_data(entity)
assert(entity, 'missing entity argument')
if not global._entity_data then
return nil
end
local unit_number = entity.unit_number
if unit_number then
return global._entity_data[unit_number]
else
local entity_name = entity.name
if not global._entity_data[entity_name] then
return nil
end
local entity_category = global._entity_data[entity_name]
for _, entity_data in pairs(entity_category) do
if Entity._are_equal(entity_data.entity, entity) then
return entity_data.data
end
end
return nil
end
end
--- Associates the user data to an entity.
-- The user data will be stored in the global object and it will persist between loads.
--> The user data will be removed from an entity when the entity becomes invalid.
-- @tparam LuaEntity entity the entity with which to associate the user data
-- @tparam ?|nil|Mixed data the data to set, or nil to delete the data associated with the entity
-- @treturn ?|nil|Mixed the previous data associated with the entity, or nil if the entity had no previous data
function Entity.set_data(entity, data)
assert(entity, 'missing entity argument')
if not global._entity_data then
global._entity_data = {}
end
local unit_number = entity.unit_number
if unit_number then
local prev = global._entity_data[unit_number]
global._entity_data[unit_number] = data
return prev
else
local entity_name = entity.name
if not global._entity_data[entity_name] then
global._entity_data[entity_name] = {}
end
local entity_category = global._entity_data[entity_name]
for i = #entity_category, 1, -1 do
local entity_data = entity_category[i]
if not entity_data.entity.valid then
table.remove(entity_category, i)
end
if Entity._are_equal(entity_data.entity, entity) then
local prev = entity_data.data
if data then
entity_data.data = data
else
table.remove(entity_category, i)
end
return prev
end
end
table.insert(entity_category, { entity = entity, data = data })
end
return nil
end
--- Freezes an entity, by making it inactive, inoperable, and non-rotatable, or unfreezes by doing the reverse.
-- @tparam LuaEntity entity the entity to freeze or unfreeze
-- @tparam[opt=true] boolean mode if true, freezes the entity, if false, unfreezes the entity. If not specified, it is set to true
-- @treturn LuaEntity the entity that has been frozen or unfrozen
function Entity.set_frozen(entity, mode)
assert(entity, 'missing entity argument')
mode = mode == false and true or false
entity.active = mode
entity.operable = mode
entity.rotatable = mode
return entity
end
--- Makes an entity indestructible so that it cannot be damaged or mined neither by the player nor by their enemy factions.
-- @tparam LuaEntity entity the entity to make indestructable
-- @tparam[opt=true] boolean mode if true, makes the entity indestructible, if false, makes the entity destructable
-- @treturn LuaEntity the entity that has been made indestructable or destructable
function Entity.set_indestructible(entity, mode)
assert(entity, 'missing entity argument')
mode = mode == false and true or false
entity.minable = mode
entity.destructible = mode
return entity
end
--- Tests if two entities are equal.
-- If they don't have a reference equality and ***entity\_a*** has ***equals*** function, it will be called with ***entity\_b*** as its first argument.
-- @tparam LuaEntity entity_a
-- @tparam LuaEntity entity_b
-- @treturn boolean
function Entity._are_equal(entity_a, entity_b)
if entity_a == nil then
return entity_a == entity_b
elseif entity_a == entity_b then
return true
elseif Entity.has(entity_a, 'equals') and entity_a.equals ~= nil then
return entity_a.equals(entity_b)
else
return false
end
end
function Entity.find_resources(entity, all)
if entity.type == 'mining-drill' then
local radius = entity.prototype.mining_drill_radius
local name = (not all and (entity.mining_target and entity.mining_target.name)) or nil
return entity.surface.count_entities_filtered {
type = 'resource',
name = name,
position = entity.position,
radius = radius,
}
end
return 0
end
function Entity.is_damaged(entity)
return entity.get_health_ratio() < 1
end
Entity.damaged = Entity.is_damaged
function Entity.is_circuit_connected(entity)
local list = entity.circuit_connected_entities
return list and (next(list.red) or next(list.green))
end
function Entity.count_circuit_connections(entity)
local list = entity.circuit_connected_entities
return list and #list.red + #list.green
end
function Entity.has_fluidbox(entity)
local box = entity.fluidbox
return box and #box > 0
end
function Entity.can_deconstruct(entity)
return entity.minable and entity.prototype.selectable_in_game and not entity.has_flag('not-deconstructable')
end
return Entity

View File

@@ -0,0 +1,157 @@
--- For working with inventories.
-- @module Entity.Inventory
-- @usage local Inventory = require('__stdlib__/stdlib/entity/inventory')
local Inventory = {
__class = 'Inventory',
__index = require('__stdlib__/stdlib/core')
}
setmetatable(Inventory, Inventory)
local min = math.min
--- Given a function, apply it to each slot in the given inventory.
-- Passes the index of a slot as the second argument to the given function.
-- <p>Iteration is aborted if the applied function returns true for any element during iteration.
-- @tparam LuaInventory inventory the inventory to iterate
-- @tparam function func the function to apply to values
-- @param[opt] ... additional arguments passed to the function
-- @treturn ?|nil|LuaItemStack the slot where the iteration was aborted **OR** nil if not aborted
function Inventory.each(inventory, func, ...)
local index
for i = 1, #inventory do
if func(inventory[i], i, ...) then
index = i
break
end
end
return index and inventory[index]
end
--- Given a function, apply it to each slot in the given inventory.
-- Passes the index of a slot as the second argument to the given function.
-- <p>Iteration is aborted if the applied function returns true for any element during iteration.
-- <p>Iteration is performed from last to first in order to support dynamically sized inventories.
-- @tparam LuaInventory inventory the inventory to iterate
-- @tparam function func the function to apply to values
-- @param[opt] ... additional arguments passed to the function
-- @treturn ?|nil|LuaItemStack the slot where the iteration was aborted **OR** nil if not aborted
function Inventory.each_reverse(inventory, func, ...)
local index
for i = #inventory, 1, -1 do
if func(inventory[i], i, ...) then
index = i
break
end
end
return index and inventory[index]
end
--- Copies the contents of source inventory to destination inventory by using @{Concepts.SimpleItemStack}.
-- @tparam LuaInventory src the source inventory
-- @tparam LuaInventory dest the destination inventory
-- @tparam[opt=false] boolean clear clear the contents of the source inventory
-- @treturn {Concepts.SimpleItemStack,...} an array of left over items that could not be inserted into the destination
function Inventory.copy_as_simple_stacks(src, dest, clear)
assert(src, 'missing source inventory')
assert(dest, 'missing destination inventory')
local left_over = {}
for i = 1, #src do
local stack = src[i]
if stack and stack.valid and stack.valid_for_read then
local simple_stack = {
name = stack.name,
count = stack.count,
health = stack.health or 1,
durability = stack.durability
}
-- ammo is a special case field, accessing it on non-ammo itemstacks causes an exception
simple_stack.ammo = stack.prototype.magazine_size and stack.ammo
--Insert simple stack into inventory, add to left_over if not all were inserted.
simple_stack.count = simple_stack.count - dest.insert(simple_stack)
if simple_stack.count > 0 then
table.insert(left_over, simple_stack)
end
end
end
if clear then
src.clear()
end
return left_over
end
--- Return a blueprint stack from either stack or blueprint_book
-- @tparam LuaItemStack stack
-- @tparam[opt] bool is_bp_setup
-- @tparam[opt] bool no_book
-- @treturn LuaItemStack
function Inventory.get_blueprint(stack, is_bp_setup, no_book)
if stack and stack.valid and stack.valid_for_read then
if stack.is_blueprint then
return not is_bp_setup and stack or stack.is_blueprint_setup() and stack
elseif stack.is_blueprint_book and not no_book and stack.active_index then
local book = stack.get_inventory(defines.inventory.item_main)
if #book >= stack.active_index then
return Inventory.get_blueprint(book[stack.active_index], is_bp_setup)
end
end
end
end
--- Is the stack a blueprint with label?
-- @tparam LuaItemStack stack
-- @tparam string label
-- @treturn bool
function Inventory.is_named_bp(stack, label)
return stack and stack.valid_for_read and stack.is_blueprint and stack.label and stack.label:find('^' .. label)
end
--- Returns either the item at a position, or the filter at the position if there isn't an item there.
-- @tparam LuaInventory inventory
-- @tparam int idx
-- @tparam[opt] bool item_only
-- @tparam[opt] bool filter_only
-- @return the item or filter
function Inventory.get_item_or_filter(inventory, idx, item_only, filter_only)
local filter = not item_only and inventory.get_filter(idx)
return filter or (not filter_only and inventory[idx].valid_for_read and inventory[idx].name) or nil
end
--- Transfer items from 1 inventory to another.
-- @tparam LuaInventory source
-- @tparam LuaInventory destination
-- @tparam[opt=nil] table source_filters the filters to use if the source is not filtered/filterable
-- @treturn nil|table the filters if the destination does not support filters
function Inventory.transfer_inventory(source, destination, source_filters)
local filtered = source.is_filtered()
local destination_filterable = destination.supports_filters()
local filters = {}
for i = 1, min(#destination, #source) do
destination[i].transfer_stack(source[i])
if filtered then
if destination_filterable then
destination.set_filter(i, source.get_filter(i))
else
filters[i] = source.get_filter(i)
end
elseif source_filters then
if destination_filterable then
destination.set_filter(i, source_filters[i])
end
end
end
return (filtered and not destination_filterable and filters) or nil
end
--- Swap items from 1 inventory to another.
-- @tparam LuaInventory source
-- @tparam LuaInventory destination
function Inventory.swap_inventory(source, destination)
for i = 1, min(#destination, #source) do
destination[i].swap_stack(source[1])
end
end
return Inventory

View File

@@ -0,0 +1,204 @@
--- Resource utilities.
-- @module Entity.Resource
-- @usage local Resource = require('__stdlib__/stdlib/entity/resource')
local Resource = { __class = 'Resource',
__index = require('__stdlib__/stdlib/core') }
setmetatable(Resource, Resource)
local Is = require('__stdlib__/stdlib/utils/is')
local Surface = require('__stdlib__/stdlib/area/surface')
local Area = require('__stdlib__/stdlib/area/area')
local Tile = require('__stdlib__/stdlib/area/tile')
local Queue = require('__stdlib__/stdlib/misc/queue')
local table = require('__stdlib__/stdlib/utils/table')
--- Gets all resource entities at the specified position and surface.
-- Adapted from *YARM/resmon.lua &rarr; find\_resource\_at*
-- @tparam string|LuaSurface surface the surface to look up
-- @tparam Concepts.Position position the position to check
-- @treturn {nil|LuaEntity,...} an array of resource entities or nil if none found
function Resource.get_resources_at(surface, position)
Is.Assert(surface, 'missing surface')
Is.Assert(position, 'missing position')
local surfaces = Surface.lookup(surface)
Is.Assert(#surfaces == 1, 'invalid surface')
local tile_at_position = Tile.from_position(Tile(position))
local tile_area = Tile.to_area(tile_at_position)
local resources_at_tile = table.first(surfaces).find_entities_filtered { area = tile_area, type = 'resource' } or {}
return resources_at_tile
end
--- From the resources at the given surface and position, return all connected (horizontally, vertically and diagonally) resource entities.
-- <p>When the resource patches are found, the returned object will be an associative array where the key is the
-- resource-type string and the value is an array of entities that correspond to the resource-type.
-- <p>For now, this function gets just the ore patches, since problems arise when a single resource entity spans multiple tiles.
--> This implementation is unstable; if a resource entity reference changes during the search,
-- *both the old and the new version* of the entity might be included.
-- @tparam LuaSurface surface the surface to look up
-- @tparam Concepts.Position position the position to check
-- @return (<span class="types">{@{nil}} or {[@{string} &lt;resource-type&gt;] = {@{LuaEntity},...},...}</span>)
-- a map of resource types to resource entities or empty array if they don't exist
function Resource.get_resource_patches_at(surface, position)
Is.Assert(surface, 'missing surface')
Is.Assert(position, 'missing position')
-- get the initial resource tile if there is one at the given position
local all_resource_entities = Resource.get_resources_at(surface, position)
local all_resource_types = Resource.get_resource_types(all_resource_entities)
local resource_patches = {}
for _, type in pairs(all_resource_types) do
local resource_patch = Resource.get_resource_patch_at(surface, position, type)
resource_patches[type] = resource_patch
end
return resource_patches
end
--- From the resources at the given surface and position, return all connected (horizontally, vertically and diagonally) resource entities of specified type.
-- <p>For now, this function gets just the ore patches, since problems arise when a single resource entity spans multiple tiles.
--> This implementation is unstable; if a resource entity reference changes during the search,
-- *both the old and the new version* of the entity might be included.
-- @tparam LuaSurface surface the surface to look up
-- @tparam Concepts.Position position the position to check
-- @tparam string type the resource type (example: "iron-ore")
-- @treturn {nil|LuaEntity,...} an array containing all resources in the resource patch, or an empty array if there are no resources there
function Resource.get_resource_patch_at(surface, position, type)
Is.Assert(surface, 'missing surface')
Is.Assert(position, 'missing position')
Is.Assert(position, 'missing ore name')
local surfaces = Surface.lookup(surface)
Is.Assert(#surfaces == 1, 'invalid surface')
surface = table.first(surfaces)
-- get the initial resource tile if there is one at the given position
local all_resource_entities = Resource.get_resources_at(surface, position)
local filtered_resource_entities = Resource.filter_resources(all_resource_entities, { type })
if #filtered_resource_entities == 0 then
return {}
end
-- for the search, keep track of the relevant entities and tiles visited
-- we use the entities as keys to prevent having a single entity multiple times in the list
local resource_patch = {}
local visited_tiles = {}
-- local cache of bitwise functions, because they are called in a tight loop
local bitwise_or = bit32.bor
local bitwise_and = bit32.band
local bitwise_lshift = bit32.lshift
local initial_tile = Tile.from_position(Tile(filtered_resource_entities[1].position))
-- do a BFS starting from the initial tile
local search_queue = Queue.new()
Queue.push_last(search_queue, initial_tile)
while not Queue.is_empty(search_queue) do
local current_tile = Queue.pop_first(search_queue) --[[@as MapPosition Fix when typed]]
local current_entities = surface.find_entities_filtered { area = Tile.to_area(current_tile), type = 'resource' }
local current_tile_index = bitwise_or(bitwise_lshift(bitwise_and(current_tile.x, 0xFFFF), 16), bitwise_and(current_tile.y, 0xFFFF))
visited_tiles[current_tile_index] = true
local filtered_current_entities = Resource.filter_resources(current_entities, { type })
if #filtered_current_entities ~= 0 then
-- this tile belongs to the ore patch, add the resources
table.merge(resource_patch, table.invert(filtered_current_entities))
-- queue all tiles around this one that we did not visit yet
for _, adjacent_tile in pairs(Tile.adjacent(surface, current_tile, true)) do
local adj_tile_index = bitwise_or(bitwise_lshift(bitwise_and(adjacent_tile.x, 0xFFFF), 16), bitwise_and(adjacent_tile.y, 0xFFFF))
if not visited_tiles[adj_tile_index] then
Queue.push_last(search_queue, adjacent_tile)
visited_tiles[adj_tile_index] = true
end
end
end
end
-- map the resource entities back to an array
resource_patch = table.keys(resource_patch)
return resource_patch
end
--- Given an array of resource entities, get an array containing their names.
-- Every element within the new array is unique and is the name of a resource entity.
-- @tparam {LuaEntity,...} resources an array of resource entities
-- @treturn {nil|string,...} a new array with the names of the resources or nil if no resource entities are given
function Resource.get_resource_types(resources)
local result = {}
if resources then
local resource_names = {}
for _, resource in pairs(resources) do
resource_names[resource.name] = true
end
result = table.keys(resource_names, false, true)
end
return result
end
--- Given an array of resource entities, return the ones that have the given resource names.
-- @tparam {LuaEntity,...} resources an array of resource entities
-- @tparam {string,...} resource_names the names of the resource entities
-- @treturn {nil|LuaEntity,...} a new array containing the entities matching the given resource names or nil if no matches were found
function Resource.filter_resources(resources, resource_names)
Is.Assert(resources, 'missing resource entities list')
if not resource_names or #resource_names == 0 then
return resources
end
-- filter the resources that have the same name as one of the given names in resource_names
local result =
table.filter(
resources,
function(resource_entity)
return table.any(
resource_names,
function(name)
return resource_entity.name == name
end
)
end
)
return result
end
--- Given a resource patch, return its area.
-- @see Resource.get_resource_patch_at
-- @tparam {LuaEntity,...} resource_patch the resource patch
-- @treturn Concepts.BoundingBox the area of the resource patch
function Resource.get_resource_patch_bounds(resource_patch)
Is.Assert(resource_patch, 'missing resource patch')
local min_x = math.huge
local min_y = math.huge
local max_x = -math.huge
local max_y = -math.huge
for _, entity in pairs(resource_patch) do
local pos = entity.position
min_x = math.min(min_x, pos.x)
min_y = math.min(min_y, pos.y)
max_x = math.max(max_x, pos.x)
max_y = math.max(max_y, pos.y)
end
return Area.construct(min_x, min_y, max_x, max_y)
end
return Resource