On tick Event, need synced registration {RESOLVED}

Place to get help with not working mods / modding interface.
User avatar
Ranakastrasz
Smart Inserter
Smart Inserter
Posts: 2179
Joined: Thu Jun 12, 2014 3:05 am
Contact:

On tick Event, need synced registration {RESOLVED}

Post by Ranakastrasz »

I have a gameloop that runs each tick. However, for some reason, sometimes, it stops existing after a game is saved and loaded. I have no idea how this happened.

I tried to have it registered in the control file itself, but that caused a rolling desync loop when a second person joined.

Originally, the loop started from an on_init event. I have no idea what caused it to stop running, but that is clearly the case.
Last edited by Ranakastrasz on Sun Sep 04, 2016 5:38 pm, edited 1 time in total.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Supercheese
Filter Inserter
Filter Inserter
Posts: 841
Joined: Mon Sep 14, 2015 7:40 am
Contact:

Re: On tick Event, need synced registration

Post by Supercheese »

You can define a top-level on_tick function so it always runs, or if you only want to have it run sometimes and disable it other times, you do indeed need to include a check to register it in on_load like so: https://github.com/Suprcheese/Vehicle-W ... ua#L13-L17

I, like you, learned this the hard way after users reported nasty desyncs and crashes!
User avatar
Adil
Filter Inserter
Filter Inserter
Posts: 945
Joined: Fri Aug 15, 2014 8:36 pm
Contact:

Re: On tick Event, need synced registration

Post by Adil »

Ranakastrasz wrote: I tried to have it registered in the control file itself, but that caused a rolling desync loop when a second person joined.
That means something wrong in your handler.
The handlers are not saved, you must re-register them after each game startup.
I do mods. Modding wiki is friend, it teaches how to mod. Api docs is friend too...
I also update mods, some of them even work.
Recently I did a mod tutorial.
User avatar
Ranakastrasz
Smart Inserter
Smart Inserter
Posts: 2179
Joined: Thu Jun 12, 2014 3:05 am
Contact:

Re: On tick Event, need synced registration

Post by Ranakastrasz »

I am using a Top level one, and it desync loops.

Code: Select all

--require "defines"
require "config"
require 'libs/EvoGUI'
--require "interfaces"

--[[
    This module handles the gameloop alteration, allowing conduit modules in power armor grid to tranfer energy between your power grid and your armor.

]]--

--[[
    Figure out if you can access energy network with the get network command thinggy.
    Alternately, do aura search, steal power from accumulators and roboports. /Done
    
    Add command to disable conduit mechanics.
    -Shield pulse visial /Done, Removed to seperate mod
    -Better Energy Distribution
    -Sheld autobalance /Done
    -Boost batteries. Add higher tier,larger battery(s) /Done
    -Finish tech fixing /Done
    -Add GUI display for fuel.
    -Add custom fuel slot.
    -Method to discharge energy into network?
]]--

luadata = nil



--



function verifySettings()
	if (RanaMods.ModularArmor.config.tickRate < 0) then
		RanaMods.ModularArmor.config.tickRate = 1
		throwError("Tick rate must be >= 0.")
	end
end
script.on_event(defines.events.on_tick, ticker)

script.on_init(function()
       -- globalPrint("onLoad")
	if (global.loaded == nil) then
		global.loaded = true
       -- globalPrint("loaded")
        
		verifySettings()
	end
    refresh_equipment()
    
    --[[if (not global.surface) then
        global.surface = game.surfaces['nauvis']
    end]]--
    if (not global.modularArmor) then
        global.modularArmor = {}
    end
    if (global.ticking == nil) then
        global.ticking = 0
    end
	--if not evo_gui then
		--evo_gui = EvoGUI.new(Natural_Evolution_state)
		--evo_gui = EvoGUI.new(Expansion_State)
		
	--end	
end
)

