Computer Core

by Relik77

Computer is a modification for Factorio that’s all about computer programming. It allows you to write programs using the Lua programming language.

Utilities
6 years ago
0.15 - 0.16
21

i A bunch of requests

6 years ago
(updated 6 years ago)

As far as I can tell, there's no way to write to or read from files within scripts. I feel like this should already exist, but can't find it in any of the ingame documentation or even in the mods code. Am I just being dumb? If not, i'd love for it to be added. Perhaps an api "disk" with functions for read, write, append, export (which would write tables/variables in lua format that could be easily loaded), load (alias for os.require, sorta).

Global variables persisting between game reloads. If I have a script that declares a global variable, the script works fine with it, until I exit the save. Perhaps add a memory api ("mem" or "ram"?) that persists, similarly to how "global" does in factorio? Perhaps two apis: one which is scoped within the script, and is cleared when the script ends, and another which is persistent throughout the computers life?

Write text to specific part of the screen, plus other screen variables to support this. eg: term.writeAt(0, math.floor(term.height / 2), "This text would be vertically centered"). This would probably require a massive overhaul of how text is displayed though, and a fixed-width font would have to be used. If you decide to make this, colored text would be relatively easy to make as well.

Speaker API at specified position, so we can create icons in the map at any position. One use case: to show where a car is currently driving to.

Files saving into real directories. This would allow us to edit scripts in an external text editor, then load them ingame without having to copy paste the script in (which kinda work arounds the issue of newlines not being copied correctly). The directory could be based off of the computer's label, so if you picked up a computer then placed it elsewhere and set it to the same label, your files would persist.

Ability to print messages to the ingame chat log. Per force or per player, so that it can't be abused in pvp settings.

A way for one computer to tell another computer to run a script when they have just been placed (not within a script). This would help me to create a self expanding factory using recursive blueprints, where one computer places blueprints for another computer, then sets it to perform a task. I'm not sure how this could work without being abusable, but it's something I really need. Alternatively: blueprinted computers saving active script.

I think that's all for now. Great mod, but really needs some polish to make it exceptional.

Edit: Oh and you left a print in when os.require is called.

6 years ago
(updated 6 years ago)

Hello, I will try to answer all the points:

Disk API: ok, I will develop it ;-)


Global variables: Normally values should not be lost when reloading the game with a running script. However, your problem may be related to the ticket https://github.com/Relik77/factorio_computer_core/issues/1

Basically: I have no way to serialize a declared global variable with the keyword "local".
So I had to work around the problem by creating an api os.set("myVar1", a, b) and os.get("mayVar1")
Otherwise, you can simply set your variable without the keyword local, which saves it in the environment variable of the script (which is serialized)

For the second point, I can add apis to save persistent variables in the computer. On another side, with the Disk API this may not be necessary anymore?


Write text to a specific part of the screen / in color: For these points, I am limited by factorio apis. But I will look at what I can do.


Speaker API at specified position : I am going to look, the concern being that the icon works with a speaker entity and that its position is not editable once created (Factorio limitation).


Recording files in real directories: Again, I am limited by the tools made available by factorio :-/
Indeed, factorio does not allow a script to read a real file (only to write it)

NB: the problem of new lines that are not copied correctly has been solved in one of the last factorio update. (experimental version, however)

For the preservation of files in order to move a computer, you can use your "personal computer" (icon at the top left). The personal computer is linked to the character and you can copy files from one computer to another by placing a label on the target computer label set mycomputer, which mounts a "virtual disk" /mnt/mycomputer allowing you to use the commands cp and mv (ex: cp myfile /mnt/mycomputer/myfile)


Print message in chat log : ok, I will develop it.


A way for one computer to tell another computer to run a script : This is one of the points I had already considered developing, just not yet had the time to do it. So, yes, I'll go back to the question.
For the blueprint question, I'm not sure if I can do it


I saw, for the message and it was removed with the latest update of the script. (I was hoping that no one saw, this api was not necessarily very used ^^)

6 years ago
(updated 6 years ago)

Regarding serializing global variables: I took a closer look at it, and it's not a global variable that is becoming nil when I reload a game with an active script, its lan. I can consistently recreate the bug with a script, but it is a large script, so i'm unsure what the exact circumstance of it occurring is. I'll play around with it some more, and try to get a smaller script that recreates the issue, which I'll send to you (Edit: see bottom of post).
However, it does seem that global variables are being saved correctly. My bad.


