RE:NODE
Обзор хостинга

Руководства14 мин чтения

Factorio mods and UPS: what a megabase server costs

How mods get onto a Factorio server, why every client needs the same list, what really costs UPS, and how to measure a save with the headless benchmark flag.

Эта статья пока на английском. Мы её переводим.

0 прочтений

A Factorio server has one performance number and it is UPS: updates per second, target 60. Below 60 the game itself runs slow - conveyor belts move slower, furnaces smelt slower, the clock in the corner drifts behind real time - for everybody connected, and no amount of bandwidth or memory fixes it. UPS is decided by how long one simulation tick takes on one CPU core, and mods are the fastest way to make that tick longer. This post covers getting mods onto a headless server correctly, the rule that catches everyone (every client runs the identical list), what actually eats the tick budget, and how to measure a save instead of guessing.

UPS is the number that matters, not FPS#

Factorio runs its simulation at a fixed 60 updates per second. That gives the server 16.67 milliseconds to update every entity on every surface, once. If it finishes in 9 ms, the game runs at 60 UPS with headroom to spare. If it takes 22 ms, the game runs at roughly 45 UPS and everything in the world happens at three quarters of normal speed.

FPS is a separate, client-side number: how often your machine draws the world. A headless server has no renderer at all, so it has no FPS. This is the first thing to establish when somebody says the server is laggy, because the three common complaints have three different causes:

  • Everything is slow, for everyone, including the clock. That is UPS. The server cannot simulate fast enough.
  • My game stutters but the factory runs normally. That is client FPS, on their machine.
  • My character rubber-bands, other people look fine. That is their connection, not the server.

The same distinction runs through what tick rate actually means for other games. Factorio is unusual only in that the simulation rate and the game's sense of time are the same thing, so losing UPS is losing real speed rather than losing smoothness.

Because the update loop is effectively one thread, the only hardware that raises UPS is a faster core. Adding vCPU to a Factorio plan buys you headroom for saving, networking and the odd background task, and nothing else. This is the clearest case of the point made in CPU vs RAM for game servers: the two are not interchangeable and only one of them is your bottleneck.

Installing mods on a headless server#

Mods are zip files in the mods/ directory of the install, named exactly Name_Version.zip - Krastorio2_1.4.0.zip, not Krastorio2.zip or Krastorio2 (1).zip. The version in the file name must match the version inside the mod's info.json, because that is how Factorio resolves dependencies.

code
/opt/factorio/mods/  mod-list.json  mod-settings.dat  Krastorio2_1.4.0.zip  flib_0.15.0.zip  stdlib_1.4.6.zip

The headless build has no mod browser, so there are two practical routes. Download the zips from mods.factorio.com in a browser and upload them, or - the route that actually scales - build the mod list in a single-player game on your own machine, where the in-game manager resolves dependencies for you, and then copy the whole mods folder up. Uploading over SFTP or a file manager is the same job either way; SFTP and the file manager has the connection details if you have not done it before.

Dependencies are declared in each mod's info.json and the server refuses to start if one is missing, printing the name and version range it wanted. That error is the single most useful thing in the log during a mod install, so read it rather than reinstalling things at random. A leading ? in a dependency means optional, ! means incompatible, and ~ means the mod is required but does not affect load order.

Mods go in the same folder whichever host you are on. On RE:NODE the mods folder is there from the first boot and mods drop straight into it over SFTP or the in-browser file manager, which also unpacks archives in place.

mod-list.json, versions and mod-settings.dat#

mods/mod-list.json decides which of the zips present are actually loaded. It is written by the game and safe to edit by hand:

mods/mod-list.json
{  "mods": [    { "name": "base", "enabled": true },    { "name": "elevated-rails", "enabled": true },    { "name": "quality", "enabled": true },    { "name": "space-age", "enabled": true },    { "name": "flib", "enabled": true },    { "name": "Krastorio2", "enabled": false }  ]}

Two things to notice. base is a mod and is always in the list. And the Space Age expansion is delivered as three separate mods - space-age, quality and elevated-rails - which can be enabled independently, so a server can run elevated rails without the rest of it.

Disabling a mod here is not the same as deleting the zip. Disabled mods are still checked for version conflicts on start but are not loaded. Deleting a content mod that a save already uses is a different and much more dangerous operation, covered below.

mods/mod-settings.dat holds every mod's settings. It is a binary file, so you cannot edit it with a text editor, and the headless server has no settings GUI. The only sane way to change a startup setting is to load the identical mod set in a single-player game on your own machine, set everything there, and upload the resulting mod-settings.dat. Runtime-global settings can be changed in game by an admin; startup settings cannot be changed at all without a restart, because they alter prototypes.

Mod sync, desyncs and the identical-list rule#

