games/factorio: make more configurable

This makes the server fully configurable, and adds the contents of
example JSON configs as the defaults for all servers.

Change-Id: I8ff3e66a586a9db3acb9721810c8c5aa13072b4b
diff --git a/games/factorio/kube/config/map-gen-settings.libsonnet b/games/factorio/kube/config/map-gen-settings.libsonnet
new file mode 100644
index 0000000..18612f3
--- /dev/null
+++ b/games/factorio/kube/config/map-gen-settings.libsonnet
@@ -0,0 +1,81 @@
+{
+    // The following options are defaults taken verbatim from Factorio 1.1.35
+    // headless' map-gen-settings.example.json, with the following changes:
+    //  - field names unquoted where possible
+    //  - pseudo-comments converted to jsonnet comments
+    //  - comments reflowed to fit 80 columns
+
+    // The inverse of 'water scale' in the map generator GUI.
+    terrain_segmentation: 1,
+
+    // The equivalent to 'water coverage' in the map generator GUI. Higher
+    // coverage means more water in larger oceans.
+    // Water level = 10 * log2(this value)
+    water: 1,
+
+    // Width and height of map, in tiles; 0 means infinite
+    width: 0,
+    height: 0,
+
+    // Multiplier for 'biter free zone radius'
+    starting_area: 1,
+
+    peaceful_mode: false,
+    autoplace_controls: {
+      "coal": {"frequency": 1, "size": 1, "richness": 1},
+      "stone": {"frequency": 1, "size": 1, "richness": 1},
+      "copper-ore": {"frequency": 1, "size": 1,"richness": 1},
+      "iron-ore": {"frequency": 1, "size": 1, "richness": 1},
+      "uranium-ore": {"frequency": 1, "size": 1, "richness": 1},
+      "crude-oil": {"frequency": 1, "size": 1, "richness": 1},
+      "trees": {"frequency": 1, "size": 1, "richness": 1},
+      "enemy-base": {"frequency": 1, "size": 1, "richness": 1}
+    },
+
+    cliff_settings:
+    {
+      // Name of the cliff prototype
+      name: "cliff",
+
+      // Elevation of first row of cliffs
+      cliff_elevation_0: 10,
+
+      // Elevation difference between successive rows of cliffs.
+      // This is inversely proportional to 'frequency' in the map generation
+      // GUI. Specifically, when set from the GUI the value is 40 / frequency.
+      cliff_elevation_interval: 40,
+
+      // Called 'cliff continuity' in the map generator GUI. 0 will result in
+      // no cliffs, 10 will make all cliff rows completely solid
+      richness: 1
+    },
+
+    // Overrides for property value generators (map type)
+    // Leave 'elevation' blank to get 'normal' terrain.
+    // Use 'elevation': '0_16-elevation' to reproduce terrain from 0.16.
+    // Use 'elevation': '0_17-island' to get an island.
+    // Moisture and terrain type are also controlled via this.
+    property_expression_names:
+    {
+      // 'control-setting:moisture:frequency:multiplier' is the inverse of the
+      // 'moisture scale' in the map generator GUI.
+      "control-setting:moisture:frequency:multiplier": "1",
+      // 'control-setting:moisture:bias' is the 'moisture bias' in the map
+      // generator GUI.
+      "control-setting:moisture:bias": "0",
+      // 'control-setting:aux:frequency:multiplier' is the inverse of the
+      // 'terrain type scale' in the map generator GUI.
+      "control-setting:aux:frequency:multiplier": "1",
+      // 'control-setting:aux:bias' is the 'terrain type bias' in the map
+      // generator GUI
+      "control-setting:aux:bias": "0"
+    },
+
+    starting_points:
+    [
+      { x: 0, y: 0}
+    ],
+
+    // Use null for a random seed, number for a specific seed.
+    seed: null
+}
diff --git a/games/factorio/kube/config/map-settings.libsonnet b/games/factorio/kube/config/map-settings.libsonnet
new file mode 100644
index 0000000..458a348
--- /dev/null
+++ b/games/factorio/kube/config/map-settings.libsonnet
@@ -0,0 +1,126 @@
+{
+    // The following options are defaults taken verbatim from Factorio 1.1.35
+    // headless' map-settings.example.json, with the following changes:
+    //  - field names unquoted where possible
+    //  - pseudo-comments converted to jsonnet comments
+    //  - comments reflowed to fit 80 columns
+
+    difficulty_settings:
+    {
+      recipe_difficulty: 0,
+      technology_difficulty: 0,
+      technology_price_multiplier: 1,
+      research_queue_setting: "after-victory"
+    },
+    pollution:
+    {
+      enabled: true,
+      // these are values for 60 ticks (1 simulated second)
+      // amount that is diffused to neighboring chunk
+      diffusion_ratio: 0.02,
+      min_to_diffuse: 15,
+      ageing: 1,
+      expected_max_per_chunk: 150,
+      min_to_show_per_chunk: 50,
+      min_pollution_to_damage_trees: 60,
+      pollution_with_max_forest_damage: 150,
+      pollution_per_tree_damage: 50,
+      pollution_restored_per_tree_damage: 10,
+      max_pollution_to_restore_trees: 20,
+      enemy_attack_pollution_consumption_modifier: 1
+    },
+    enemy_evolution:
+    {
+      enabled: true,
+      time_factor: 0.000004,
+      destroy_factor: 0.002,
+      pollution_factor: 0.0000009
+    },
+    enemy_expansion:
+    {
+      enabled: true,
+      min_base_spacing: 3,
+      max_expansion_distance: 7,
+      friendly_base_influence_radius: 2,
+      enemy_building_influence_radius: 2,
+      building_coefficient: 0.1,
+      other_base_coefficient: 2.0,
+      neighbouring_chunk_coefficient: 0.5,
+      neighbouring_base_chunk_coefficient: 0.4,
+      max_colliding_tiles_coefficient: 0.9,
+      settler_group_min_size: 5,
+      settler_group_max_size: 20,
+      min_expansion_cooldown: 14400,
+      max_expansion_cooldown: 216000
+    },
+    unit_group:
+    {
+      min_group_gathering_time: 3600,
+      max_group_gathering_time: 36000,
+      max_wait_time_for_late_members: 7200,
+      max_group_radius: 30.0,
+      min_group_radius: 5.0,
+      max_member_speedup_when_behind: 1.4,
+      max_member_slowdown_when_ahead: 0.6,
+      max_group_slowdown_factor: 0.3,
+      max_group_member_fallback_factor: 3,
+      member_disown_distance: 10,
+      tick_tolerance_when_member_arrives: 60,
+      max_gathering_unit_groups: 30,
+      max_unit_group_size: 200
+    },
+    steering:
+    {
+      default:
+      {
+        radius: 1.2,
+        separation_force: 0.005,
+        separation_factor: 1.2,
+        force_unit_fuzzy_goto_behavior: false
+      },
+      moving:
+      {
+        radius: 3,
+        separation_force: 0.01,
+        separation_factor: 3,
+        force_unit_fuzzy_goto_behavior: false
+      }
+    },
+    path_finder:
+    {
+      fwd2bwd_ratio: 5,
+      goal_pressure_ratio: 2,
+      max_steps_worked_per_tick: 100,
+      max_work_done_per_tick: 8000,
+      use_path_cache: true,
+      short_cache_size: 5,
+      long_cache_size: 25,
+      short_cache_min_cacheable_distance: 10,
+      short_cache_min_algo_steps_to_cache: 50,
+      long_cache_min_cacheable_distance: 30,
+      cache_max_connect_to_cache_steps_multiplier: 100,
+      cache_accept_path_start_distance_ratio: 0.2,
+      cache_accept_path_end_distance_ratio: 0.15,
+      negative_cache_accept_path_start_distance_ratio: 0.3,
+      negative_cache_accept_path_end_distance_ratio: 0.3,
+      cache_path_start_distance_rating_multiplier: 10,
+      cache_path_end_distance_rating_multiplier: 20,
+      stale_enemy_with_same_destination_collision_penalty: 30,
+      ignore_moving_enemy_collision_distance: 5,
+      enemy_with_different_destination_collision_penalty: 30,
+      general_entity_collision_penalty: 10,
+      general_entity_subsequent_collision_penalty: 3,
+      extended_collision_penalty: 3,
+      max_clients_to_accept_any_new_request: 10,
+      max_clients_to_accept_short_new_request: 100,
+      direct_distance_to_consider_short_request: 100,
+      short_request_max_steps: 1000,
+      short_request_ratio: 0.5,
+      min_steps_to_check_path_find_termination: 2000,
+      start_to_goal_cost_multiplier_to_terminate_path_find: 500.0,
+      overload_levels: [0, 100, 500],
+      overload_multipliers: [2, 3, 4],
+      negative_path_cache_delay_interval: 20
+    },
+    max_failed_behavior_count: 3
+}
diff --git a/games/factorio/kube/config/server-settings.libsonnet b/games/factorio/kube/config/server-settings.libsonnet
new file mode 100644
index 0000000..876ec85
--- /dev/null
+++ b/games/factorio/kube/config/server-settings.libsonnet
@@ -0,0 +1,91 @@
+{
+    // The following options are defaults taken verbatim from Factorio 1.1.35
+    // headless' server-settings.example.json, with the following changes:
+    //  - field names unquoted where possible
+    //  - pseudo-comments converted to jsonnet comments
+    //  - comments reflowed to fit 80 columns
+
+    name: "Name of the game as it will appear in the game listing",
+    description: "Description of the game that will appear in the listing",
+    tags: ["game", "tags"],
+
+    // Maximum number of players allowed, admins can join even a full server. 0
+    // means unlimited.
+    max_players: 0,
+    
+    visibility:
+    {
+      // Game will be published on the official Factorio matching server
+      public: true,
+      // Game will be broadcast on LAN
+      lan: true,
+    },
+    
+    // Your factorio.com login credentials. Required for games with visibility
+    // public
+    username: "",
+    password: "",
+    
+    // Authentication token. May be used instead of 'password' above.
+    token: "",
+    
+    game_password: "",
+    
+    // When set to true, the server will only allow clients that have a valid
+    // Factorio.com account
+    require_user_verification: true,
+    
+    // optional, default value is 0. 0 means unlimited.
+    max_upload_in_kilobytes_per_second: 0,
+    
+    // optional, default value is 5. 0 means unlimited.
+    max_upload_slots: 5,
+    
+    // optional one tick is 16ms in default speed, default value is 0.
+    // 0 means no minimum.
+    minimum_latency_in_ticks: 0,
+    
+    // Players that played on this map already can join even when the max
+    // player limit was reached.
+    ignore_player_limit_for_returning_players: false,
+    
+    // possible values are, true, false and admins-only
+    allow_commands: "admins-only",
+    
+    // Autosave interval in minutes
+    autosave_interval: 10,
+    
+    // server autosave slots, it is cycled through when the server autosaves.
+    autosave_slots: 5,
+    
+    // How many minutes until someone is kicked when doing nothing, 0 for
+    // never.
+    afk_autokick_interval: 0,
+    
+    // Whether should the server be paused when no players are present.
+    auto_pause: true,
+    
+    only_admins_can_pause_the_game: true,
+    
+    // Whether autosaves should be saved only on server or also on all
+    // connected clients. Default is true.
+    autosave_only_on_server: true,
+    
+    // Highly experimental feature, enable only at your own risk of losing your
+    // saves. On UNIX systems, server will fork itself to create an autosave.
+    // Autosaving on connected Windows clients will be disabled regardless of
+    // autosave_only_on_server option.
+    non_blocking_saving: false,
+    
+    // Long network messages are split into segments that are sent over
+    // multiple ticks. Their size depends on the number of peers currently
+    // connected. Increasing the segment size will increase upload bandwidth
+    // requirement for the server and download bandwidth requirement for
+    // clients. This setting only affects server outbound messages. Changing
+    // these settings can have a negative impact on connection stability for
+    // some clients.
+    minimum_segment_size: 25,
+    minimum_segment_size_peer_count: 20,
+    maximum_segment_size: 100,
+    maximum_segment_size_peer_count: 10,
+}
diff --git a/games/factorio/kube/factorio.libsonnet b/games/factorio/kube/factorio.libsonnet
index 57d5bf4..7d08ad7 100644
--- a/games/factorio/kube/factorio.libsonnet
+++ b/games/factorio/kube/factorio.libsonnet
@@ -17,6 +17,42 @@
         rconPort: 2137,
         rconPassword: "farts",
 
