Client-side scripts to send custom events to sim; readfile()

Things that we aren't going to implement
Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Client-side scripts to send custom events to sim; readfile()

Post by Zeblote »

There's a makefile method to write a file and store data, but no matching readfile method to access the data later.

This would be really useful to persistently store mod settings and similar things, shared between multiple save games.
Last edited by Zeblote on Mon Oct 05, 2015 9:18 pm, edited 2 times in total.

ratchetfreak
Filter Inserter
Filter Inserter
Posts: 952
Joined: Sat May 23, 2015 12:10 pm
Contact:

Re: Readfile method

Post by ratchetfreak »

not gonna happen because it leads to desyncs when the files on each client aren't synced

Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Readfile method

Post by Zeblote »

ratchetfreak wrote:not gonna happen because it leads to desyncs when the files on each client aren't synced
How would this lead to a desync? Other clients don't even need to know whether the file exists or that it has been read at all.


For example you could load settings in a client sided gui. Other clients don't even need to know whether you have this gui open, it's irrelevant for them.
When you apply the changes a notice is sent to other clients how settings have changed so they can reproduce the changes. For many things there's no need to duplicate all actions on different clients, only the end result.

ratchetfreak
Filter Inserter
Filter Inserter
Posts: 952
Joined: Sat May 23, 2015 12:10 pm
Contact:

Re: Readfile method

Post by ratchetfreak »

Zeblote wrote:
ratchetfreak wrote:not gonna happen because it leads to desyncs when the files on each client aren't synced
How would this lead to a desync? Other clients don't even need to know whether the file exists or that it has been read at all.


For example you could load settings in a client sided gui. Other clients don't even need to know whether you have this gui open, it's irrelevant for them.
When you apply the changes a notice is sent to other clients how settings have changed so they can reproduce the changes. For many things there's no need to duplicate all actions on different clients, only the end result.
In the current state of affairs all clients will run the exact same code and there is no way to only run some code on a single client.

It would be nice to have a on_gui_create event to fill a gui that while it is being handled disallows game state changes (only reads from the game state is allowed).

Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Readfile method

Post by Zeblote »

ratchetfreak wrote:
Zeblote wrote:
ratchetfreak wrote:not gonna happen because it leads to desyncs when the files on each client aren't synced
How would this lead to a desync? Other clients don't even need to know whether the file exists or that it has been read at all.


For example you could load settings in a client sided gui. Other clients don't even need to know whether you have this gui open, it's irrelevant for them.
When you apply the changes a notice is sent to other clients how settings have changed so they can reproduce the changes. For many things there's no need to duplicate all actions on different clients, only the end result.
In the current state of affairs all clients will run the exact same code and there is no way to only run some code on a single client.

It would be nice to have a on_gui_create event to fill a gui that while it is being handled disallows game state changes (only reads from the game state is allowed).
In that case it would be nice for mods to have lower level control over how they work in multiplayer. Duplicating all actions seems like quite the brute force approach that doesn't really make sense when it comes to user interfaces.

We should be able to send/receive custom data to other clients and sync certain things ourselves.

User avatar
Adil
Filter Inserter
Filter Inserter
Posts: 945
Joined: Fri Aug 15, 2014 8:36 pm
Contact:

Re: Readfile method

Post by Adil »

Welp, to some people multiplayer brings only despair.
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.

Rseding91
Factorio Staff
Factorio Staff
Posts: 14132
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Readfile method

Post by Rseding91 »

Zeblote wrote:In that case it would be nice for mods to have lower level control over how they work in multiplayer. Duplicating all actions seems like quite the brute force approach that doesn't really make sense when it comes to user interfaces.

We should be able to send/receive custom data to other clients and sync certain things ourselves.
As far as mods are aware they never know they're being run in a MP game. To them you're just running a single player game with a bunch of simulated players doing stuff.

Mods do no syncing of data and they don't need to - they simply respond to the events generated by the game and do what ever logic they see fit based off those events. No extra data has to be sent between peers with 1 mod vs. 100 mods using this method and there's no chance for a mod to send the wrong data or interpret the data in the wrong way.

It's highly unlikely this will ever change - that goes against the entire model that Factorio is built on: input actions are synced (player clicked GUI, player pressed key) and the game simulation is run deterministically by all peers in the game.
If you want to get ahold of me I'm almost always on Discord.

Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Readfile method

Post by Zeblote »

Rseding91 wrote: As far as mods are aware they never know they're being run in a MP game.
Why not? This may be important for some things.
Rseding91 wrote: Mods do no syncing of data and they don't need to - they simply respond to the events generated by the game and do what ever logic they see fit based off those events. No extra data has to be sent between peers with 1 mod vs. 100 mods using this method and there's no chance for a mod to send the wrong data or interpret the data in the wrong way.