Factorio has no concept of a client-side-only mod. Every mod is part of the simulation - even one that only adds a GUI runs Lua that all machines must run identically - so the server and every client must have the same mods at the same versions, with the same startup settings. The game enforces this: a mismatch is refused at the join, with a list of what differs.

That sounds worse than it is, because the client will fix it for you. When a player joins a modded server the game offers to download and enable exactly what the server has, straight from the official mod portal, and to disable anything extra. The two cases where that fails are mods that are not published on the portal - a personal script, a mod pulled from a GitHub release - and mods that were removed from the portal after you installed them. Those must be distributed by hand.

Desyncs are the other side of determinism. If one machine's simulation diverges from the server's, Factorio detects it, drops that client, writes a desync report and makes them re-download the map. In vanilla this is rare enough to be a bug worth reporting. With mods it is usually a mod doing something non-deterministic, and the game will often tell you so plainly in the log - calling math.random() outside an event, for example, is invalid precisely because different machines would get different numbers.

If a particular mod desyncs one player repeatedly, the useful information is in the desync report the game writes, and the mod's author is the person who can read it. What you can do from the server side is make sure everyone is on the same mod versions, and stop the mods updating underneath you - which is the argument for pinning them, below.

What actually costs UPS#

The tick budget is spent almost entirely on updating active entities. Anything asleep is nearly free; Factorio is aggressive about putting idle inserters, machines and belts to sleep. So the question is never "how big is my base" but "how many things are doing something every tick".

CostWhyWhat helps
Logistic robotsEach flying bot updates every tick, plus chargingBelts or direct insertion at scale
RadarsContinuous sector scanning, per radarKeep two or three, not thirty
CombinatorsEach one updates every tick, alwaysClocks and latches instead of per-tick maths
Biters and pollutionDiffusion per chunk, pathfinding on attackFewer, larger walls; reduce expansion
TrainsCheap while rolling, expensive when repathingFewer, longer trains; simpler junctions
Entity count generallyEverything above, multipliedBeacons and modules, so fewer machines do more
Extra surfacesEvery surface is simulated, all the timeDo not keep dead platforms or unused planets

Three of these deserve more than a table row.

Bots versus belts. A logistics network that moves a thousand items a second with bots is doing far more work per tick than a set of belts moving the same thing, because each bot is an individual entity with a position and a charge state, and belts use a highly optimised transport-line representation where a compressed run of items is close to free. Bots are wonderful for construction, for low-throughput logistics and for anything irregular. They are the wrong tool for a main bus. Direct insertion - machine to machine, no belt and no bot at all - is cheaper than either.

Beacons and productivity. The cheapest entity is the one that does not exist. Twenty beaconed assemblers producing what eighty unbeaconed ones would is not just a space saving; it is sixty fewer entity updates, sixty fewer inserters and a shorter belt network. This is why megabases look the way they do.

Mod Lua. A mod that registers a handler on the per-tick event and does real work in it pays that cost sixty times a second forever, on top of the entities it adds. Overhaul packs are usually well written about this; small convenience mods are the ones that quietly cost 2 ms a tick. The benchmark below will tell you which, because you can run the same save with and without a mod.

Measuring it with the benchmark flag#

Guessing is a waste of an afternoon. The headless build can run a save as fast as the CPU allows, with no clients and no rendering, and report how long a tick took:

bash
$ cd /opt/factorio$ ./bin/x64/factorio --benchmark ./saves/world.zip \    --benchmark-ticks 2000 --benchmark-runs 3 \    --benchmark-verbose all --mod-directory ./mods

--benchmark-ticks is how many ticks to simulate, --benchmark-runs repeats the whole thing so you can see the variance, and --benchmark-verbose all adds the per-system breakdown: entity update, transport lines, circuit network, trains, electric network, fluids, robots and the rest. --mod-directory lets you point at a different mods folder, which is exactly how you test "what does this mod cost me" - benchmark the save twice, with two folders.

Read the average milliseconds per tick against the 16.67 ms budget. Under 10 ms is comfortable. Between 12 and 16 ms the server will hold 60 UPS on a quiet machine and drop below it when something else on the box is busy. Over 16.67 ms the game is already running slow.

Two caveats. A benchmark runs the save deterministically forwards, so it measures the factory rather than the players; twelve people opening map view and placing blueprints add work it will not see. And a benchmark on your own desktop tells you about your desktop's CPU, not the server's. Run it on the machine that will host the map if you can - the panel console will take the command, because it is the same binary.

In the graphical client, F4 opens the debug settings and F5 toggles the debug overlay, where the time usage panel gives you the same per-system breakdown live. Connected to a multiplayer game, that shows your own machine's work, but the UPS figure is the shared one.

Overhaul packs, Space Age and memory#

Big mod packs change the sizing conversation entirely. Krastorio 2, Bob's and Angel's, Industrial Revolution 3, Pyanodons and the various space overhauls all add prototypes, recipes and often whole new surfaces. The effect on a server is threefold: the game takes longer to load at start, memory use goes up permanently, and the tick gets more expensive per entity because there are more entity types in play.

