[Resolved] Weird BUG with my MOD - Mining Rail

Place to get help with not working mods / modding interface.
TheSAguy
Smart Inserter
Smart Inserter
Posts: 1456
Joined: Mon Jan 13, 2014 6:17 pm
Contact:

[Resolved] Weird BUG with my MOD - Mining Rail

Post by TheSAguy »

Hi,

Someone reported the weirdest bug on my MOD that I've seen in some time.
When mining a section or rail, a section or rail far away from the mined rail also disappears.

Here is a GIF showing what happens: BUG

Image of issue:
BUG
I've attached a save. Anyone know what's going on here?
Seems like two rail pieces has the same Item ID or something.
I know with the release of 0.16.40 and then 0.16.41 some rail stuff got tweaked. Does that have something to do with it?

Would really appreciate it if someone could look at this.
Thanks.
Attachments
Mega-mod-Gameplay.zip
Save
(11.24 MiB) Downloaded 78 times
Last edited by TheSAguy on Fri May 11, 2018 8:14 pm, edited 1 time in total.
Bilka
Factorio Staff
Factorio Staff
Posts: 3470
Joined: Sat Aug 13, 2016 9:20 am
Contact:

Re: Weird BUG with my MOD - Mining Rail

Post by Bilka »

Could you also link/attach your mod.
I'm an admin over at https://wiki.factorio.com. Feel free to contact me if there's anything wrong (or right) with it.
User avatar
darkfrei
Smart Inserter
Smart Inserter
Posts: 2905
Joined: Thu Nov 20, 2014 11:11 pm
Contact:

Re: Weird BUG with my MOD - Mining Rail

Post by darkfrei »

Bilka wrote:Could you also link/attach your mod.
If you have the Savegame, you can sync all mods by one click.
Bilka
Factorio Staff
Factorio Staff
Posts: 3470
Joined: Sat Aug 13, 2016 9:20 am
Contact:

Re: Weird BUG with my MOD - Mining Rail

Post by Bilka »

TheSAguy wrote: Seems like two rail pieces has the same Item ID or something.
I know with the release of 0.16.40 and then 0.16.41 some rail stuff got tweaked. Does that have something to do with it?
Well, you save your entities by position hashes (why? just use unit_number...), so no rail change should affect that. So, your global table is broken. There can be many reasons for that: A user messed with it, it didn't get saved properly, your mod has a bug somewhere, etc etc. If it is your mod, it could be anywhere you save, get, or delete entitites since you have everything in the same table.
I'm an admin over at https://wiki.factorio.com. Feel free to contact me if there's anything wrong (or right) with it.
Bilka
Factorio Staff
Factorio Staff
Posts: 3470
Joined: Sat Aug 13, 2016 9:20 am
Contact:

Re: Weird BUG with my MOD - Mining Rail

Post by Bilka »

darkfrei wrote:
Bilka wrote:Could you also link/attach your mod.
If you have the Savegame, you can sync all mods by one click.
That doesn't work on mobile :P
Here are the relevant code parts for anybody who doesn't want to download a save and 55 mods:

Code: Select all

-- Power Rail on_built_entity
	if (entity.valid and entity.name == "bi-straight-rail-power") or (entity.valid and entity.name == "bi-curved-rail-power") then
	writeDebug("Power Rail has been built")
		local surface = entity.surface
		local force = entity.force
		local position = entity.position		   
		local rail_track = entity
		local pole_name = "bi-rail-hidden-power-pole"  		
		
		local create_rail_pole = surface.create_entity({name = pole_name, position = position, force = force})
				
		create_rail_pole.minable = false
		create_rail_pole.destructible = false 
		
		group_entities(cantor(position.x,position.y), { rail_track, create_rail_pole })	  

	end

Code: Select all

--- Power Rail has been removed
   	if (entity.valid and entity.name == "bi-straight-rail-power") or (entity.valid and entity.name == "bi-curved-rail-power") then
		local pos_hash = cantor(entity.position.x,entity.position.y)
        local entity_group = getGroup_entities(pos_hash)
        if entity_group then
            for ix, vx in ipairs(entity_group) do
                if vx == entity then
                    --vx.destroy()
                else
                    vx.destroy()
                end
            end
        end
        ungroup_entities(pos_hash)
	end

Code: Select all

-- Cantor Hash
-------------------------------------------------------------------
function cantor(k1, k2)
	return (0.5 * (k1+k2) * (k1+k2+1) + k2)
end

Code: Select all

function group_entities(entity_groupid, entity_list)
    return group("entities", entity_groupid, entity_list)
end

function getGroup_entities(entity_groupid)
    return getGroup("entities", entity_groupid)
end

function ungroup_entities(entity_groupid)
    return ungroup("entities", entity_groupid)
end

Code: Select all

-- Grouping
--
function group(index_id, group_id, members)
	_init_group(index_id, group_id)

	if index_id == nil then
	 index_id = "default"
 	end

	if group_id then
		for ix, vx in ipairs(members) do
			_addto_group(index_id, group_id, vx)
		end
		return group_id
	else
		-- no GID, then assign one
		return group(index_id, _new_group(index_id), members)
	end
end

function getGroup(index_id, group_id)
	_init_group(index_id, group_id)

	if group_id then
		return _get_group(index_id, group_id)
	else
		return nil
	end
end

function ungroup(index_id, group_id)
	_init_group(index_id, group_id)

	if group_id then
		return _clear_group(index_id, group_id)
	else
		return false
	end
end
-------------------------------------------------------------------
function _init_group(index_id)
	if not global.group then
		global.group = {}
	end
	if not global.group.default then
		global.group.default = {}
	end
	if index_id and not global.group[index_id] then
		-- don't care if they name their group "default"
		global.group[index_id] = {}
	end