It's highly unlikely this will ever change - that goes against the entire model that Factorio is built on: input actions are synced (player clicked GUI, player pressed key) and the game simulation is run deterministically by all peers in the game.
That makes a lot of sense, but in some situations it just doesn't work. The mod I'm thinking about at the moment is a blueprint library.

For this I suggest a new sub-type of mod/script: client side scripts. These don't change the game state by themselves and run on one client only - no synchronization. Other clients don't know what you're doing with them or whether they exist at all (and it doesn't matter as they don't change the game state). However they are able to send custom inputs (events) to the simulation - much like the examples you gave above. That would then allow all clients to handle the changes exactly the same.

How I imagine it works is with a client-side script that handles saving a blueprint to the local library (on my client, inside script-output folder), and loading these blueprints from in-game on any server that runs the mod.

The client script runs the gui with the blueprint library. Using it I can, for example, save the blueprint I have currently selected to a local file and list all blueprints in the library. There's nothing that needs to be synchronized so far. Loading a blueprint however, modifies the game state so the client script can't do it. It would send the structure of the blueprint as an 'input' to the simulation, so all clients can reproduce the change of my current blueprint. Perfectly deterministic for the part that matters.

I'm sure more modders could come up with more and maybe even better uses for client-sided scripts that are able to send custom events to the simulation (these are then called on all clients just like you described). It would allow for much more complex and even more awesome mods.

Rseding91
Factorio Staff
Factorio Staff
Posts: 14132
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Readfile method

Post by Rseding91 »

Right now the blueprint saving/loading mods that exist simply take the input through a GUI text field. The user pastes the blueprint text into the GUI and the mod reads the GUI.

If there was some way to guarantee that a mod wasn't going to touch the game state then it might be feasible to implement such a method for mods to use. As it is right now there's no good way to guarantee that a mod will or won't touch the game state.
If you want to get ahold of me I'm almost always on Discord.

Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Readfile method

Post by Zeblote »

Rseding91 wrote:Right now the blueprint saving/loading mods that exist simply take the input through a GUI text field. The user pastes the blueprint text into the GUI and the mod reads the GUI.
Yes but this isn't user friendly and annoying to use. You have to minimize factorio and open a text editor. (https://www.factorio.com/blog/post/fff-106) The one I described would be completely seamless and well integrated within the game.
Rseding91 wrote: If there was some way to guarantee that a mod wasn't going to touch the game state then it might be feasible to implement such a method for mods to use. As it is right now there's no good way to guarantee that a mod will or won't touch the game state.
You don't have to do the work of modders, if a mod causes a desync because it is badly programmed then that's the modders fault, not yours! ;) More options that may be dangerous if used wrong is better than less options. All it takes is adding a client.lua that is executed on the client side and telling modders to not change the game state in it or things will go bad. Both the client and the server part could be in the same mod folder by using control.lua like usual and client.lua for the client sided scripts/guis/whatever

I imagine the method would work similar to this, in client.lua:

Code: Select all

local params = {test="blah", num=4.5} 
game.transmit_event("transmitBlueprint", params)
It can call any event by its name.

And in control.lua:

Code: Select all

game.on_event("transmitBlueprint", function(event)
	//This is called on all clients like a regular event, change blueprint in here
	//event.params.test contains "blah", event.params.num contains 4.5
end)
The params would be serialized and sent to all clients along the normal inputs. For simplicity let's say there is a size limit of 500kB or however big your packet size is so it doesn't have to be fragmented. The modder could implement this himself if it is really necessary to fragment and send large data. On the other side you'd hook the event like usual and access the sent parameters.

Rseding91
Factorio Staff
Factorio Staff
Posts: 14132
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Readfile method

Post by Rseding91 »

Zeblote wrote: You don't have to do the work of modders, if a mod causes a desync because it is badly programmed then that's the modders fault, not yours! ;)
It doesn't work that way in the real world :P every mod that breaks gets blamed on the game engine and not the mod.
If you want to get ahold of me I'm almost always on Discord.

Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Readfile method

Post by Zeblote »

Rseding91 wrote:
Zeblote wrote: You don't have to do the work of modders, if a mod causes a desync because it is badly programmed then that's the modders fault, not yours! ;)
It doesn't work that way in the real world :P every mod that breaks gets blamed on the game engine and not the mod.
But you're not breaking mods, they just won't work in the first place. The modder has to ensure it'll work before he releases it.

At the moment I'm blaming your engine for not supporting client-side scripts :D

Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Client-side scripts to send custom events to sim; readfile()

Post by Zeblote »

I don't know how your lua integration works in detail, but can't you just forbid changing the game state in client scripts? Let client.lua only read from the game state and access local things that won't change the game state like guis, chat or files. To change things it needs to send an event to the simulation to the other part of the mod in control.lua.