Space Age is the official version of this. Every planet you settle is another surface, simulated whenever anything on it is active, and a platform in transit is another one again. A five-surface Space Age game is closer to running five servers than one, and 4-6 GB is a realistic figure rather than a generous one.

Memory behaves differently from UPS and people mix the two up. More memory does not raise your update rate. What it buys is the ability to hold a bigger map, more surfaces and more mod prototypes without the container being stopped at its limit. Factorio also needs more memory momentarily while saving than while running, which is why a server that is fine for an hour dies exactly on an autosave. On RE:NODE hitting the memory limit stops the container and restarts it clean rather than letting it swap, which is the right behaviour for a game like this - but a restart mid-tick costs you everything since the last autosave, so it is worth sizing above the peak rather than at it. When to upgrade your plan is the general version of that judgement.

Before committing a long run to a pack, check which game version it supports. The 2.0 rewrite broke a great many mods and some large packs took a long time to come back; a map started on a mod that is then abandoned is a map you cannot update.

Getting UPS back on a slowing server#

In rough order of how much they return for the effort:

  1. Benchmark first. Find out which system is expensive before changing anything. Half of all Factorio "optimisation" is aimed at the wrong subsystem.
  2. Delete surplus radars. A handful of radars covering the base is fine. Thirty spread across the map for visibility is a real cost with no gameplay value; use map pings and a few scouted chunks instead.
  3. Cut idle bots. Look at the logistics network tab: bots that are permanently in the air are the expensive ones. Reducing the number of roboports in a network, or replacing a high-throughput bot link with a belt, moves the needle.
  4. Turn off what you do not use. Disable enemy expansion in map-settings.json, or go peaceful, if the biter game is not the point of your run. Pollution diffusion and pathfinding are genuinely expensive on a large polluted map.
  5. Beacon and module the big production blocks. Fewer machines doing more is the structural fix.
  6. Look at combinator spaghetti. Per-tick arithmetic across hundreds of combinators adds up. Gate it behind a clock.
  7. Restart the server weekly. Not a UPS fix, but it keeps memory flat and gives you a clean save point. The Schedules tab can do it - see restart schedules that help.

And then stop. A server sitting at 60 UPS with 6 ms to spare does not need optimising, and rebuilding a working base for a number nobody can perceive is how groups lose interest in a map. Optimise when the clock drifts, not before.

If UPS is fine but the server still feels wrong, the problem is elsewhere: a noisy neighbour on shared hardware, a network path with jitter, or a client that cannot keep up. Shared CPU and noisy neighbours covers the first, and latency, jitter and packet loss the second.

Updating mods without breaking the save#

Mods on the portal update whenever their authors publish, and there is no dependency lock file. On a server that matters, treat the mods folder as pinned state:

  1. Take a backup of the save and a copy of the whole mods folder before touching anything. A backup nobody has restored is a hypothesis, so restore one occasionally - backups that actually restore makes the case at length.
  2. Update one mod at a time when you can, and read its changelog for migration notes.
  3. Start the server and watch the log through the load. Migration scripts run once, on the first load after an update, and errors there are the ones that corrupt a save.
  4. Tell players to sync from the server rather than updating from the portal themselves, so the versions cannot drift apart.

When a mod update does break the map, the fix is almost always to put the old zip back, not to remove the mod. What to do when a mod update breaks has the full procedure, and keeping a modded server clean covers the hygiene that stops you needing it.

FAQ#

How many mods can a Factorio server run?

There is no limit and the count is the wrong measure. Fifty small quality-of-life mods can cost less than one overhaul pack. What matters is how many entities the resulting map has and how much Lua runs every tick, which the benchmark flag will tell you in a minute.

Why is my server at 45 UPS when the CPU graph shows 40%?

Because the graph is averaging across cores. Factorio uses one of them for the simulation, and that one is at 100%. A four-core allocation with a single-threaded workload will always look under-used while being completely saturated.

Do players need to install the mods themselves?

No, as long as the mods are on the official portal. On joining, the client offers to download and enable exactly what the server runs and disable anything extra. Mods from outside the portal have to be sent to players by hand.

Can I add a mod to a map that is already running?

Adding is usually safe; removing is not. A new mod's content simply appears. Removing one deletes every entity it provided, permanently. Back the save up before either, and never remove an overhaul pack from a live map.

Does more RAM increase UPS?

No. Memory lets the server hold a bigger map without being killed; it does not make a tick shorter. Only a faster CPU core, or a cheaper factory, does that.

What is a realistic UPS target for a big base?

Sixty, and you should design to stay there. Serious megabasers accept less because they are chasing a production figure, but for a group playing together the moment the clock slows down the game stops feeling right, so treat 60 UPS as the constraint and build within it.


Комментарии

Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.

0/2000