Aleksei-bird 7c9c708c92 Первый фикс
Пачки некоторых позиций увеличены
2024-03-01 20:54:33 +03:00

210 lines
6.3 KiB
Lua

---@class FPCollection<T>
---@field datasets { [integer]: `T` }
---@field index integer
---@field count integer
---@field class "Collection"
-- 'Class' representing a list of objects/datasets with some useful methods
-- (An object only becomes a dataset once it is added to the collection)
Collection = {}
function Collection.init()
return {
datasets = {},
index = 0,
count = 0,
class = "Collection"
}
end
-- Adds given object to the end of the collection
function Collection.add(self, object)
if not object then error("Can't insert nil dataset") end
self.index = self.index + 1
object.id = self.index
self.datasets[self.index] = object
self.count = self.count + 1
object.gui_position = self.count
return object -- Returning it here feels nice
end
-- Inserts the given object at the given position, shifting other elements down
function Collection.insert_at(self, gui_position, object)
if not object then error("Can't insert nil dataset") end
if not gui_position then error("Can't insert at nil position") end
self.index = self.index + 1
object.id = self.index
self.count = self.count + 1
object.gui_position = gui_position
for _, dataset in pairs(self.datasets) do
if dataset.gui_position >= gui_position then
dataset.gui_position = dataset.gui_position + 1
end
end
self.datasets[self.index] = object
return object
end
function Collection.remove(self, dataset)
if not dataset then error("Can't remove nil dataset") end
-- Move positions of datasets after the deleted one down by one
for _, d in pairs(self.datasets) do
if d.gui_position > dataset.gui_position then
d.gui_position = d.gui_position - 1
end
end
self.count = self.count - 1
self.datasets[dataset.id] = nil
if self.count ~= table_size(self.datasets) then error("Dataset count incorrect") end
-- Returning the deleted position here to allow for GUI adjustments
return dataset.gui_position
end
-- Replaces the dataset with the new object in-place
function Collection.replace(self, dataset, object)
if not dataset then error("Can't replace nil dataset") end
if not object then error("Can't replace with nil object") end
object.id = dataset.id
object.gui_position = dataset.gui_position
self.datasets[dataset.id] = object
return object -- Returning it here feels nice
end
function Collection.get(self, object_id)
return self.datasets[object_id]
end
-- For when order doesn't matter
function Collection.get_all(self)
return self.datasets
end
-- Return format: {[gui_position] = dataset}
function Collection.get_in_order(self, reverse)
local ordered_datasets = {}
for _, dataset in pairs(self.datasets) do
local table_position = (reverse) and (self.count - dataset.gui_position + 1) or dataset.gui_position
ordered_datasets[table_position] = dataset
end
return ordered_datasets
end
-- Returns the dataset specified by the gui_position
function Collection.get_by_gui_position(self, gui_position)
if gui_position == 0 then return nil end
for _, dataset in pairs(self.datasets) do
if dataset.gui_position == gui_position then
return dataset
end
end
end
-- Returns the dataset with the given name, nil if it doesn't exist
function Collection.get_by_name(self, name)
for _, dataset in pairs(self.datasets) do
-- Check against the prototype, if it exists
local check_against = dataset.proto or dataset
if check_against.name == name then
return dataset
end
end
return nil
end
-- Returns the dataset with the given type and name, nil if it doesn't exist
function Collection.get_by_type_and_name(self, type_name, name)
for _, dataset in pairs(self.datasets) do
-- Check against the prototype, if it exists
local check_against = dataset.proto or dataset
if check_against.type == type_name and check_against.name == name then
return dataset
end
end
return nil
end
function Collection.shift(self, main_dataset, first_position, direction, spots)
if not main_dataset then error("Can't shift nil dataset") end
if not(direction == "negative" or direction == "positive") then error("Can't shift in invalid direction") end
local original_position = main_dataset.gui_position
local new_position = nil
if spots == nil then -- means shift-to-end
new_position = (direction == "positive") and self.count or first_position
else
if direction == "positive" then
new_position = math.min(original_position + spots, self.count)
else
new_position = math.max(original_position - spots, first_position)
end
end
Collection.remove(self, main_dataset)
Collection.insert_at(self, new_position, main_dataset)
end
-- Packs every dataset in this collection
function Collection.pack(self, object_class)
local packed_collection = {
objects = {},
class = self.class
}
for _, dataset in ipairs(Collection.get_in_order(self)) do
table.insert(packed_collection.objects, object_class.pack(dataset))
end
return packed_collection
end
-- Unpacks every dataset in this collection
function Collection.unpack(packed_self, parent, object_class)
local self = Collection.init()
self.class = packed_self.class
for _, object in ipairs(packed_self.objects) do -- packed objects already in array order
local dataset = Collection.add(self, object_class.unpack(object))
dataset.parent = parent
end
return self
end
-- Updates the validity of all datasets in this collection
function Collection.validate_datasets(self, object_class)
local valid = true
for _, dataset in pairs(self.datasets) do
-- Stays true until a single dataset is invalid, then stays false
valid = object_class.validate(dataset) and valid
end
return valid
end
-- Removes any invalid, unrepairable datasets from the collection
function Collection.repair_datasets(self, player, object_class)
for _, dataset in pairs(self.datasets) do
if not dataset.valid and not object_class.repair(dataset, player) then
_G[dataset.parent.class].remove(dataset.parent, dataset)
end
end
end