end

function _addto_group(index_id, group_id, member_id)
	if global.group[index_id] then
		if not global.group[index_id][group_id] then
			global.group[index_id][group_id] = {}
		end
	end

	table.insert(global.group[index_id][group_id], member_id)
end

function _get_group(index_id, group_id)
	return global.group[index_id][group_id]
end

function _clear_group(index_id, group_id)
	global.group[index_id][group_id] = nil
end
I'm an admin over at https://wiki.factorio.com. Feel free to contact me if there's anything wrong (or right) with it.
TheSAguy
Smart Inserter
Smart Inserter
Posts: 1456
Joined: Mon Jan 13, 2014 6:17 pm
Contact:

Re: Weird BUG with my MOD - Mining Rail

Post by TheSAguy »

Bilka wrote:
TheSAguy wrote: Seems like two rail pieces has the same Item ID or something.
I know with the release of 0.16.40 and then 0.16.41 some rail stuff got tweaked. Does that have something to do with it?
Well, you save your entities by position hashes (why? just use unit_number...), so no rail change should affect that. So, your global table is broken. There can be many reasons for that: A user messed with it, it didn't get saved properly, your mod has a bug somewhere, etc etc. If it is your mod, it could be anywhere you save, get, or delete entitites since you have everything in the same table.
Thanks for your feedback Bilka. I've always used the hashes, that was the way I was introduced to group entities.
What would be the optimal way to group entities and then remove them? (The code please :D )

I assume that any change that I make will have to be on a new game only...

Thanks!
User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5211
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Weird BUG with my MOD - Mining Rail

Post by eradicator »

Just use .unit_number for indexing instead of your hashing function. Unit_number is an integer unique to that entity, i.e. the same entity will always have the same unit_number even if the position changes. Position hashing was only used before unit_number was introduced in what...0.13?

Code: Select all

script.on_configuration_changed(function()
 global.newblob = {}
 for k,v pairs(your_global_blob) do
   global.newblob[v[1].unit_number] = v -- assumes v[1] is the element you want to index by.
   end
end)
TheSAguy
Smart Inserter
Smart Inserter
Posts: 1456
Joined: Mon Jan 13, 2014 6:17 pm
Contact:

Re: Weird BUG with my MOD - Mining Rail

Post by TheSAguy »

eradicator wrote:Just use .unit_number for indexing instead of your hashing function. Unit_number is an integer unique to that entity, i.e. the same entity will always have the same unit_number even if the position changes. Position hashing was only used before unit_number was introduced in what...0.13?

Code: Select all

script.on_configuration_changed(function()
 global.newblob = {}
 for k,v pairs(your_global_blob) do
   global.newblob[v[1].unit_number] = v -- assumes v[1] is the element you want to index by.
   end
end)
Thanks eradicator, so I could use the above to, in theory, migrate old games to the new code.

For updating the code however, what is the best code to use?
Do I store it in global tables, like below?

Code: Select all

global.Arboretum_Table[create_arboretum.unit_number] = {inventory=create_arboretum, radar=create_radar}
and remove using:

Code: Select all

   	if entity.valid and entity.name == "bi-drill-base" then
		writeDebug("Drill has been removed")

		global.bi_drill_table[entity.unit_number].drill_bit.destroy()
		global.bi_drill_table[entity.unit_number] = nil
		
	end
I've looked at some other mods that add hidden entities, and it seems everyone does it differently. Just wandering what's the best way to do this, since I'm going to re-do it....

Thanks,.
Bilka
Factorio Staff
Factorio Staff
Posts: 3470
Joined: Sat Aug 13, 2016 9:20 am
Contact:

Re: Weird BUG with my MOD - Mining Rail

Post by Bilka »

Just like in the game itself, there is no objectively best way to do this. But here is how I'd do it: Your general concept works, but has too much boilerplate for my taste. If you dont need the original entity in the table, don't add it. Separate tables for each type of entity because it allows you to easily remove one entity type, or change how it is saved.

So, for your rails, init the global in on_init/on_config_changed, to save global.rails[rail.unit_number] = power_pole would be enough, and when your rail is destroyed, get the power pole with the unit number, kill it, set the entry in the table nil. All of this can be done directly in the functions in like 5 lines instead of in some boilerplate code 5 files away. But you can still boilerplate it if you want. If you do need to save more than 1 entity, do global.labs[lab.unit_number] = {pump = pump, lamp = lamp}, like you did before.

There is probably a way that fits better to you/your coding style/your mod, but this is my opinion for how I'd do it.
I'm an admin over at https://wiki.factorio.com. Feel free to contact me if there's anything wrong (or right) with it.
User avatar
eradicator
Smart Inserter
Smart Inserter
Posts: 5211
Joined: Tue Jul 12, 2016 9:03 am
Contact:

Re: Weird BUG with my MOD - Mining Rail

Post by eradicator »

TheSAguy wrote: For updating the code however, what is the best code to use?
I've looked at some other mods that add hidden entities, and it seems everyone does it differently. Just wandering what's the best way to do this, since I'm going to re-do it....
I have no clue what your mod even does, much less what kind of data you need to store (your examples look like they're taken from several different mods to me). I would recommend you only change the indexing for now and keep the rest as is if there aren't any obvious/major problems with it (i.e. don't change for the sake of changing). That also reduces the risk of introducing new bugs while fixing this one.

Not sure how other mods do it, but i'm of the impression that everyone does it pretty much the same, as there's not much room for variation. You just dump the data you need into a global table. I.e. global.data_i_care_for[main_entity.unit_number] = {data1 = x, data2 = y, data3 = z}.
Post Reply

Return to “Modding help”