616 lines
22 KiB
Lua

------------------------------------------------------------------------------
---Description of the module.
---@class Model
local Model = {
---single-line comment
classname = "HMModel",
version = "0.9.35",
beacon_combo = 4,
beacon_factory = 0.5,
beacon_factory_constant = 3
}
-------------------------------------------------------------------------------
---Get models
---@param bypass boolean
---@return table
function Model.getModels(bypass)
local display_all_sheet = User.getModGlobalSetting("display_all_sheet")
local first_id = nil
local models = {}
if Model.countModel() > 0 then
for _,model in pairs(global.models) do
if Player.isAdmin() and ( display_all_sheet or model.owner == "admin" or bypass ) then
models[model.id] = model
if first_id == nil then first_id = model.id end
elseif model.owner == Player.native().name or (model.share ~= nil and model.share > 0) then
models[model.id] = model
if first_id == nil then first_id = model.id end
end
end
end
return models
end
-------------------------------------------------------------------------------
---Get models
---@param bypass boolean
---@return table
function Model.getModelsByOwner(bypass)
local models = Model.getModels(bypass)
local models_by_owner = {}
for _, model in pairs(models) do
if models_by_owner[model.owner] == nil then models_by_owner[model.owner] = {} end
table.insert(models_by_owner[model.owner], model)
end
return models_by_owner
end
-------------------------------------------------------------------------------
---Get models
---@return table
function Model.getModelsOwner()
local models = Model.getModels()
local models_owner = {}
for _, model in pairs(models) do
if model.owner == Player.native().name then
table.insert(models_owner, model)
end
end
return models_owner
end
-------------------------------------------------------------------------------
---Get block order
---@param block table
---@return table
function Model.getBlockOrder(block)
local order = {"products", "ingredients"}
if block.by_product == false then order = {"ingredients", "products"} end
return order
end
-------------------------------------------------------------------------------
---Get rules
---@return table
function Model.getRules()
if global.rules == nil then
Model.resetRules()
end
return global.rules
end
-------------------------------------------------------------------------------
---Reset rules
function Model.resetRules()
global.rules = {}
table.insert(global.rules, {index=0, mod="base", name="production-crafting", category="extraction-machine", type="entity-subgroup", value="extraction-machine", excluded = false})
table.insert(global.rules, {index=1, mod="base", name="production-crafting", category="extraction-machine", type="entity-type", value="mining-drill", excluded = false})
table.insert(global.rules, {index=2, mod="base", name="production-crafting", category="energy", type="entity-subgroup", value="energy", excluded = false})
table.insert(global.rules, {index=3, mod="base", name="production-crafting", category="technology", type="entity-type", value="lab", excluded = false})
table.insert(global.rules, {index=4, mod="base", name="module-limitation", category="extraction-machine", type="entity-type", value="mining-drill", excluded = true})
table.insert(global.rules, {index=5, mod="base", name="module-limitation", category="technology", type="entity-type", value="lab", excluded = true})
table.insert(global.rules, {index=6, mod="ShinyIcons", name="production-crafting", category="extraction-machine", type="entity-subgroup", value="shinyminer1", excluded = false})
table.insert(global.rules, {index=7, mod="ShinyIcons", name="production-crafting", category="extraction-machine", type="entity-subgroup", value="shinyminer2", excluded = false})
table.insert(global.rules, {index=8, mod="DyWorld", name="production-crafting", category="extraction-machine", type="entity-subgroup", value="dyworld-extraction-burner", excluded = false})
table.insert(global.rules, {index=9, mod="DyWorld", name="production-crafting", category="extraction-machine", type="entity-subgroup", value="dyworld-drills-electric", excluded = false})
table.insert(global.rules, {index=10, mod="DyWorld", name="production-crafting", category="extraction-machine", type="entity-subgroup", value="dyworld-drills-burner", excluded = false})
table.insert(global.rules, {index=11, mod="DyWorld", name="production-crafting", category="standard", type="entity-name", value="assembling-machine-1", excluded = true})
table.insert(global.rules, {index=12, mod="DyWorld", name="production-crafting", category="standard", type="entity-name", value="assembling-machine-2", excluded = true})
table.insert(global.rules, {index=13, mod="DyWorld", name="production-crafting", category="standard", type="entity-name", value="assembling-machine-3", excluded = true})
table.insert(global.rules, {index=14, mod="DyWorld", name="production-crafting", category="extraction-machine", type="entity-group", value="production", excluded = true})
table.insert(global.rules, {index=15, mod="Transport_Drones", name="production-crafting", category="standard", type="entity-name", value="supply-depot", excluded = true})
table.insert(global.rules, {index=16, mod="Transport_Drones", name="production-crafting", category="standard", type="entity-name", value="request-depot", excluded = true})
table.insert(global.rules, {index=17, mod="Transport_Drones", name="production-crafting", category="standard", type="entity-name", value="buffer-depot", excluded = true})
end
---Return effects on a table
---@return ModuleEffectsData
function Model.newEffects()
return { speed = 0, productivity = 0, consumption = 0, pollution = 0 }
end
-------------------------------------------------------------------------------
---Get and initialize the model
---@return table
function Model.newModel()
if global.model_id == nil then global.model_id = 1 end
if global.models == nil then global.models = {} end
local owner = Player.native().name
if owner == nil or owner == "" then owner = "admin" end
global.model_id = global.model_id + 1
local model = {}
model.id = "model_"..global.model_id
model.owner = owner
model.blocks = {}
model.ingredients = {}
model.resources = {}
model.time = 1
model.version = Model.version
model.index = table.size(global.models)
Model.appendParameters(model)
global.models[model.id] = model
return model
end
---Append parameters
---@param model ModelData
function Model.appendParameters(model)
if model ~= nil then
if model.parameters == nil then
model.parameters = {}
end
if model.parameters.effects == nil then
model.parameters.effects = Model.newEffects()
end
end
end
-------------------------------------------------------------------------------
---Get model
---@return table
function Model.getModelById(model_id)
if model_id ~= nil and global.models ~= nil then
return global.models[model_id]
end
end
-------------------------------------------------------------------------------
---Get parameter objects
---@param parameter table --{name=parameter.name, model=model.id, block=block.id, recipe=recipe.id}
---@return ModelData, BlockData, RecipeData
function Model.getParameterObjects(parameter)
if parameter ~= nil then
if global.models == nil then
---initialisation
global.models = {}
local model = Model.newModel()
User.setParameter(parameter.name, {name=parameter.name, model=model.id})
return model
end
if parameter.model ~= nil and global.models[parameter.model] ~= nil then
local model = global.models[parameter.model]
local block, recipe
if model ~= nil and parameter.block ~= nil and model.blocks ~= nil then
block = model.blocks[parameter.block]
if block ~= nil and parameter.recipe ~= nil and block.recipes ~= nil then
recipe = block.recipes[parameter.recipe]
end
end
return model, block, recipe
else
---initialisation parameter
local model = Model.getLastModel()
if model == nil then model = Model.newModel() end
User.setParameter(parameter.name, {name=parameter.name, model=model.id})
return model
end
end
end
-------------------------------------------------------------------------------
---Get last model
---@return table
function Model.getLastModel()
local last_model = nil
local models = Model.getModels()
for _,model in pairs(models) do
last_model = model
end
return last_model
end
-------------------------------------------------------------------------------
---Create model Production Block
---@param model table
---@param recipe table
---@return table
function Model.newBlock(model, recipe)
if model.block_id == nil then model.block_id = 0 end
model.block_id = model.block_id + 1
local inputModel = {}
inputModel.id = "block_"..model.block_id
inputModel.name = recipe.name
inputModel.owner = Player.native().name
inputModel.count = 1
inputModel.power = 0
inputModel.ingredients = {}
inputModel.products = {}
inputModel.recipes = {}
return inputModel
end
-------------------------------------------------------------------------------
---Create model Beacon
---@param name string
---@param count number
---@return table
function Model.newBeacon(name, count)
local beaconModel = {}
beaconModel.name = name or "beacon"
beaconModel.type = "entity"
beaconModel.count = count or 0
beaconModel.energy = 0
beaconModel.combo = User.getPreferenceSetting("beacon_affecting_one")
beaconModel.per_factory = User.getPreferenceSetting("beacon_by_factory")
beaconModel.per_factory_constant = User.getPreferenceSetting("beacon_constant")
---limit infini = 0
beaconModel.limit = 0
---modules
beaconModel.modules = {}
return beaconModel
end
-------------------------------------------------------------------------------
---Create model Factory
---@param name string
---@param count number
---@return table
function Model.newFactory(name, count)
local factoryModel = {}
factoryModel.name = name or "assembling-machine-1"
factoryModel.type = "entity"
factoryModel.count = count or 0
factoryModel.energy = 0
factoryModel.speed = 0
---limit infini = 0
factoryModel.limit = 0
---modules
factoryModel.modules = {}
return factoryModel
end
-------------------------------------------------------------------------------
---Create model Ingredient
---@param name string
---@param type string
---@param count number
---@return table
function Model.newIngredient(name, type, count)
if count == nil then count = 0 end
local ingredientModel = {}
ingredientModel.index = 1
ingredientModel.name = name
ingredientModel.type = type
ingredientModel.count = count
return ingredientModel
end
-------------------------------------------------------------------------------
---Create model Rule
---@param mod string
---@param name string
---@param category string
---@param type string
---@param value string
---@param excluded boolean
---@param index number
---@return Table
function Model.newRule(mod, name, category, type, value, excluded, index)
local rule_model = {}
rule_model.mod = mod
rule_model.name = name
rule_model.category = category
rule_model.type = type
rule_model.value = value
rule_model.excluded = excluded
rule_model.index = index
return rule_model
end
-------------------------------------------------------------------------------
---Count modules model
---@param element table
---@return number
function Model.countModulesModel(element)
local count = 0
if element ~= nil and element.modules ~= nil then
for _, value in pairs(element.modules) do
count = count + value
end
end
return count
end
-------------------------------------------------------------------------------
---Create model Recipe
---@param model table
---@param name string
---@param type string
---@return table
function Model.newRecipe(model, name, type)
if model.recipe_id == nil then model.recipe_id = 0 end
model.recipe_id = model.recipe_id + 1
local recipeModel = {}
recipeModel.id = "R"..model.recipe_id
recipeModel.index = 1
recipeModel.name = name
recipeModel.type = type or "recipe"
recipeModel.count = 0
recipeModel.production = 1
recipeModel.factory = Model.newFactory()
recipeModel.beacons = {}
table.insert(recipeModel.beacons, Model.newBeacon())
return recipeModel
end
-------------------------------------------------------------------------------
---Create model Resource
---@param model table
---@param name string
---@param type string
---@param count number
---@return table
function Model.newResource(model, name, type, count)
if model.resource_id == nil then model.resource_id = 0 end
model.resource_id = model.resource_id + 1
if count == nil then count = 1 end
local resourceModel = {}
resourceModel.id = model.resource_id
resourceModel.index = 1
resourceModel.type = type
resourceModel.name = name
resourceModel.count = count
return resourceModel
end
-------------------------------------------------------------------------------
---Count in list
---@return number
function Model.countModel()
return table.size(global.models)
end
-------------------------------------------------------------------------------
---Set the beacon
---@param recipe table
---@param name string
---@param combo number
---@param per_factory number
---@param per_factory_constant number
---@return BeaconData
function Model.addBeacon(recipe, name, combo, per_factory, per_factory_constant)
if recipe ~= nil then
local beacon_prototype = EntityPrototype(name)
if beacon_prototype:native() ~= nil then
local beacon = Model.newBeacon(name, 0)
beacon.combo = combo or User.getPreferenceSetting("beacon_affecting_one")
beacon.per_factory = per_factory or User.getPreferenceSetting("beacon_by_factory")
beacon.per_factory_constant = per_factory_constant or User.getPreferenceSetting("beacon_constant")
if recipe.beacons == nil then recipe.beacons = {} end
table.insert(recipe.beacons, beacon)
return beacon
end
end
end
-------------------------------------------------------------------------------
---Set the beacon
---@param recipe table
---@param index number
---@param name string
---@param combo number
---@param per_factory number
---@param per_factory_constant number
function Model.setBeacon(recipe, index, name, combo, per_factory, per_factory_constant)
if recipe ~= nil and recipe.beacons ~= nil then
local beacon_prototype = EntityPrototype(name)
if beacon_prototype:native() ~= nil then
local beacon = {}
local beacon = Model.newBeacon(name, 0)
beacon.combo = combo or User.getPreferenceSetting("beacon_affecting_one")
beacon.per_factory = per_factory or User.getPreferenceSetting("beacon_by_factory")
beacon.per_factory_constant = per_factory_constant or User.getPreferenceSetting("beacon_constant")
if recipe.beacons[index] ~= nil then
recipe.beacons[index] = beacon
end
end
end
end
-------------------------------------------------------------------------------
---Set a factory
---@param recipe table
---@param factory_name string
---@param factory_fuel table
function Model.setFactory(recipe, factory_name, factory_fuel)
if recipe ~= nil then
local factory_prototype = EntityPrototype(factory_name)
if factory_prototype:native() ~= nil then
recipe.factory.name = factory_name
recipe.factory.fuel = factory_fuel
if Model.countModulesModel(recipe.factory) >= factory_prototype:getModuleInventorySize() then
recipe.factory.modules = {}
end
end
end
end
-------------------------------------------------------------------------------
---Return first recipe of block
---@param recipes table
---@return table
function Model.firstRecipe(recipes)
for _, recipe in spairs(recipes,function(t,a,b) return t[b].index > t[a].index end) do
return recipe
end
end
-------------------------------------------------------------------------------
---Return last recipe of block
---@param recipes table
---@return table
function Model.lastRecipe(recipes)
for _, recipe in spairs(recipes,function(t,a,b) return t[b].index < t[a].index end) do
return recipe
end
end
-------------------------------------------------------------------------------
---Get and initialize the default
---@return table
function Model.getDefault()
local default = User.get("default")
if default.recipes == nil then default.recipes = {} end
return default
end
-------------------------------------------------------------------------------
---Get the default recipe
---@param key string --recipe name
---@return table
function Model.getDefaultRecipe(key)
local default = Model.getDefault()
if default.recipes[key] == nil then
default.recipes[key] = {
name = key,
factory = nil,
beacon = nil
}
end
return default.recipes[key]
end
-------------------------------------------------------------------------------
---Get speed of the factory
---@param key string --factory name
---@return number
function Model.getSpeedFactory(key)
local entity_prototype = EntityPrototype(key)
local crafting_speed = entity_prototype:getCraftingSpeed()
if crafting_speed ~= 0 then return crafting_speed end
local mining_speed = entity_prototype:getMiningSpeed()
if mining_speed ~= 0 then return mining_speed end
return 1
end
-------------------------------------------------------------------------------
---Get the factory of prototype
---@param recipe_prototype table
---@return string
function Model.getDefaultPrototypeFactory(recipe_prototype)
local category = recipe_prototype:getCategory()
if category ~= nil then
local factories = {}
if recipe_prototype:getType() == "boiler" then
factories = Player.getBoilersForRecipe(recipe_prototype)
elseif recipe_prototype:getType() == "fluid" then
factories = Player.getProductionsCrafting("fluid", recipe_prototype:native())
else
factories = Player.getProductionsCrafting(category, recipe_prototype:native())
end
local default_factory_level = User.getPreferenceSetting("default_factory_level")
local factory_level = 1
if default_factory_level == "fast" then
factory_level = 100
else
factory_level = tonumber(default_factory_level)
end
local level = 1
local lua_factory = nil
local last_factory = nil
for _, factory in spairs(factories, function(t,a,b) return Model.getSpeedFactory(t[b].name) > Model.getSpeedFactory(t[a].name) end) do
if level == factory_level then lua_factory = factory end
last_factory = factory
level = level + 1
end
if lua_factory ~= nil then return lua_factory.name end
if last_factory ~= nil then return last_factory.name end
end
return nil
end
-------------------------------------------------------------------------------
---Get the beacon of recipe
---@param key string --recipe name
---@return string
function Model.getDefaultRecipeBeacon(key)
local default = Model.getDefault()
if default.recipes[key] == nil then
return nil
end
return default.recipes[key].beacon
end
---Check if factory has module
---@param factory FactoryData
---@return boolean
function Model.factoryHasModule(factory)
if factory == nil then return false end
if factory.modules == nil then return false end
if factory.modules ~= nil and #factory.modules then return false end
return true
end
---Compare module priorities
---@param module_priorities1 {[uint] : ModulePriorityData}
---@param module_priorities2 {[uint] : ModulePriorityData}
function Model.compareModulePriorities(module_priorities1, module_priorities2)
if module_priorities1 == nil or module_priorities2 == nil then return false end
if #module_priorities1 ~= #module_priorities2 then return false end
for i = 1, #module_priorities1, 1 do
local module_priority1 = module_priorities1[i]
local module_priority2 = module_priorities2[i]
if module_priority1.name ~= module_priority2.name then return false end
if module_priority1.value ~= module_priority2.value then return false end
end
return true
end
---Compare 2 factories
---@param factory1 FactoryData
---@param factory2 FactoryData
---@param with_priority boolean
---@return boolean
function Model.compareFactory(factory1, factory2, with_priority)
if factory1 == nil or factory2 == nil then return false end
if factory1.name ~= factory2.name then return false end
if factory1.fuel ~= factory2.fuel then return false end
if with_priority and Model.compareModulePriorities(factory1.module_priority, factory2.module_priority) == false then return false end
return true
end
---Compare 2 factories
---@param beacon1 BeaconData
---@param beacon2 BeaconData
---@param with_priority boolean
---@return boolean
function Model.compareBeacon(beacon1, beacon2, with_priority)
if beacon1 == nil or beacon2 == nil then return false end
if beacon1.name ~= beacon2.name then return false end
if beacon1.fuel ~= beacon2.fuel then return false end
if beacon1.combo ~= beacon2.combo then return false end
if beacon1.per_factory ~= beacon2.per_factory then return false end
if beacon1.per_factory_constant ~= beacon2.per_factory_constant then return false end
if with_priority and Model.compareModulePriorities(beacon1.module_priority, beacon2.module_priority) == false then return false end
return true
end
---Compare 2 factories
---@param beacons1 {[uint] : BeaconData}
---@param beacons2 {[uint] : BeaconData}
---@return boolean
function Model.compareBeacons(beacons1, beacons2)
if beacons1 == nil or beacons2 == nil then return false end
if #beacons1 ~= #beacons2 then return false end
for i = 1, #beacons1, 1 do
local beacon1 = beacons1[i]
local beacon2 = beacons2[i]
local with_priority = Model.factoryHasModule(beacon1) or Model.factoryHasModule(beacon2)
if Model.compareBeacon(beacon1, beacon2, with_priority) == false then return false end
end
return true
end
return Model