As for saving the current script in a blueprint, take a look at the programmable structures mod. It supports blueprinting specific mod variables somehow (although it is only a series of booleans).
An alternative method, that I just thought of, is a script named "startup" or such, which exists on the wlan network, that gets executed (if it exists) whenever any computer is placed, before going into its normal command interface. That would allow me to set a label on new computers, and make them wait for a command through wlan that states what script to download and run. The ability to download files could be done with the disk and wlan apis.


For the os.require printing: seems like im a version or two out of date, my bad.


Edit: I was able to boil down the reloading bug to calling lan from within a global function. See the following script:

function readSignals()
lan.getRightSignals("red")
end

function tick()
readSignals()
os.wait(tick, 1)
end
tick()

This script will crash consistently.
1. Run script on a computer.
2. Save the game.
3. Load the save.

The exact error message is:
[string "function readSignals()..."]:2: attempt to index global 'lan' (a nil value)

Moving the "lan.getRightSignals" call to within the tick function prevents the crash.

I am running the latest version of the mod, factorio version 0.16.30.

6 years ago
(updated 6 years ago)

Version 1.3.4 available :
- Add DISK API: functions for file manipulation
- Add speaker.print API (Print your message to the ingame chat log)


For the bug when loading, I have not found a solution yet. It seems that Lua is losing the scope of global variables in functions defined outside the callback functions. So :

function readSignals()
  lan.getRightSignals("red")
end

function tick()
  readSignals()
  os.wait(tick, 1)
  end
tick()