script.on_configuration_changed(function(data)
    -- If anything changes, at all, refresh everything. 
    -- All mods altering this stuff must do so as well.

    refresh_equipment()
    --[[if data.mod_charges ~= nil then
        refresh_equipment()
    end]]--

    --[[if data.mod_changes ~= nil and data.mod_changes["Modular-Armor"] ~= nil then
        if data.mod_changes["Modular-Armor"].old_version == nil then
            -- "My Mod" was added to an existing game
            refresh_equipment()
        elseif data.mod_changes["Modular-Armor"].old_version ~= data.mod_changes["Modular-Armor"].new_version then
            refresh_equipment()

        end
    end]]--
end)

function globalPrint(msg)
  local players = game.players
  --if RanaMods.ModularArmor.config.Debug then
      for x=1, #players do
        game.players[x].print(msg)
      end
  --end
end


function tableIsEmpty(t)
	if (t) then
		for k in pairs(t) do
			return false
		end
	end
	return true
end



function registerEquipmentGroup(iGroup)

    --iGroup.mod = iMod
    if not RanaMods.ModularArmor.equipmentData then
        RanaMods.ModularArmor.equipmentData = {}

    end
    if iGroup and iGroup.name and iGroup.type then
        
        for _, v in pairs(RanaMods.ModularArmor.equipmentData) do
            if v.name == iGroup.name then
                return
            end
        end
        table.insert(RanaMods.ModularArmor.equipmentData, iGroup)
        
    else
        return "Invalid Table"
    end
end

function registerPrototype (iGroup,iPrototype,iType)
-- Ideally, this will register equipment group itself, if it doesn't yet exist.
    if not RanaMods.ModularArmor.equipmentData then
        RanaMods.ModularArmor.equipmentData = {}
    end
    if iGroup and iGroup.name and iGroup.type then
        if iPrototype and iPrototype.name and iPrototype.power then
            iPrototype.power = iPrototype.power * RanaMods.ModularArmor.config.powerCoef *RanaMods.ModularArmor.config.secondsPerTick
            for _, v in pairs(RanaMods.ModularArmor.equipmentData) do
                if v.name == iGroup.name then

                    thisTable = nil
                    --[[if iType == "equipment" then
                        if not v.equipment then
                            v.equipment = {}
                        end
                        thisTable = v.equipment
                    elseif iType == "fuel" then
                        if not v.fuel then
                            v.fuel = {}
                        end
                        thisTable = v.fuel
                    else
                        globalPrint("Invalid Type "..iType)
                        return "Invalid Type"
                    end]]--
                    if not v[iType] then
                        v[iType] = {}
                    end
                    
                    for _, data in pairs(v[iType]) do
                        if data.name == iPrototype.name then
                            -- if it already exists, overwrite it.
                            data = iPrototype
                            return
                        end
                    end
                    table.insert(v[iType], iPrototype)
                    
                    break
                end
            end
        else
            return "Invalid iPrototype"
        end
    else
        return "Invalid iGroup"
    end
end


function reset_equipment()
    RanaMods.ModularArmor.equipmentData = {}
end

