Need a little help updating Floors mod

Place to get help with not working mods / modding interface.
Post Reply
User avatar
Taehl
Long Handed Inserter
Long Handed Inserter
Posts: 50
Joined: Sun Jan 18, 2015 2:23 am
Contact:

Need a little help updating Floors mod

Post by Taehl »

Hello, all. I'm very familiar with Lua (via Garry's Mod, then Love2D), but this is my first time looking at Factorio's modding system. I'm trying to update the Floors mod to work with the latest version of Factorio, specifically, in multiplayer.

Running the 0.0.3 version of the mod in multiplayer and attempting to place a "Floor-O-Matic" causes a script error and closes Factorio. The error is:
"Error while running the event handler: _ _ floors _ _\control.lua:254: Map doesn't contain 1 player, this function can't be used"

The code it's referring to is this:

Code: Select all

function safe_insert(i)
	if not i then return false end
	if game.player then				-- the culprit, line 254
		if game.player.character then
			if (game.player.caninsert{name=i, count=1}==true) then
				game.player.character.insert{name=i, count=1}
				return true
			end
		end
	end
	return false
end

game.onevent(defines.events.onbuiltentity, function(event)
	local is_floor=false
	for _, ftype in ipairs(floor_types) do
		if (event.createdentity.name==ftype) then is_floor=true end
	end
	if (is_floor==true) then	
		update_area(event.createdentity.position.x,event.createdentity.position.y,event.createdentity.name)
	elseif (event.createdentity.name=="floor-b-gone") then
		delete_area(event.createdentity.position.x,event.createdentity.position.y)
		safe_insert("floor-b-gone")
	elseif (event.createdentity.name=="floor-o-matic") then
		flooromatic(event.createdentity.position.x,event.createdentity.position.y)
		safe_insert("floor-o-matic")
	end
end)
From what I understand, the issue is that in multiplayer, game.player is nil and instead game.players is used. Another thread had a snippet of code which suggests a solution:

Code: Select all

for i, player in ipairs(game.players) do
   -- call player functions here
end
However, this is not quite the solution. The intended behaviour would seemingly be to insert 1 Floor-O-Matic into the inventory of the player who just placed it, not into every player's inventory. So we need to determine the index of the player who placed it. According to the wiki, this information is not provided to the event handler function (it only gives createdentity). Is there a proper way to determine who placed it, or am I going to have to do something hacky like iterate through all players and just give the FOM to the one standing nearest to it?

User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Need a little help updating Floors mod

Post by FreeER »

The wiki is not currently up to date (and never has been completely up to date as far as I know) :)
I've been away for a while and just getting back to Factorio (hello again everyone!).
I knew that events were getting a playerindex prior to leaving so when I came back I did some testing and compiled this list (version 11.11):
quick note: I've no idea what does and doesn't cause desyncs in MP...
Events with event.playerindex
  • onplayercrafteditem
  • onpreplayermineditem
  • onplayermineditem
  • onplayercreated
  • onbuiltentity
  • onpickedupitem
  • onguiclick
  • onplayerrotatedentity
  • onshiplandingstart
events without event.playerindex (for the most part it wouldn't make sense for these to have a playerindex):
  • *onputitem (not sure why this doesn't have playerindex)
  • ontick
  • onchunkgenerated
  • onentitydied
  • onsectorscanned
  • onrobotbuiltentity
  • onrobotpremined
  • onrobotmined
  • onmarkedfordeconstruction
  • oncanceleddeconstruction
  • ontrainchangedstate
  • onresearchstarted
  • onresearchfinished
  • // assuming the below don't
  • oninit :)
  • ontriggercreatedentity (Not sure how to trigger this. Tried Distractor capsule and landmine, but no luck)
edit: for the curious this is what I've used to compile this list:
then duplicated for each event (I made a list of event names and then used a regular expression to add the boilerplate!)

Code: Select all

game.onevent(defines.events.onputitem, function(event)
  game.player.print(serpent.block(event))
   -- event.name is numeric id (the same as defines.events.onputitem)
   -- using a string here because I did this with ALL of the events and wanted a _nice_ way to identify them
  game.player.print('defines.events.onputitem')
end)
<I'm really not active any more so these may not be up to date>
~FreeER=Factorio Modding
- Factorio Wiki
- My Factorio Modding Guide
- Wiki Modding Guide
Feel free to pm me :)
Or drop into #factorio on irc.esper.net

User avatar
Taehl
Long Handed Inserter
Long Handed Inserter
Posts: 50
Joined: Sun Jan 18, 2015 2:23 am
Contact:

Re: Need a little help updating Floors mod

Post by Taehl »

Superb! Thank you, this is much better. So, the code should be updated to this?

Code: Select all

function safe_insert(i, p)
	if not (i and p) then return false end
	local player = game.players[p]
	if player and player.character then
		if (player.caninsert{name=i, count=1}==true) then
			player.character.insert{name=i, count=1}
			return true
		end
	end
	return false
