My initial approach was to convert the number I wanted to get out of the game (player life percent) to a binary representation in Lua and then call a function for every 1 and call a function for every 0.
This gets called every tick.
Code: Select all
...
function pushBits2flashlight(originalInt, bitArray)
dontcare = game.darkness -- reset signal
for cnt, bit in ipairs(bitArray) do
if bit == 0 then
game.player.disable_flashlight() -- send 0
elseif bit == 1 then
game.player.enable_flashlight() -- send 1
else
print("pushBits2flashlight: UNEXPECTED VALUE IN bitArray")
end
end
end
...
I would then run Factorio in GDB to register hooks when the breakpoint of the Lua function in the binary was hit. This example is valid for Factorio 0.12.33.
Code: Select all
break _ZN13LuaGameScript15luaReadDarknessEP9lua_State
commands
silent
shell /usr/local/bin/factorioHook r
continue
end
break _ZN10LuaControl20luaDisableFlashlightEP9lua_State
commands
silent
shell /usr/local/bin/factorioHook 0
continue
end
break _ZN10LuaControl19luaEnableFlashLightEP9lua_State
commands
silent
shell /usr/local/bin/factorioHook 1
continue
end
run
/usr/local/bin/factorioHook was just a shell script that wrote to a FIFO in /tmp that was created with a C program that was running as a local daemon.
This program would read the value from the FIFO, reassemble the Integer and then send it via UDP to the Raspberry Pi over UDP.
Code: Select all
...
for (;;) {
fifo = open(fifoNAME, O_RDONLY);
bytes = read(fifo, buf, 1);
close(fifo);
printf("Received (%d bytes): %s \n", bytes, buf);
if ( buf[0] == 'r' ) {
printf("RESET SIGNAL!\n");
i=0;
continue;
}
else if ( buf[0] != '0' && buf[0] != '1' ) {
printf("GOT FUCKED UP VALUE!\n");
continue;
}
strncpy(&intAssembling[i], buf, 1);
i++;
if (i >= 8) {
assembled = assembleINT(intAssembling);
// put tha shit on the wire
sprintf(udpBUF, "%d", assembled);
printf("Sending %d to Raspi!\n", assembled);
sendto(socke, udpBUF, strlen(udpBUF)/*+1*/, 0, (struct sockaddr*) &dest, (socklen_t) sizeof(struct sockaddr_in));
i = 0;
}
}
...
The Raspberry Pi was just running a trivial UDP server to listen for the value to display.
Code: Select all
...
def percent2strip(self, percent, col):
"""Light up 'percent' percent of the strip.
This value is between 0 and 100."""
leds2light = int(float(NUMBER_OF_PIXELS) * (float(percent)/100)) # calculate how many LEDs to light
print "Will light %d of %d LEDs (%d%%)" % (leds2light, NUMBER_OF_PIXELS, percent)
self.ledpixels = [color(0,0,0)]*(NUMBER_OF_PIXELS-leds2light) + [col]*leds2light
self.writeStrip(self.ledpixels)
...
This was a lot of nasty hacking, a lot too much because the game was lagging at 12 FPS on my new Laptop.
The next thing I found out after registering hooks on breakpoints for the Factorio binary was that
game.write_file() exists
xD
This made it far easier because now all I needed to do was write the Integer value to a file in the script-output/ folder and read that file from my local C daemon, no binary calculation, GDB debugging or FIFO required anymore; it also runs at 60 FPS now ^^
In the end I did a lot of redudant work but still learned a lot about debugging and Linux binary formats as well as 64 Linux calling conventions (my very first approach was to rewrite the functions for the Lua functions in the Linux binary...^^).
But now it works and I can finally put my LED strip to good use.
Maybe I will clean up the source code and release it so everyone with Raspberry Pi and a WS2801 LED strip can use it (also not using GDB anymore improved the practicability by a great bit).