function refresh_equipment()
    --[[luadata = {raw = loadstring(game.entity_prototypes["DATA_RAW"].order)()}
    reset_equipment()
    for i, equipment in pairs (luadata.raw["battery-equipment"]) do
        if equipment.rana_mod then
            if equipment.rana_mod.powerType then
                -- This will happen repeatedly, but it should work correctly even with duplicate registrations, just failing instead.
                registerEquipmentGroup({name = equipment.rana_mod.powerGroup,type = equipment.rana_mod.powerType})
                registerPrototype({name = equipment.rana_mod.powerGroup,type = equipment.rana_mod.powerType},{name = equipment.name     ,power =  equipment.rana_mod.fuelPower},"equipment")
            end
            -- might have more data attachment types later.
        end
    end
    
    for i, fuel in pairs (luadata.raw["item"]) do
        if fuel.rana_mod then

            if fuel.rana_mod.powerType then
            
                registerEquipmentGroup({name = fuel.rana_mod.powerGroup,type = fuel.rana_mod.powerType})
                registerPrototype({name = fuel.rana_mod.powerGroup,type = fuel.rana_mod.powerType},{name = fuel.name     ,power =  fuel.rana_mod.fuelPower},"fuel")
            end
        end
    end]]--
    
    
    registerEquipmentGroup({name = "conduit",type = "conduit"})
    registerEquipmentGroup({name = "burner" ,type = "fuelled"})
    registerEquipmentGroup({name = "fusion" ,type = "fuelled"})

    registerPrototype({name = "conduit",type = "conduit"},{name = "semiconductor-conduit-equipment"    ,power =  40 * 1000},"equipment")
    registerPrototype({name = "conduit",type = "conduit"},{name = "superconductor-conduit-equipment "  ,power = 720 * 1000},"equipment")
    registerPrototype({name = "burner" ,type = "fuelled"},{name = "engine-equipment"                   ,power = 100 * 1000},"equipment")
    registerPrototype({name = "fusion" ,type = "fuelled"},{name = "fusion-reactor-equipment"           ,power = 960 * 1000},"equipment")
                    
    registerPrototype({name = "burner" ,type = "fuelled"},{name = "solid-fuel"  ,power = 25     * 1000 * 1000},"fuel")
    registerPrototype({name = "burner" ,type = "fuelled"},{name = "coal"        ,power = 8.     * 1000 * 1000},"fuel")
    registerPrototype({name = "burner" ,type = "fuelled"},{name = "raw-wood"    ,power = 4.     * 1000 * 1000},"fuel")
    registerPrototype({name = "fusion" ,type = "fuelled"},{name = "alien-fuel"  ,power = 200.   * 1000 * 1000},"fuel")

end

function ticker() -- run once per tickRate number of gameticks.
    if (game.tick % RanaMods.ModularArmor.config.tickRate) == 0 then
		tick()
        
	else
	end
    --[[if (game.tick %  60) == 0 then
        refresh_equipment()
    end]]--
end



function tickDummies(id,iSurface,iPosition) -- This and kill dummies need to use a factory. I have no idea what that is. Need research

    --GlobalPrint("2")
    if not id.units then
        id.units = {}
    else
        -- Already exists.
    end
    if not id.units.accumulator then
        id.units.accumulator = iSurface.create_entity{name = "laser-turret-dummy", position = iPosition, force=game.forces.player}
        id.units.accumulator.energy = RanaMods.ModularArmor.config.accumulatorEnergyCap -- initialize energy levels
        id.previousEnergy = id.units.accumulator.energy -- and previous energy level from last tick
        id.units.accumulator.destructible = false -- Make dummy invulnerable.
    else
        id.units.accumulator.teleport(iPosition) -- Ensure that the power drain dummy is always at the player's position.
    end
    
    --[[if not id.units.pole then
        id.units.pole = global.surface.create_entity{name = "electric-pole-dummy", position = positionz, force=game.forces.player}
        id.units.pole.destructible = false
    else
        id.units.pole.teleport(positionz)
    end
    
    if not id.units.solar then
        id.units.solar = global.surface.create_entity{name = "solar-panel-dummy", position = positionz, force=game.forces.player}
        id.units.solar.destructible = false
    else
        id.units.solar.teleport(positionz)
    end]]--
end
function killDummies(id)
    --GlobalPrint("1")
    if id.units then
        if id.units.accumulator then
            id.units.accumulator.destroy()
            id.units.accumulator = nil
        else
            -- Already gone
        end
        --[[if id.units.pole then
            id.units.pole.destroy()
            id.units.pole = nil
        else
            -- Already gone
        end
        if id.units.solar then
            id.units.solar.destroy()
            id.units.solar = nil
        else
          -- Already gone
        end]]--
    else
        -- Already deleted.
    end
end