end

game.onevent(defines.events.onbuiltentity, function(event)
	local is_floor=false
	for _, ftype in ipairs(floor_types) do
		if (event.createdentity.name==ftype) then is_floor=true end
	end
	if (is_floor==true) then	
		update_area(event.createdentity.position.x,event.createdentity.position.y,event.createdentity.name)
	elseif (event.createdentity.name=="floor-b-gone") then
		delete_area(event.createdentity.position.x,event.createdentity.position.y)
		safe_insert("floor-b-gone", event.playerindex)
	elseif (event.createdentity.name=="floor-o-matic") then
		flooromatic(event.createdentity.position.x,event.createdentity.position.y)
		safe_insert("floor-o-matic", event.playerindex)
	end
end)
Just to make sure, player.caninsert and player.character.insert are regular functions, not methods (ie., called using ":" )?

User avatar
FreeER
Smart Inserter
Smart Inserter
Posts: 1266
Joined: Mon Feb 18, 2013 4:26 am
Contact:

Re: Need a little help updating Floors mod

Post by FreeER »

Taehl wrote:Just to make sure, player.caninsert and player.character.insert are regular functions, not methods (ie., called using ":" )?
Hm, yes (and technically no since game.player is actually a C++ userdata object but from a lua user perspective you call them as functions without the ':').
Taehl wrote:So, the code should be updated to this?
A few things I would note, but it looks like it should work to me :)
  • (not an issue here since inserting 1 item but I should mention it)- caninsert returns true if ANY portion of the count can be inserted. Not if ALL of it can be inserted. IF you were checking that you could insert an amount greater than 1 then caninsert would return true even if only 1 could actually fit in the player's inventory (and insert would give that 1 and print a message saying the player's inventory was full).
  • if the check for "i" not converting to a false boolean is meant to prevent errors then it should be a check that game.itemprototypes converts to a true boolean ("i" being true just says you got some kind of value for it that isn't false or nil, "game.itemprototypes" says that Factorio actually has an itemprototype registered with that value. It's not an error to index non-existent elements (including with nil), you'll just get nil as as the result, which converts to a false bool)
  • The code is creating two separate tables for caninsert and insert, not exactly a performance critical function from the looks of it but it'd be slightly better to have a "local itemstack = {name=i, count=1}", and use "if player.caninsert(itemstack) then player.insert(itemstack) return true end" (nicely formatted of course).
  • (personal preference) the explicit comparisons to true are unnecessary


quick edit:
you can also use player.insert(itemstack) like you do with player.caninsert, in which case you wouldn't NEED the player.character to exist, it'll insert into the proper inventory (ghost or god mode don't have characters but at least god does still have an inventory, I think ghost does too but not 100% certain).

User avatar
Taehl
Long Handed Inserter
Long Handed Inserter
Posts: 50
Joined: Sun Jan 18, 2015 2:23 am
Contact:

Re: Need a little help updating Floors mod

Post by Taehl »

Thanks again, FreeER. I know the code is a little rough, but I didn't write it, you know? ;)
I might dive in and start cleaning up and/or adding features later, for now, I just wanted to make a quick edit.

I've tested it out for a few minutes in both multi and single player. Haven't had a chance to try it with others connected, but I don't see why that would break anything. Here's the download link.

Choumiko
Smart Inserter
Smart Inserter
Posts: 1352
Joined: Fri Mar 21, 2014 10:51 pm
Contact:

Re: Need a little help updating Floors mod

Post by Choumiko »

Taehl wrote:I've tested it out for a few minutes in both multi and single player. Haven't had a chance to try it with others connected, but I don't see why that would break anything. Here's the download link.
You can't be sure, see https://forums.factorio.com/forum/vie ... 68&p=63481 (post from kovarex) That's a pretty hidden reason for a desync :D

User avatar
Taehl
Long Handed Inserter
Long Handed Inserter
Posts: 50
Joined: Sun Jan 18, 2015 2:23 am
Contact:

Re: Need a little help updating Floors mod

Post by Taehl »

Yikes! I'll make sure to fully test it ASAP (probably tomorrow). And even if we do find a desync, well, that means I've helped Factorio get one more bug ironed out. :)

User avatar
Taehl
Long Handed Inserter
Long Handed Inserter
Posts: 50
Joined: Sun Jan 18, 2015 2:23 am
Contact:

Re: Need a little help updating Floors mod

Post by Taehl »

Okay, I gave it a nice, long test with two (Windows) clients. No Mac available (or gaming-grade Linux box), so that's the best I can do by myself. No crashes or desynch or anything. No issues saving and loading. The floors did a few strange things when using the Floor-O-Matic to overlay floor sections, but I'm pretty sure it's the mod's "correct" behaviour. Also, if you place floors over water, the game has a harsh pause when removing them.

Can't wait until floors are an official feature. :)

Post Reply

Return to “Modding help”