User avatar
DaveMcW
Smart Inserter
Smart Inserter
Posts: 3713
Joined: Tue May 13, 2014 11:06 am
Contact:

Re: Client-side scripts to send custom events to sim; readfile()

Post by DaveMcW »

A better model is the text box gui. You can paste a block of text into it, and it automatically copies to all clients.

We need a similar object that can read a file on a specific player's computer, and copy the contents to all clients.

Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Client-side scripts to send custom events to sim; readfile()

Post by Zeblote »

DaveMcW wrote:A better model is the text box gui. You can paste a block of text into it, and it automatically copies to all clients.

We need a similar object that can read a file on a specific player's computer, and copy the contents to all clients.
That would solve the problem for blueprint loading. :D It's kinda what I meant, except they would implement the specific thing in C++ instead of a more generic version where you'd implement the sync logic in lua. I guess this can be implemented a lot easier :D

To go with this, we could then use functions to list all files in a folder and copy the result to all clients aswell.

Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Client-side scripts to send custom events to sim; readfile()

Post by Zeblote »

This topic is kind of a mess now, so I'll try to summarize it. This is the mod interface we need at this point:


player.write_file(path, contents) - returns boolean
Works just like the existing makefile, except only on one clients computer. Returns true or false depending on whether the file could be written.


player.read_file(path) - returns string or false
Reads a file from script-output on one clients computer and replicates the contents to other clients. Returns false if the file couldn't be read.


player.delete_file(path) - returns boolean
Deletes a file from script-output on one clients computer. Returns false if the file doesn't exist or couldn't be deleted.


player.delete_path(path) - returns boolean
Deletes a folder with all subfolders and files from script-output on one clients computer. Returns false if the folder doesn't exist or couldn't be deleted.


player.find_files(mask) - returns a table of file paths, file sizes and modified dates
Searches for files matching the mask inside script-output and replicates the table to other clients.

For example, it could be used like this: player.find_paths("blueprints/*.dat") and might return the following:

Code: Select all

blueprints/big_station.dat           |  938 | 04/10/2015 14:51:43
blueprints/station.dat               |  472 | 08/10/2015 08:33:12
blueprints/somefolder/powerplant.dat | 2134 | 14/09/2015 19:16:58

player.find_paths(mask) - returns a list of folders
Searches for folders matching the mask inside script-output and replicates the table to other clients.

Works similar to the above method, but searches for folders (including empty ones!). player.find_paths("blueprints/*") might return

Code: Select all

blueprints/somefolder/
blueprints/sometolder/anotherfolder/
With all these functions together, it should be possible to implement a fancy local blueprint library and all sorts of other things like saving favorite mod settings and whatnot.
Last edited by Zeblote on Fri Oct 09, 2015 2:47 am, edited 4 times in total.

ratchetfreak
Filter Inserter
Filter Inserter
Posts: 952
Joined: Sat May 23, 2015 12:10 pm
Contact:

Re: Client-side scripts to send custom events to sim; readfile()

Post by ratchetfreak »

There is one thing missing

How do you specify which client to write/read the file to/from

Or what about headless servers can they provide files for this as well?

Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Client-side scripts to send custom events to sim; readfile()

Post by Zeblote »

ratchetfreak wrote:There is one thing missing

How do you specify which client to write/read the file to/from
They're methods on the player class. Based on other mods, that's what identifies a specific client. Gui events pass along the player who clicked buttons. Or did I miss something? :D

About headless servers, I've no idea. They would need a seperate set of methods.

ratchetfreak
Filter Inserter
Filter Inserter
Posts: 952
Joined: Sat May 23, 2015 12:10 pm
Contact:

Re: Client-side scripts to send custom events to sim; readfile()

Post by ratchetfreak »

Zeblote wrote: They're methods on the player class. Based on other mods, that's what identifies a specific client. Gui events pass along the player who clicked buttons. Or did I miss something? :D

About headless servers, I've no idea. They would need a seperate set of methods.
I noticed that a bit later. was too lazy to clear the text.

Also on the more technical side; the replay file must contain the file that was pulled in. That can cause the replay file to grow quite a bit if a mod is dumb and pulls a file every tick.

Zeblote
Filter Inserter
Filter Inserter
Posts: 973
Joined: Fri Oct 31, 2014 11:55 am
Contact:

Re: Client-side scripts to send custom events to sim; readfile()

Post by Zeblote »

ratchetfreak wrote: Also on the more technical side; the replay file must contain the file that was pulled in. That can cause the replay file to grow quite a bit if a mod is dumb and pulls a file every tick.
I see no reason for a mod to do that. If a file is needed regularly, it can be cached in lua.

Post Reply

Return to “Won't implement”