function tick()
	local shouldKeepTicking
    local thisPlayer = nil
    local players = game.players
    --globalPrint("tick")
    --shouldKeepTicking = true -- Due to lack of any alternate method of detecting player's armor state, we have to always tick.

    
    for x=1, #players do
        thisPlayer = players[x]
        if (thisPlayer.connected) then
            if (thisPlayer.character) then
                --game.getplayer(1).print(x..' '..player)
                
                --if not global.modularArmor[x] then
                --    global.modularArmor[x] = {}
                --end
                local modularArmor = global.modularArmor[x]
                
                if (not modularArmor) then
                    
                    modularArmor = {} -- ensure player has data attached
                    --modularArmor.storedFuel = {["steam"] = 0, ["fusion"] = 0}
                    global.modularArmor[x] = modularArmor
                    
                    --[[if (RanaMods.ModularArmor.config.Debug == true) then
                
                        game.always_day=true -- test mode stuff
                        thisPlayer.insert{name="basic-grenade",count=50}
                        thisPlayer.insert{name="energy-shield-basic-equipment",count=20}
                        thisPlayer.insert{name="energy-shield-equipment",count=20}
                        thisPlayer.insert{name="energy-shield-mk2-equipment",count=10}
                        --thisPlayer.insert{name="energy-shield-module-equipment",count=10}
                        --thisPlayer.insert{name="energy-shield-core-equipment",count=5}
                        
                        thisPlayer.insert{name="power-conduit-equipment",count=40}
                        thisPlayer.insert{name="engine-equipment",count=10}
                        thisPlayer.insert{name="fusion-reactor-equipment",count=10}
                        --thisPlayer.insert{name="power-conduit-core-equipment",count=5}
                        
                        thisPlayer.insert{name="coal",count=50}
                        thisPlayer.insert{name="solid-fuel",count=50}
                        thisPlayer.insert{name="alien-fuel",count=50}

                        --thisPlayer.insert{name="solar-panel-equipment-node",count=20}
                        thisPlayer.insert{name="solar-panel-equipment",count=20}
                        thisPlayer.insert{name="solar-panel-equipment-mk2",count=10}
                        thisPlayer.insert{name="basic-actuator-equipment",count=20}
                        thisPlayer.insert{name="basic-exoskeleton-equipment",count=20}

                        thisPlayer.insert{name="battery-equipment",count=5}
                        thisPlayer.insert{name="battery-mk2-equipment",count=5}
                        thisPlayer.insert{name="battery-mk3-equipment",count=5}
                        thisPlayer.insert{name="battery-mk4-equipment",count=5}
                        thisPlayer.insert{name="power-armor-mk2",count=1}
                        thisPlayer.insert{name="power-armor",count=1}
                        thisPlayer.insert{name="basic-modular-armor",count=1}
                        
                        
                        thisPlayer.insert{name="basic-laser-defense-equipment",count=5}
                        thisPlayer.insert{name="basic-electric-discharge-defense-equipment",count=5}
                        thisPlayer.insert{name="basic-electric-discharge-defense-remote",count=1}
                        
                        
                        thisPlayer.insert{name="small-electric-pole",count=50}
                        thisPlayer.insert{name="solar-panel",count=50}
                        thisPlayer.insert{name="basic-accumulator",count=50}
                        thisPlayer.insert{name="basic-mining-drill",count=50}
                    end]]--
                    
                end
                if (not modularArmor.storedFuel) then
                    modularArmor.storedFuel = {}
                end
                for x,equipmentData in ipairs(RanaMods.ModularArmor.equipmentData) do
                    if equipmentData.type == "fuelled" then
                        if not modularArmor.storedFuel[x] then
                            modularArmor.storedFuel[x] = 1
                        end
                    end
                end
                
                --[[if (not modularArmor.shieldData) then
                    modularArmor.shieldData = {}
                    modularArmor.shieldData.previousShield = 0
                    modularArmor.shieldData.lastDamage = 0
                    --modularArmor.shieldData.direction = 0
                    --modularArmor.shieldData.lastSFX = 0
                end]]--
                
                -- Removed till I can figure out how to fix the entity.
                --[[if modularArmor.units and modularArmor.units.name == "modular-accumulator-dummy" then
                    modularArmor.units.destroy()
                end
                if modularArmor.units == nil then
                    modularArmor.units = {}
                end]]--
                -- Ensure dummies exist.
                --[[]]--
                
                local armor = thisPlayer.get_inventory(defines.inventory.player_armor)[1] -- Check for armour presence.
                
                -- /c ((game.players[1].get_inventory(defines.inventory.player_armor)[1]).grid).put{equipment = "battery-equipment"}
                -- /c ((game.players[1].get_inventory(defines.inventory.player_armor)[1]).grid).put{equipment = game.players[1].insert{name = "battery-equipment",count=1}}
                
                if (armor.valid_for_read) then
                    
                    if (armor.has_grid) then -- Check for grid existence.
                        local grid = armor.grid
                        
                        tickDummies(modularArmor,thisPlayer.character.surface,thisPlayer.character.position)-- validate, create, and move dummy units.
                        
                        
                        
                        local transferRate = 0 -- Rate of transfer from external network to armor.
                    
                        --transferRate = transferRate + ArmorTransferRatePerGridSize*grid.width*grid.height
                        
                        local fuelRates = {}
                    
                        local energy = 0 -- Total energy and energy capacity
                        local energyCap = 0 -- need smallest fraction count as well. Essentially, if any of them have less than 50% or 90%, activate fusion and steam respectively.
                        --local hasBattery = false -- Due to lack of a good energy distrubution system, I only limit production so long as you have a battery. Otherwise, things near the end of the list don't get any energy.
                        -- Disabled, since power distribution percentages of 98 and 99% don't really have problems anymore. You would need 50 mini-shields, which wont happen
                        local shieldHealth = 0 -- Total shield and shield capacity for auto-balancing.
                        local shieldCap = 0
                        for x,equipment in ipairs(grid.equipment) do -- Loop through all equipment.
                            if (equipment.max_energy ~= 0) then
                                energy = energy + equipment.energy -- If it has energy, add values to total value.
                                energyCap = energyCap + equipment.max_energy
                                --if equipment.type == "battery-equipment" then
                                --    hasBattery = true
                                --else
                                
                                --end
                            else
                            
                            end
                            
                            if equipment.max_shield ~= 0 then
                                shieldHealth = shieldHealth + equipment.shield -- Same with shield.
                                shieldCap = shieldCap + equipment.max_shield
                            else
                            end
                            
                            for x,equipmentData in ipairs(RanaMods.ModularArmor.equipmentData) do -- Count all scripted equipment
                                    --globalPrint(x)
                                for y,equipmentType in ipairs (equipmentData.equipment) do
                                    --globalPrint(y)
                                    --globalPrint(equipmentType.name)
                                    if (equipment.name == equipmentType.name) then
                                    --globalPrint(equipment.name.." ? "..fuelType)
                                         if equipmentData.type == "fuelled" then -- Get total production rate for each type.

                                            if not fuelRates[x] then
                                                fuelRates[x] = equipmentType.power
                                            else
                                                fuelRates[x] = fuelRates[x] + equipmentType.power
                                            end
                                        elseif equipmentData.type == "conduit" then -- And network transfer rate.
                                            transferRate = transferRate + equipmentType.power
                                        end
                                    else
                                        
                                    end
                                end
                            end
                            
                                
                            --[[if (equipment.name == "power-conduit-equipment") then -- Also count each conduit module.
                                transferRate = transferRate + data.ConduitTransferRatePerEquipment
                            end]]--
                        end
                        
                        
                        
                        local shieldFraction = shieldHealth/shieldCap
                        
                        --[[if shieldCap > 0 then
                            
                            if shieldHealth < modularArmor.shieldData.previousShield then
                                -- Took damage last tick.
                                modularArmor.shieldData.lastDamage = 0
                            else
                                -- Not taking damage this tick. Might have taken damage previously however.
                                
                            end
                            if modularArmor.shieldData.lastDamage < 120 then
                                transferRate = 0
                            else
                            end
                            
                            modularArmor.shieldData.previousShield = shieldHealth
                            modularArmor.shieldData.lastDamage = modularArmor.shieldData.lastDamage+1
                        else
                            
                        end]]--
                        
                        local energyWanted = energyCap-energy
                        
                        local transferRate = math.min(transferRate,energyWanted) -- We cant transfer energy without space to put it into
                        
                        
                        --local accumulatorEnergy = 0*conversionAntiRatio -- Temporarily removed.
                        local accumulatorEnergy = (modularArmor.units.accumulator.energy - modularArmor.previousEnergy)--*conversionAntiRatio -- How much energy was accumulated since last tick
                        --globalPrint("Accumulator "..accumulatorEnergy)
                        local energyToAdd = math.min(transferRate,accumulatorEnergy) -- Accumulated energy, or transfer wanted, whichever is lower.
                        local newEnergy = energy+energyToAdd
                        local storageRatio = newEnergy/energyCap
                        
                        accumulatorEnergy = accumulatorEnergy - energyToAdd -- Remove 
                        -- SFX
                        -- if energyToAdd >= 10000 and game.tick%60 == 0 then
                        --    global.surface.create_entity{name = "conduit-sparks", position = thisPlayer.character.position, force=game.forces.neutral}
                        --end
                        --globalPrint("Accumulator -- "..accumulatorEnergy)
                        --global.surface.create_entity{name = "smoke-fast", position = thisPlayer.character.position, force=game.forces.neutral} 
                        
                        for x,equipment in ipairs(RanaMods.ModularArmor.equipmentData) do
                            if equipment.type == "fuelled" then
                                
                               --globalPrint("detected Generator "..(fuelRates.fuelType)..(fuelType))
                                if (fuelRates[x] and (fuelRates[x] > 0.0)) then -- Make sure it exists, and that is is above zero.
                                    --globalPrint("detected Generator "..fuelRates.fuelType..fuelType)
                                    -- This type exists
                                    local threshhold = energyCap -- How much power this generator is allowed to bring you up to.
                                    -- Currently leaving it at 100% for now, till I have a better idea how I want to do this.
                                    --if hasBattery then
                                        --threshhold = threshhold * fuelVal.threshhold -- Without a battery, you cannot regulate energy production.
                                    --else
                                        
                                    --end
                                    local energyWanted = threshhold - newEnergy -- How much power we want to generate
                                    energyWanted = math.max(energyWanted,0) -- Can't request negative power
                                    energyWanted = math.min(energyWanted,fuelRates[x]) -- Can't make more power than the engines can support
                                    local energyToGenerate = 0
                                    
                                    --globalPrint("Stored "..modularArmor.storedFuel[x]..fuelType)
                                    --globalPrint("Wanted "..energyWanted)
                                    if (modularArmor.storedFuel[x] < energyWanted) then
                                        -- Check for fuel. If available, consume. If not, spend what you have
                                        local mainInventory = thisPlayer.get_inventory(defines.inventory.player_main)
                                        local validFuel = nil
                                        for y,fuel in ipairs(equipment.fuel) do
                                            if (mainInventory.get_item_count(fuel.name) > 0) then
                                                -- Got some
                                                validFuel = fuel
                                                break
                                            else
                                                -- No luck, skip it
                                            end
                                            --globalPrint(fuel[x][1].." "..mainInventory.get_item_count(fuel[x][1]))
                                        end
                                        if (validFuel) then
                                            mainInventory.remove{name = validFuel.name, count = 1}
                                            modularArmor.storedFuel[x] = modularArmor.storedFuel[x] + validFuel.power
                                            --surface.create_entity{name="flying-text", position=thisPlayer.character.position, text=("-1 "..validFuel[1]), color={r=1,g=1,b=1}}
                                            --globalPrint(validFuel[1].." "..modularArmor.storedFuel[x])
                                        else
                                            if RanaMods.ModularArmor.config.LowFuelMessage then
                                                if (game.tick%RanaMods.ModularArmor.config.ticksPerSecond == 0) then
                                                    thisPlayer.character.surface.create_entity{name="flying-text", position=thisPlayer.character.position, text=("No "..(equipment.name).." fuel"), color={r=1,g=0.25,b=0.25}}
                                                -- Needs a better feedback method.
                                                else
                                                  
                                                end
                                            end

                                            -- Out of fuel
                                            --globalPrint("No fuel")
                                        end
                                        
                                        
                                    else
                                        -- Have enough fuel already.
                                    end
                                    energyToGenerate = math.min(modularArmor.storedFuel[x],energyWanted)
                                    
                                    modularArmor.storedFuel[x] = modularArmor.storedFuel[x] - energyToGenerate
                                    
                                    
                                        
                                    energyToAdd = energyToAdd + energyToGenerate
                                    
                                    --global.surface.pollute(thisPlayer.character.position, energyToGenerate*RanaMods.ModularArmor.config.pollutionCoef)
                                    
                                  
                                        
                                    --end
                                else
                                    -- No such generator.
                                end
                            else
                                -- Its a conduit.
                            end
                        end
                        
                        -- I have energy to add, Energy Cap, and current energy.
                        -- I want to give amount proportional to amount missing to each elements. Ones with less get a higher fraction.
                        -- The amount I have available needs to be split into fractions of amount missing overall.
                        -- For each point missing from an element, add energyFraction to it.
                        -- Calc extra as well, and if it is greater than like 10%, feed into accumulator for next tick.
                        
                        
                        --globalPrint("energyFraction"..energyFraction)
                        --globalPrint("energyToAdd"..energyToAdd)
                        
                        --globalPrint("energySpent"..energySpent)
                        --shieldHealth = 0
                        for x,equipment in ipairs(grid.equipment) do -- Basic Setup. Distribute as much to first in line, remainder to next, and next, till you run out.
                            if (equipment.max_energy ~= 0 and energyToAdd > 0) then          -- Poor Distribution method.
                                local difference = equipment.max_energy - equipment.energy
                                if (energyToAdd > difference) then
                                    energyToAdd = energyToAdd - difference
                                    equipment.energy = equipment.max_energy
                                else
                                    equipment.energy = equipment.energy + energyToAdd
                                    energyToAdd = 0
                                    --break -- Removed since it interferes with shield.
                                end
                            end  
                            if (equipment.max_shield ~= 0) then
                                
                                equipment.shield = equipment.max_shield * shieldFraction -- This part is a quick autobalance. All shields get equal power.
                                --shieldHealth = shieldHealth + equipment.shield
                                --equipment.shield = equipment.shield - (equipment.max_shield*ShieldDecayPerTick)
                            else -- Ideally, I want to send power from high efficiency ones to lower efficiency ones. That minimizes power consumption.
                                
                            end
                            
                        end
                        
                        
                        
                        modularArmor.units.accumulator.energy = RanaMods.ModularArmor.config.accumulatorEnergyCap - transferRate--*conversionRatio
                        modularArmor.previousEnergy = modularArmor.units.accumulator.energy --*conversionRatio -- The additional accumulated energy over
                        
                        
                        
                    else
                        killDummies(modularArmor)
                    end
                else
                    killDummies(modularArmor)
                end
            else
                -- No player
                -- killDummies(modularArmor)
            end
        end
            
    end
    
	--[[if (not shouldKeepTicking) then
		global.ticking = nil
		script.onevent(defines.events.ontick, nil)
	end]]--