+        // Configuration options that will get serialized into
+        // --config config.ini
+        factorioConfig: {
+            // There is no documentation for this file, but you can check
+            // config.ini in any installed Factorio data directory for a
+            // sample.
+            //
+            // This uses std.manifestIni, so to create a file containing:
+            //   version=9
+            //   [other]
+            //   verbose-logging=true
+            // You would set the following:
+            // main: {
+            //   version: "9",
+            // },
+            // other: {
+            //   "verbose-logging": "true",
+            // },
+        },
+        // Configuration options that will get serialized into
+        // --server-settings server-settings.json.
+        serverSettings: (import "config/server-settings.libsonnet") {
+            visibility+: {
+              public: false,
+              lan: false,
+            },
+        },
+        // Configuration options that will get serialized into
+        // --map-settings map-settings.json.
+        mapSettings: (import "config/map-settings.libsonnet") {
+        },
+        // Configuration options that will get serialized into
+        // --map-gen-settings map-gen-settings.json.
+        mapGenSettings: (import "config/map-gen-settings.libsonnet") {
+        },
+
         tag: "latest",
         image: "registry.k0.hswaw.net/q3k/factorio:" + cfg.tag,
         resources: {
@@ -78,6 +114,9 @@
                 "mod { name: \"%s\" version: \"%s\" }" % [m.name, m.version],
                 for m in cfg.mods
             ]),
+            "server-settings.json": std.manifestJson(cfg.serverSettings),
+            "map-settings.json": std.manifestJson(cfg.mapSettings),
+            "map-gen-settings.json": std.manifestJson(cfg.mapGenSettings),
         },
     },
 
@@ -115,6 +154,9 @@
                                 "/entrypoint.sh",
                                 "--rcon-port", std.toString(cfg.rconPort),
                                 "--rcon-password", cfg.rconPassword,
+                                "--server-settings", "/factorio/config/server-settings.json",
+                                "--map-settings", "/factorio/config/map-settings.json",
+                                "--map-gen-settings", "/factorio/config/map-gen-settings.json",
                             ],
                             ports_: {
                                 client: { containerPort: 34197 },
@@ -123,6 +165,7 @@
                             volumeMounts_: {
                                 data: { mountPath: "/data" },
                                 mods: { mountPath: "/factorio/mods" },
+                                config: { mountPath: "/factorio/config" },
                             },
                             resources: cfg.resources,
                         },