Does not work :(

But:

function tick()
  function readSignals()
    lan.getRightSignals("red")
  end

  readSignals()
  os.wait(tick, 1)
  end
tick()

Work as well as :

-- main file:
function tick()
  os.require("readSignals")()
  os.wait(tick, 1)
  end
tick()


-- readSignals file
function readSignals()
  lan.getRightSignals("red")
end

return function()
  return readSignals()
end

I'm still working on "A way for one computer to tell another computer to run a script" (I currently have 3 or 4 implementation ideas, I have to choose which implementation to do according to the constraints and behavior that I want to create). May be available in the next update ;)

6 years ago

v1.3.5 Add a WLAN.onBuiltComputer API :

wlan.onBuiltComputer(function(event)
    term.write("wlan.onBuiltComputer", event)
    event.autorun(function()
        term.write("Hello World !")
    end)
end)

When creating a new computer, it will receive a startup script to execute (here it writes "Hello World!" On the terminal).
Startup script can be a function or a "text" program.

6 years ago
(updated 6 years ago)

Fantastic work. Time to automate playing factorio!

Has there been any progress with the lan being nil issue?

Edit: Im getting an error with the latest version when using os.require
computer_core/logic/computer.lua:463: attempt to index field 'file' (a nil value)

The error occurs whether or not the file exists, on new and old computers.

6 years ago
(updated 6 years ago)

From what I understand (after many tests), when calling a function (a) defined outside the callback function of asynchronous APIs, the execution environment of the function (a) is invalid.
This is probably due to a loss of data during the serialization of the script by factorio or a Lua limitation (or a risky implementation on my part, I'm not immune ^^)

To work around the problem, I just had the idea of an api os.pcall that will work as a pcall(load(string.dump(callback))) in order to regenerate the environment.
Description: os.pcall(callback, ...) - The os.pcall function calls its first argument in protected mode, so that it catches any errors while the function is running. If there are no errors, pcall returns true, plus any values returned by the call. Otherwise, it returns false, plus the error message.

So :

function readSignals(color)
  lan.getRightSignals()
end

function tick()
  readSignals("red")
  os.wait(tick, 1)
  end
tick()

would become:

function readSignals(color)
  lan.getRightSignals(color)
end

function tick()
  os.pcall(readSignals, "red")
  os.wait(tick, 1)
  end
tick()

Edit: The first tests seem conclusive :)

6 years ago

Not sure if you saw my last posts edit, but the os.require bug is still occuring on the latest version.

6 years ago

Indeed, I was missing this bug :/

v1.3.7 should fix the problem.

6 years ago
(updated 6 years ago)

Latest version now crashes as soon as I press Run, or use the run command, even with an empty script. Error is:
Error while running event computer_core::on_gui_click (ID 1)
computer_core/logic/computer.lua:649: attempt to call field '?' (a nil value)

6 years ago

sorry, new version available.

6 years ago
(updated 6 years ago)

Great work. All seems good so far.

Edit: Found another crash, when I try running a script that has a syntax error. Just a script like "aaaaaa" causes it. Error:
Error while running event computer_core::on_gui_click (ID 1)
computer_core/logic/computerCommands.lua:543: attempt to index local 'env' (a nil value)

6 years ago
(updated 6 years ago)

Another bug. It seems computers that are executing an autorun script don't register to wlan events until the GUI is opened. See the following script:

function tick()
    wlan.broadcast("TestMessage")

    os.wait(tick, 1)
end
tick()

wlan.onBuiltComputer(function(event)
    event.autorun(NewComputerAutorun)
end)

function NewComputerAutorun()
    term.write("NewComputerAutorun")

    wlan.on("TestMessage", function()
        term.write("TestMessage")

        wlan.broadcast("TestMessage_Received")
    end)
end

wlan.on("TestMessage_Received", function()
    term.write("TestMessage_Received")
end)

What I'd expect to happen is: when a new computer is placed, it prints "NewComputerAutorun" on the new computer. And every second after a new computer has been placed, it should print out "TestMessage" on the new computer, and "TestMessage_Received" on the first computer.

What happens is: "NewComputerAutorun" gets printed correctly (as far as I can tell), but no wlan messages are received on the new computers (and thus no other messages are printed) until I open the GUI for them, at which point everything works as expected.

I'll mess around with it, see if I can get it working somehow, but as far as I can tell this should work.

Also see my edit in the post above about a crash.

6 years ago

v1.3.9 should fix these 2 points.

6 years ago

Nice! Looks good so far. Loving the fast update time btw.

6 years ago

Welp, found another crash. I swear I'm not doing this on purpose. I deconstruction ordered some miners that had unsatisfied module requests. Error:

Error while running event computer_core::on_pre_ghost_deconstructed (ID 91)
Entity is not ghost.
stack traceback:
    __computer_core__/control.lua:413: in function <__computer_core__/control.lua:410>
6 years ago

For once it's not completely my fault, I add a listen of this event in order to be able to support the wires connections in blueprints and correctly remove the generated ghosts.
This event is supposed to be called by factorio only on ghosts entity (http://lua-api.factorio.com/latest/events.html#on_pre_ghost_deconstructed); but factorio call also this event for "ghosts module" without considering them as a ghosts entity...
<3 Factorio ^^
v1.3.10 work around this problem.

6 years ago
(updated 6 years ago)

"tree" is now crashing:

Error while running event computer_core::on_gui_text_changed (ID 2)
__computer_core__/logic/computer.lua:179: attempt to index global 'player' (a nil value)
6 years ago

I hope we will eventually get to a bugfree version (usually my programs are more reliable, I had to want to release the latest versions a bit too fast :/)
v1.3.11 done

6 years ago

It's been a while, but I'm not dead. I've been creating a core library for my computers, which is capable of detecting missing/outdated files and downloading them from a file server.
Haven't found any bugs with the latest version yet (although I've yet to test the pcall functionality, and I've been busy with work), just thought of a few more feature requests:

First, a way to iterate through all of the files on the system. Would make my automatic update system a bit easier to manage. Something like disk.FindFiles(folder, bool for searching subfolders), maybe a variant for finding folders (although I can't think of a specific use).

Second, a way for a script to end. Seems kind of silly, but I want an autorun script that checks the wlan network to see if it was placed automatically, or by a player. If it doesn't receive a response in x seconds, it assumes it was placed manually and automatically exits the script to let the player use it. os.exit() would make sense.

Third, support for executing strings. Like os.require, but just pass in a string and it gets executed. I'm pretty sure lua has a function for that, but the library it's in doesn't seem to exist in the computers. I tried finding it when os.require broke a few versions ago so I could work around it by reading the files myself. Other than that, can't think of a use case, but shouldn't be hard to implement.

Fourth, scroll bars in the text editor.

6 years ago

Hi,
I will look at what I can do.
- For points 1 and 2 it does not seem too complicated;
- For point 3 normally the native lua functions "load" and "pcall" are available;
- For the last point, I am limited by the interface implemented by factorio, but I will look;

New response