end
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Nexela
Smart Inserter
Smart Inserter
Posts: 1828
Joined: Wed May 25, 2016 11:09 am
Contact:

Re: On tick Event, need synced registration

Post by Nexela »

first issue is the way you are getting players in tick #players could be one but the players index could be 2

Code: Select all

function tick()
    --globalPrint("tick")
    --shouldKeepTicking = true -- Due to lack of any alternate method of detecting player's armor state, we have to always tick.
   for x, thisPlayer in pairs(game.players) do
        if (thisPlayer.connected) then 
            if (thisPlayer.character) then --this line and the one above could be combined into one using AND. LUA the second condition will not be evaluated if the first is false
User avatar
Adil
Filter Inserter
Filter Inserter
Posts: 945
Joined: Fri Aug 15, 2014 8:36 pm
Contact:

Re: On tick Event, need synced registration

Post by Adil »

That's a mighty big ticker you have there. Nexela is right about the first bug, althought I'd expect it to throw lua error if game.players is queried with incorrect index.
Maybe somewhere you accidentally declare a global variable instead of a local one, difficult to tell.
Try commenting out blocks of code and see which one breaks the mod.

Also, I believe you could move sizable chunks of code to different handlers such as on_player_created, on_player_placed_equipment, on_player_removed_equipment and so on.
I do mods. Modding wiki is friend, it teaches how to mod. Api docs is friend too...
I also update mods, some of them even work.
Recently I did a mod tutorial.
User avatar
Ranakastrasz
Smart Inserter
Smart Inserter
Posts: 2179
Joined: Thu Jun 12, 2014 3:05 am
Contact:

Re: On tick Event, need synced registration

Post by Ranakastrasz »

Adil wrote:That's a mighty big ticker you have there. Nexela is right about the first bug, althought I'd expect it to throw lua error if game.players is queried with incorrect index.
Maybe somewhere you accidentally declare a global variable instead of a local one, difficult to tell.
Try commenting out blocks of code and see which one breaks the mod.

Also, I believe you could move sizable chunks of code to different handlers such as on_player_created, on_player_placed_equipment, on_player_removed_equipment and so on.
Technically true. However, several things. Started the mod a while back, before equipment events existed, and I haven't found a mod that uses them yet, so I have no examples to work with. Until then, I am reluctant to delete 90% of the code and start over. I need to at least be able to visualize what I want to do.

And yea, the ticker is insanely large, and until I found Combat Robots, was the most expensive mod I've ever run. 0.5 generally, while most mods never pass 0.1.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
User avatar
Adil
Filter Inserter
Filter Inserter
Posts: 945
Joined: Fri Aug 15, 2014 8:36 pm
Contact:

Re: On tick Event, need synced registration

Post by Adil »

I do mods. Modding wiki is friend, it teaches how to mod. Api docs is friend too...
I also update mods, some of them even work.
Recently I did a mod tutorial.
User avatar
Ranakastrasz
Smart Inserter
Smart Inserter
Posts: 2179
Joined: Thu Jun 12, 2014 3:05 am
Contact:

Re: On tick Event, need synced registration

Post by Ranakastrasz »

Found the issue. As it turns out, unlike most sensible programming languages, it doesn't give an error if you try to register an event to call a function which is defined lower down in the file, but it doesn't work either. Normally, it would throw an error claiming the function doesn't exist, or else would work.


Most likely this will fix everything.


Still going to have to investigate the other events, but that can wait until the mod actually works again in the first place.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Rseding91
Factorio Staff
Factorio Staff
Posts: 15984
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: On tick Event, need synced registration

Post by Rseding91 »

Ranakastrasz wrote:Found the issue. As it turns out, unlike most sensible programming languages, it doesn't give an error if you try to register an event to call a function which is defined lower down in the file, but it doesn't work either. Normally, it would throw an error claiming the function doesn't exist, or else would work.


Most likely this will fix everything.


Still going to have to investigate the other events, but that can wait until the mod actually works again in the first place.
Passing a variable before it's defined is the same as passing nil since the undefined variable has no value - AKA: nil. Passing nil to the script.on_event() function tells Factorio you want to unsubscribe from the event.

It's all perfectly defined behavior and how every script language works that I know of.
If you want to get ahold of me I'm almost always on Discord.
User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: On tick Event, need synced registration {RESOLVED}

Post by aubergine18 »

Using a code linter like luacheck can significantly reduce such problems by highlighting issues at design time within your scripts (eg. it would tell you if the function you're referring to is not yet defined): viewtopic.php?f=34&t=29919
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.
Post Reply

Return to “Modding help”