set up tstl factorio mod, and auto deploy stuff. A bit of mucking around with kotlin/js & dukat but it didn't go anywhere. Add a license.

This commit is contained in:
Adam 2021-10-13 21:29:21 +02:00
parent fb80ca3f79
commit 17b4fc3b9a
47 changed files with 32006 additions and 112 deletions

24
LICENSE Normal file
View file

@ -0,0 +1,24 @@
COPYRIGHT (C) LIMITED USE SOFTWARE LICENSE AGREEMENT
All rights are reserved by the copyright holder.
Permission is granted to use this software as a Factorio mod.
Permission is granted distribute this software under the
condition that the distribution is publicly accessible,
and no payment or registration is required. Additionally,
all distributions must include the full source code of the
software, without restrictions or limitations.
Permission is granted to make modifications to this software
under the condition that any claim of ownership is
relinquished, and any modification becomes the property of
the original copyright holder of this software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information contact fredthedeadhead@gmail.com

View file

@ -4,11 +4,11 @@ plugins {
base base
} }
group = rootProject.group.toString() + "." + project.name group = "${rootProject.group}.${project.name}"
version = rootProject.version version = rootProject.version
val projectId by extra(rootProject.name + "-" + project.name) val projectId by extra("${rootProject.name}-${project.name}")
val modBuildDir by extra(layout.buildDirectory.dir(projectId).get()) //val modBuildDir by extra(layout.buildDirectory.dir(projectId).get())
//group = "dev.adamko.factoriowebmap" //group = "dev.adamko.factoriowebmap"
//version = "0.0.1" //version = "0.0.1"

View file

@ -12,10 +12,11 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
plugins { plugins {
kotlin("js") kotlin("js")
id("com.github.node-gradle.node") id("dev.adamko.factoriowebmap.archetype.node")
id("dev.adamko.factoriowebmap.archetype.base")
} }
kotlin { kotlin {
js(IR) { js(IR) {
@ -47,16 +48,18 @@ val rootPackageJson by rootProject.tasks.getting(RootPackageJsonTask::class)
//fun NpmTask.setNodeModulesPath(folder: File): Unit = //fun NpmTask.setNodeModulesPath(folder: File): Unit =
// setNodeModulesPath(folder.normalize().absolutePath) // setNodeModulesPath(folder.normalize().absolutePath)
// https://github.com/node-gradle/gradle-node-plugin/issues/150
// https://github.com/lamba92/kotlingram/blob/master/examples/js-bot/build.gradle.kts
val nodePath: Directory by extra { val nodePath: Directory by extra {
val file = rootPackageJson.rootPackageJson.parentFile.normalize() val file = rootPackageJson.rootPackageJson.parentFile.normalize()
logger.lifecycle("Found root NODE_PATH: $file") logger.lifecycle("Kotlin/JS NODE_PATH: $file")
project.layout.dir(provider { file }).get() project.layout.dir(provider { file }).get()
} }
val nodeModulesDir: Directory by extra { val nodeModulesDir: Directory by extra {
val file = nodePath.dir(NpmProject.NODE_MODULES) val file = nodePath.dir(NpmProject.NODE_MODULES)
logger.lifecycle("Found root NODE_MODULES: $file") logger.lifecycle("Kotlin/JS NODE_MODULES: $file")
file file
} }
@ -66,7 +69,7 @@ node {
distBaseUrl.set(null as String?) // set by dependencyResolutionManagement distBaseUrl.set(null as String?) // set by dependencyResolutionManagement
nodeProjectDir.set(nodePath) // nodeProjectDir.set(nodePath)
// nodeProjectDir.set(packageJson.packageJson.parentFile.normalize()) // nodeProjectDir.set(packageJson.packageJson.parentFile.normalize())
} }

View file

@ -0,0 +1,23 @@
package dev.adamko.factoriowebmap.archetype
import org.gradle.kotlin.dsl.kotlin
import com.github.gradle.node.npm.task.NpmTask
import com.github.gradle.node.task.NodeTask
import org.jetbrains.kotlin.gradle.targets.js.dukat.DtsResolver
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
plugins {
id("com.github.node-gradle.node")
id("dev.adamko.factoriowebmap.archetype.base")
}
node {
download.set(true)
version.set("14.18.0")
distBaseUrl.set(null as String?) // set by dependencyResolutionManagement
}

View file

@ -1,28 +1,22 @@
import com.github.gradle.node.npm.task.NpmTask import com.github.gradle.node.npm.task.NpmTask
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
plugins { plugins {
base id("dev.adamko.factoriowebmap.archetype.node")
id("com.github.node-gradle.node")
} }
group = "${rootProject.group}.mod" val projectId: String by project.extra
version = rootProject.version
val tsSrcDir = layout.projectDirectory.dir("src/main/typescript")
val modBuildDir = layout.buildDirectory.dir(projectId).get()
node { node {
download.set(true) nodeProjectDir.set(tsSrcDir)
version.set("14.18.0")
nodeProjectDir.set(layout.projectDirectory.dir("src"))
distBaseUrl.set(null as String?) // set root dependencyResolutionManagement
} }
val projectId = rootProject.name + "-" + project.name val tstlTask = tasks.register<NpmTask>("typescriptToLua") {
val modBuildDir = layout.buildDirectory.dir(projectId).get()
//val tsSrcDir = layout.projectDirectory.dir("src")
val tstlTask = tasks.register<NpmTask>("tstl") {
description = "Typescript To Lua" description = "Typescript To Lua"
group = projectId group = projectId
@ -30,15 +24,25 @@ val tstlTask = tasks.register<NpmTask>("tstl") {
execOverrides { standardOutput = System.out } execOverrides { standardOutput = System.out }
npmCommand.set(listOf("run", "build")) npmCommand.set(listOf(
"run",
"build",
// "--workspace=factorio-web-map-mod",
))
val outputDir = modBuildDir.dir("tstl") inputs.dir(node.nodeProjectDir)
args.set(parseSpaceSeparatedArgs("-- --outDir $outputDir"))
val outputDir = modBuildDir.dir("typescriptToLua")
outputs.dir(outputDir) outputs.dir(outputDir)
args.set(parseSpaceSeparatedArgs("-- --outDir $outputDir"))
// args.set(listOf(
// "--",
// "--outDir $outputDir",
// "--workspace=factorio-web-map-mod",
// ))
ignoreExitValue.set(false) ignoreExitValue.set(false)
// workingDir.set(tsSrcDir.asFile) // workingDir.set(tsSrcDir.asFile)
inputs.dir(node.nodeProjectDir)
// inputs.dir("node_modules") // inputs.dir("node_modules")
// inputs.dir(fileTree("src")) // inputs.dir(fileTree("src"))
// inputs.files( // inputs.files(
@ -56,18 +60,62 @@ val modPackageTask = tasks.register<Zip>("package") {
dependsOn(tstlTask) dependsOn(tstlTask)
from(layout.projectDirectory.dir("src")) { from(
exclude("*.ts") layout.projectDirectory.dir("src/main/resources/mod-data"),
into(rootProject.name) rootProject.layout.projectDirectory.file("LICENSE"),
} tstlTask,
from(tstlTask) { )
into(rootProject.name)
}
into(rootProject.name)
// Factorio required format is:
// - filename: `mod-name_version.zip`
// - zip contains dir `mod-name`
archiveFileName.set("${rootProject.name}_${rootProject.version}.zip") archiveFileName.set("${rootProject.name}_${rootProject.version}.zip")
destinationDirectory.set(modBuildDir.dir("dist")) destinationDirectory.set(modBuildDir.dir("dist"))
} }
tasks.build { dependsOn(tstlTask, modPackageTask) } //tasks.build { dependsOn(tstlTask, modPackageTask) }
val copyModToServerTask = tasks.register<Copy>("copyModToServer") {
description = "Copy the mod to the Factorio Docker server"
group = projectId
dependsOn(modPackageTask)
from(modPackageTask)
into(layout.projectDirectory.dir("src/test/resources/server/data/mods").asFile)
}
val copyModToClientTask = tasks.register<Copy>("copyModToClient") {
description = "Copy the mod to the Factorio client"
group = projectId
dependsOn(modPackageTask)
from(modPackageTask)
into("""D:\Users\Adam\AppData\Roaming\Factorio\mods""")
}
val serverRestartTask = tasks.register<Exec>("serverRestart") {
group = projectId
workingDir = layout.projectDirectory.dir("src/test/resources/server/").asFile
commandLine = parseSpaceSeparatedArgs("docker-compose restart")
}
tasks.register<Exec>("serverStop") {
group = projectId
workingDir = layout.projectDirectory.dir("src/test/resources/server/").asFile
commandLine = parseSpaceSeparatedArgs("docker-compose stop")
}
val launch = tasks.register("modLauncher") {
group = projectId
dependsOn(
copyModToServerTask,
copyModToClientTask,
serverRestartTask,
)
}

View file

@ -1,19 +0,0 @@
script.on_event(
[defines.events.on_pre_build, defines.events.on_player_dropped_item],
(e: OnPreBuildEvent | OnPlayerDroppedItemEvent) => {
game.print("player " + e.player_index + " dropped item, tick:" + e.tick)
}
);
script.on_event(
defines.events.on_tick,
(e: OnTickEvent) => {
if (e.tick % 60 == 0) {
game.print("test mod tick: " + e.tick)
}
}
);
script.on_load(() => {
game.print("loaded Factorio Web Map!")
});

View file

@ -1,6 +1,6 @@
{ {
"name": "factorio-web-map", "name": "factorio-web-map",
"version": "0.0.1", "version": "0.0.2",
"title": "Factorio Web Map", "title": "Factorio Web Map",
"author": "fredthedeadhead", "author": "fredthedeadhead",
"factorio_version": "1.1", "factorio_version": "1.1",

View file

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 702 B

Before After
Before After

View file

@ -0,0 +1,30 @@
script.on_event(
[defines.events.on_pre_build, defines.events.on_player_dropped_item],
(e: OnPreBuildEvent | OnPlayerDroppedItemEvent) => {
game.print("player " + e.player_index + " dropped item, tick:" + e.tick)
}
);
script.on_event(
defines.events.on_tick,
(e: OnTickEvent) => {
if (e.tick % 60 == 0) {
let msg = "test mod tick: " + e.tick + "\n"
// game.print(msg)
game.write_file("tick.log", msg, true)
let groups = game.permissions.groups.map(val => {
return val.name + "\n" + serpent.block(val)
}).join("\n")
game.write_file("permissions.json", groups, false)
// game.write_file("permissions-groups.json", serpent.block(game.permissions.groups), false)
}
}
);
// script.on_load(() => {
// game.print("loaded Factorio Web Map!")
// });

View file

@ -907,16 +907,6 @@
"object-assign": "^4.1.1" "object-assign": "^4.1.1"
} }
}, },
"react-dom": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"scheduler": "^0.20.2"
}
},
"rechoir": { "rechoir": {
"version": "0.7.1", "version": "0.7.1",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
@ -962,15 +952,6 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true "dev": true
}, },
"scheduler": {
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
"integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
},
"schema-utils": { "schema-utils": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",

View file

@ -1,7 +1,7 @@
version: "3.9" version: "3.9"
services: services:
factorio: factorio:
image: factoriotools/factorio:1.1.41 image: factoriotools/factorio:1.1.42
# logging: # logging:
# driver: "json-file" # driver: "json-file"
container_name: "factorio" container_name: "factorio"

View file

@ -0,0 +1,78 @@
{
"_terrain_segmentation_comment": "The inverse of 'water scale' in the map generator GUI.",
"terrain_segmentation": 1,
"_water_comment":
[
"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,
"_comment_width+height": "Width and height of map, in tiles; 0 means infinite",
"width": 0,
"height": 0,
"_starting_area_comment": "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_comment": "Name of the cliff prototype",
"name": "cliff",
"_cliff_elevation_0_comment": "Elevation of first row of cliffs",
"cliff_elevation_0": 10,
"_cliff_elevation_interval_comment":
[
"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,
"_richness_comment": "Called 'cliff continuity' in the map generator GUI. 0 will result in no cliffs, 10 will make all cliff rows completely solid",
"richness": 1
},
"_property_expression_names_comment":
[
"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.",
"'control-setting:moisture:frequency:multiplier' is the inverse of the 'moisture scale' in the map generator GUI.",
"'control-setting:moisture:bias' is the 'moisture bias' in the map generator GUI.",
"'control-setting:aux:frequency:multiplier' is the inverse of the 'terrain type scale' in the map generator GUI.",
"'control-setting:aux:bias' is the 'terrain type bias' in the map generator GUI."
],
"property_expression_names":
{
"control-setting:moisture:frequency:multiplier": "1",
"control-setting:moisture:bias": "0",
"control-setting:aux:frequency:multiplier": "1",
"control-setting:aux:bias": "0"
},
"starting_points":
[
{ "x": 0, "y": 0}
],
"_seed_comment": "Use null for a random seed, number for a specific seed.",
"seed": null
}

View file

@ -0,0 +1,120 @@
{
"difficulty_settings":
{
"recipe_difficulty": 0,
"technology_difficulty": 0,
"technology_price_multiplier": 1,
"research_queue_setting": "after-victory"
},
"pollution":
{
"enabled": true,
"_comment_min_to_diffuse_1": "these are values for 60 ticks (1 simulated second)",
"_comment_min_to_diffuse_2": "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
}

View file

@ -0,0 +1 @@
we3Sai7phaeFohc

View file

@ -0,0 +1,69 @@
{
"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"],
"_comment_max_players": "Maximum number of players allowed, admins can join even a full server. 0 means unlimited.",
"max_players": 0,
"_comment_visibility": ["public: Game will be published on the official Factorio matching server",
"lan: Game will be broadcast on LAN"],
"visibility":
{
"public": true,
"lan": true
},
"_comment_credentials": "Your factorio.com login credentials. Required for games with visibility public",
"username": "",
"password": "",
"_comment_token": "Authentication token. May be used instead of 'password' above.",
"token": "",
"game_password": "",
"_comment_require_user_verification": "When set to true, the server will only allow clients that have a valid Factorio.com account",
"require_user_verification": true,
"_comment_max_upload_in_kilobytes_per_second" : "optional, default value is 0. 0 means unlimited.",
"max_upload_in_kilobytes_per_second": 0,
"_comment_max_upload_slots" : "optional, default value is 5. 0 means unlimited.",
"max_upload_slots": 5,
"_comment_minimum_latency_in_ticks": "optional one tick is 16ms in default speed, default value is 0. 0 means no minimum.",
"minimum_latency_in_ticks": 0,
"_comment_ignore_player_limit_for_returning_players": "Players that played on this map already can join even when the max player limit was reached.",
"ignore_player_limit_for_returning_players": false,
"_comment_allow_commands": "possible values are, true, false and admins-only",
"allow_commands": "admins-only",
"_comment_autosave_interval": "Autosave interval in minutes",
"autosave_interval": 10,
"_comment_autosave_slots": "server autosave slots, it is cycled through when the server autosaves.",
"autosave_slots": 5,
"_comment_afk_autokick_interval": "How many minutes until someone is kicked when doing nothing, 0 for never.",
"afk_autokick_interval": 0,
"_comment_auto_pause": "Whether should the server be paused when no players are present.",
"auto_pause": true,
"only_admins_can_pause_the_game": true,
"_comment_autosave_only_on_server": "Whether autosaves should be saved only on server or also on all connected clients. Default is true.",
"autosave_only_on_server": true,
"_comment_non_blocking_saving": "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,
"_comment_segment_sizes": "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
}

View file

@ -0,0 +1,11 @@
{
"mods":
[
{
"name": "base",
"enabled": true
}
]
}

View file

@ -0,0 +1,532 @@
{
"available-campaign-levels":
{
"tight-spot":
{
"level-01": "hard"
},
"transport-belt-madness":
{
"level-01": "hard"
},
"tutorial":
{
"level-01": "hard"
}
},
"tips":
{
"introduction":
{
"status": "unlocked",
"elapsed": 0
},
"show-info":
{
"status": "dependencies-not-met"
},
"e-confirm":
{
"status": "locked"
},
"clear-cursor":
{
"status": "dependencies-not-met"
},
"pipette":
{
"status": "locked"
},
"stack-transfers":
{
"status": "locked",
"skip_status":
{
"conditions":
[
{},
{},
{}
]
}
},
"entity-transfers":
{
"status": "locked",
"conditions":
[
{},
{
"elapsed": 0
}
],
"skip_status":
{
"conditions":
[
{},
{}
]
}
},
"z-dropping":
{
"status": "locked",
"conditions":
[
{},
{
"elapsed": 0
}
]
},
"shoot-targeting":
{
"status": "locked",
"conditions":
[
{},
{
"elapsed": 0
}
]
},
"bulk-crafting":
{
"status": "locked",
"conditions":
[
{},
{}
]
},
"inserters":
{
"status": "locked"
},
"burner-inserter-refueling":
{
"status": "locked"
},
"long-handed-inserters":
{
"status": "locked"
},
"move-between-labs":
{
"status": "locked"
},
"insertion-limits":
{
"status": "locked"
},
"limit-chests":
{
"status": "locked",
"conditions":
[
{},
{}
]
},
"transport-belts":
{
"status": "locked"
},
"belt-lanes":
{
"status": "locked"
},
"splitters":
{
"status": "locked"
},
"splitter-filters":
{
"status": "locked"
},
"underground-belts":
{
"status": "locked"
},
"electric-network":
{
"status": "locked",
"conditions":
[
{
"conditions":
[
{
"conditions":
[
{},
{}
]
},
{
"elapsed": 0
}
]
},
{},
{},
{}
]
},
"steam-power":
{
"status": "dependencies-not-met"
},
"electric-pole-connections":
{
"status": "locked",
"conditions":
[
{
"elapsed": 0
},
{}
]
},
"low-power":
{
"status": "locked"
},
"connect-switch":
{
"status": "locked"
},
"copy-entity-settings":
{
"status": "locked"
},
"copy-paste-trains":
{
"status": "locked"
},
"copy-paste-filters":
{
"status": "locked",
"conditions":
[
{},
{}
]
},
"copy-paste-requester-chest":
{
"status": "locked",
"conditions":
[
{},
{}
]
},
"copy-paste-spidertron":
{
"status": "locked"
},
"drag-building":
{
"status": "locked"
},
"drag-building-poles":
{
"status": "locked"
},
"drag-building-underground-belts":
{
"status": "locked"
},
"fast-belt-bending":
{
"status": "locked"
},
"fast-obstacle-traversing":
{
"status": "locked",
"conditions":
[
{},
{}
]
},
"trains":
{
"status": "locked"
},
"rail-building":
{
"status": "locked"
},
"train-stops":
{
"status": "locked",
"conditions":
[
{},
{
"conditions":
[
{},
{}
]
}
]
},
"rail-signals-basic":
{
"status": "locked",
"conditions":
[
{},
{
"conditions":
[
{},
{}
]
}
]
},
"rail-signals-advanced":
{
"status": "locked",
"conditions":
[
{},
{}
]
},
"gate-over-rail":
{
"status": "locked",
"conditions":
[
{},
{},
{}
]
},
"pump-connection":
{
"status": "locked"
},
"train-stop-same-name":
{
"status": "locked"
},
"logistic-network":
{
"status": "locked",
"conditions":
[
{},
{}
]
},
"personal-logistics":
{
"status": "locked"
},
"construction-robots":
{
"status": "locked"
},
"passive-provider-chest":
{
"status": "dependencies-not-met"
},
"storage-chest":
{
"status": "dependencies-not-met"
},
"requester-chest":
{
"status": "locked"
},
"active-provider-chest":
{
"status": "locked"
},
"buffer-chest":
{
"status": "locked"
},
"ghost-building":
{
"status": "locked"
},
"ghost-rail-planner":
{
"status": "locked",
"conditions":
[
{
"conditions":
[
{},
{}
]
},
{}
]
},
"copy-paste":
{
"status": "locked",
"conditions":
[
{},
{
"elapsed": 0
}
]
},
"fast-replace":
{
"status": "locked",
"conditions":
[
{},
{},
{}
]
},
"fast-replace-direction":
{
"status": "locked"
},
"fast-replace-belt-splitter":
{
"status": "locked",
"skip_status":
{
"conditions":
[
{},
{}
]
}
},
"fast-replace-belt-underground":
{
"status": "locked"
},
"rotating-assemblers":
{
"status": "locked",
"conditions":
[
{},
{}
]
},
"circuit-network":
{
"status": "locked",
"conditions":
[
{},
{
"elapsed": 0
}
]
}
},
"service-username": "",
"service-token": "",
"last-used-filters":
{
"players": "any",
"password": "any",
"mods": "any",
"friends": "any"
},
"column-ordering":
{
"public-index": "name",
"public-ascending": true,
"lan-index": "name",
"lan-ascending": true
},
"editor-lua-snippets":
[
{
"name": "Example (Turn trees into biters)",
"code": "local surface = game.player.surface\nlocal entities = surface.find_entities_filtered{area = area, type = 'tree'}\nfor k, tree in pairs(entities) do\n local position = tree.position\n tree.destroy()\n surface.create_entity{name = 'small-biter', position = position}\nend"
}
],
"last-played-version":
{
"game_version": "1.1.41",
"build_version": 58972,
"build_mode": "headless",
"platform": "linux64"
},
"blueprint-view": "grid"
}

View file

@ -157,3 +157,9 @@ tasks {
} }
} }
} }
configure<NodeJsRootExtension> {
versions.dukat.version = "0.5.8-rc.4-dev.20211001"
// versions.dukat.version = "0.5.8-rc.4"
}

View file

@ -2,18 +2,6 @@
import kotlin.js.* import kotlin.js.*
import kotlinext.js.PropertyDescriptor import kotlinext.js.PropertyDescriptor
import org.khronos.webgl.*
import org.w3c.dom.*
import org.w3c.dom.events.*
import org.w3c.dom.parsing.*
import org.w3c.dom.svg.*
import org.w3c.dom.url.*
import org.w3c.fetch.*
import org.w3c.files.*
import org.w3c.notifications.*
import org.w3c.performance.*
import org.w3c.workers.*
import org.w3c.xhr.*
typealias float = Number typealias float = Number

View file

@ -183,9 +183,9 @@ external interface LuaBootstrap {
fun on_init(f: (() -> Unit)?) fun on_init(f: (() -> Unit)?)
fun on_load(f: (() -> Unit)?) fun on_load(f: (() -> Unit)?)
fun on_configuration_changed(f: ((param1: ConfigurationChangedData) -> Unit)?) fun on_configuration_changed(f: ((param1: ConfigurationChangedData) -> Unit)?)
fun <E : uint> on_event(event: E, f: ((data: Any) -> Unit)?, filters: Array<Any> = definedExternally) fun <E : OnTickEvent> on_event(event: E, f: ((data: E) -> Unit)?, filters: Array<Any> = definedExternally)
fun <E : uint> on_event(event: E, f: ((data: Any) -> Unit)?) fun <E : OnTickEvent> on_event(event: E, f: ((data: E) -> Unit)?)
fun <E : uint> on_event(event: Array<E>, f: ((data: Any) -> Unit)?) fun <E : OnTickEvent> on_event(event: Array<E>, f: ((data: Any) -> Unit)?)
fun on_event(event: String, f: ((data: CustomInputEvent) -> Unit)?) fun on_event(event: String, f: ((data: CustomInputEvent) -> Unit)?)
fun on_nth_tick(tick: uint?, f: ((param1: NthTickEventData) -> Unit)?) fun on_nth_tick(tick: uint?, f: ((param1: NthTickEventData) -> Unit)?)
fun on_nth_tick(tick: Array<uint>?, f: ((param1: NthTickEventData) -> Unit)?) fun on_nth_tick(tick: Array<uint>?, f: ((param1: NthTickEventData) -> Unit)?)

View file

@ -2,6 +2,8 @@
@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS") @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
package defines.events package defines.events
import EventId
import OnTickEvent
import kotlin.js.* import kotlin.js.*
import org.khronos.webgl.* import org.khronos.webgl.*
import org.w3c.dom.* import org.w3c.dom.*
@ -17,7 +19,7 @@ import org.w3c.workers.*
import org.w3c.xhr.* import org.w3c.xhr.*
import uint import uint
external var on_tick: uint /* uint & `T$93`<OnTickEvent, Unit> */ external var on_tick: EventId<OnTickEvent> /* uint & `T$93`<OnTickEvent, Unit> */
external var on_gui_click: uint /* uint & `T$93`<OnGuiClickEvent, Unit> */ external var on_gui_click: uint /* uint & `T$93`<OnGuiClickEvent, Unit> */

View file

@ -0,0 +1,11 @@
external class TsUInt : tsstdlib.Number
external class EventId<DataT: table, FilterT: table?> {
@JsName("_eventData")
val eventData: DataT
@JsName("_filter")
val filter: FilterT
}

View file

@ -1,4 +1,5 @@
@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS") @file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER",
"RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS")
import kotlin.js.* import kotlin.js.*
import org.khronos.webgl.* import org.khronos.webgl.*
@ -17,11 +18,11 @@ import tsstdlib.Record
import tsstdlib.Iterable import tsstdlib.Iterable
external interface LuaThread { external interface LuaThread {
var __internal__: Any var __internal__: Any
} }
external interface LuaUserdata { external interface LuaUserdata {
var __internal__: Any var __internal__: Any
} }
external var _VERSION: String /* "Lua 5.1" | "Lua 5.2" | "Lua 5.3" | "Lua 5.4" */ external var _VERSION: String /* "Lua 5.1" | "Lua 5.2" | "Lua 5.3" | "Lua 5.4" */
@ -30,13 +31,15 @@ external var _G: Any
external fun <V> assert(v: V): Any external fun <V> assert(v: V): Any
external fun <V, A : Array<Any>> assert(v: V, vararg args: A): dynamic /* JsTuple<Exclude<V, Boolean?>, Any> */ external fun <V, A : Array<Any>> assert(v: V,
vararg args: A): dynamic /* JsTuple<Exclude<V, Boolean?>, Any> */
external fun collectgarbage(opt: String /* "collect" | "stop" | "restart" */ = definedExternally) external fun collectgarbage(opt: String /* "collect" | "stop" | "restart" */ = definedExternally)
external fun collectgarbage() external fun collectgarbage()
external fun collectgarbage(opt: String /* "setpause" | "setstepmul" | "step" */, arg: Number): dynamic /* Number | Boolean */ external fun collectgarbage(opt: String /* "setpause" | "setstepmul" | "step" */,
arg: Number): dynamic /* Number | Boolean */
external fun dofile(filename: String = definedExternally): Any external fun dofile(filename: String = definedExternally): Any
@ -44,17 +47,25 @@ external fun error(message: String, level: Number = definedExternally): Any
external fun <T> getmetatable(obj: T): LuaMetatable__1<T>? external fun <T> getmetatable(obj: T): LuaMetatable__1<T>?
external fun <T> ipairs(t: Record<Number, T>): Iterable<dynamic /* JsTuple<Number, NonNullable<T>> */> /* Iterable<dynamic /* JsTuple<Number, NonNullable<T>> */> & LuaIterator<dynamic /* JsTuple<Number, NonNullable<T>> */, undefined> & LuaExtension<String /* "__luaIterableBrand" */> */ external fun <T : Any> ipairs(
t: kotlinext.js.Record<Number, T>):
Iterable<dynamic /* JsTuple<Number, NonNullable<T>> */>
/* Iterable<dynamic /* JsTuple<Number, NonNullable<T>> */> & LuaIterator<dynamic /* JsTuple<Number, NonNullable<T>> */, undefined> & LuaExtension<String /* "__luaIterableBrand" */> */
external fun next(table: Any?, index: Any = definedExternally): dynamic /* JsTuple<Any, Any> | JsTuple<> */ external fun next(table: Any?,
index: Any = definedExternally): dynamic /* JsTuple<Any, Any> | JsTuple<> */
external fun <TKey : AnyNotNil, TValue> pairs(t: LuaTable<TKey, TValue>): Iterable<dynamic /* JsTuple<TKey, NonNullable<TValue>> */> /* Iterable<dynamic /* JsTuple<TKey, NonNullable<TValue>> */> & LuaIterator<dynamic /* JsTuple<TKey, NonNullable<TValue>> */, undefined> & LuaExtension<String /* "__luaIterableBrand" */> */ external fun <TKey : AnyNotNil, TValue> pairs(
t: LuaTable<TKey, TValue>): Iterable<dynamic /* JsTuple<TKey, NonNullable<TValue>> */> /* Iterable<dynamic /* JsTuple<TKey, NonNullable<TValue>> */> & LuaIterator<dynamic /* JsTuple<TKey, NonNullable<TValue>> */, undefined> & LuaExtension<String /* "__luaIterableBrand" */> */
external fun <T> pairs(t: T): Iterable<dynamic /* JsTuple<Any, NonNullable<Any>> */> /* Iterable<dynamic /* JsTuple<Any, NonNullable<Any>> */> & LuaIterator<dynamic /* JsTuple<Any, NonNullable<Any>> */, undefined> & LuaExtension<String /* "__luaIterableBrand" */> */ external fun <T> pairs(
t: T): Iterable<dynamic /* JsTuple<Any, NonNullable<Any>> */> /* Iterable<dynamic /* JsTuple<Any, NonNullable<Any>> */> & LuaIterator<dynamic /* JsTuple<Any, NonNullable<Any>> */, undefined> & LuaExtension<String /* "__luaIterableBrand" */> */
external fun <This, Args : Array<Any>, R> pcall(f: (self: This, args: Args) -> R, context: This, vararg args: Args): dynamic /* JsTuple<Boolean, R> | JsTuple<Boolean, String> */ external fun <This, Args : Array<Any>, R> pcall(f: (self: This, args: Args) -> R, context: This,
vararg args: Args): dynamic /* JsTuple<Boolean, R> | JsTuple<Boolean, String> */
external fun <A : Array<Any>, R> pcall(f: (self: Unit, args: A) -> R, vararg args: A): dynamic /* JsTuple<Boolean, R> | JsTuple<Boolean, String> */ external fun <A : Array<Any>, R> pcall(f: (self: Unit, args: A) -> R,
vararg args: A): dynamic /* JsTuple<Boolean, R> | JsTuple<Boolean, String> */
external fun print(vararg args: Any) external fun print(vararg args: Any)
@ -68,14 +79,17 @@ external fun rawlen(v: String?): Number
external fun <T : Any?, K : Any> rawset(table: T, index: K, value: Any): T external fun <T : Any?, K : Any> rawset(table: T, index: K, value: Any): T
external fun <T> select(index: Number, vararg args: T): Array<T> /* Array<T> & LuaExtension<String /* "__luaMultiReturnBrand" */> */ external fun <T> select(index: Number,
vararg args: T): Array<T> /* Array<T> & LuaExtension<String /* "__luaMultiReturnBrand" */> */
external fun <T> select(index: String /* "#" */, vararg args: T): Number external fun <T> select(index: String /* "#" */, vararg args: T): Number
external fun <T : Any?, TIndex> setmetatable(table: T, metatable: LuaMetatable<T, TIndex>? = definedExternally): Any external fun <T : Any?, TIndex> setmetatable(table: T,
metatable: LuaMetatable<T, TIndex>? = definedExternally): Any
external fun tonumber(e: Any, base: Number = definedExternally): Number? external fun tonumber(e: Any, base: Number = definedExternally): Number?
external fun tostring(v: Any): String external fun tostring(v: Any): String
external fun type(v: Any): String /* "nil" | "number" | "string" | "boolean" | "table" | "function" | "thread" | "userdata" */ external fun type(
v: Any): String /* "nil" | "number" | "string" | "boolean" | "table" | "function" | "thread" | "userdata" */

View file

@ -63,7 +63,9 @@ typealias Partial<T> = Any
typealias Pick<T, K> = Any typealias Pick<T, K> = Any
typealias Record<K, T> = Any @Deprecated("use Kotlin Wrapper", ReplaceWith("kotlinext.js.Record<K, T>"))
typealias Record<K, T> = kotlinext.js.Record<K, T>
typealias Exclude<T, U> = Any typealias Exclude<T, U> = Any

View file

@ -0,0 +1,11 @@
fun main() {
script.on_event(
defines.events.on_tick
) { event ->
}
}

View file

@ -0,0 +1,113 @@
# Typed Factorio
Complete and featureful typescript definitions for the Factorio modding lua api. This is intended to be used with [TypescriptToLua](https://typescripttolua.github.io/).
This project aims to provide type definitions for the Factorio API that are as complete as possible. This means minimal `any`s and `unknown`s, correct nullability, and smart types where possible. The generator integrates both the Factorio JSON api docs and manually defined additions and overrides.
## Installation
To use in your TypescriptToLua project:
1. Install this package
```
npm install typed-factorio
or
yarn add typed-factorio
```
2. Add to your `tsconfig.json`:
```diff
{
"compilerOptions": {
+ "types": [ "typed-factorio/runtime" ]
}
}
```
This will add the types for the runtime stage to your entire project.
Note: When types are updated, or released for a new factorio version, you will need update your package version to get the types.
### Settings and data stage
There are also definitions for the settings/data stage.
To avoid type conflicts, the global tables for the settings/data stages have to be declared manually where you need them. These types can be imported from `typed-factorio/data/types` or `typed-factorio/settings/types`.
Example:
```ts
import { Data, Mods } from "typed-factorio/data/types"
// or
import { Data, Mods } from "typed-factorio/settings/types"
declare const data: Data
declare const mods: Mods
data.extend([{ ... }])
```
There are currently full types for settings stage, but only basic types for the data stage.
### Factorio lualib modules
Currently, there are types for the following modules:
- `util`
- `mod-gui`
If you have a need for types to more lualib modules, feel free to open an issue or pull request on GitHub.
## Type features
Typed-factorio has 100% complete types for the runtime stage. Description-only concepts and some not documented types are filled in manually.
### Lua features
The types include [TypescriptToLua language extensions](https://typescripttolua.github.io/docs/advanced/language-extensions/)
and [lua-types](https://github.com/TypeScriptToLua/lua-types) (for v5.2) as dependencies.
This is to use tstl features such as `LuaLengthMethod` and `LuaMultiReturn`.
### `nil`
The types consistently use `undefined` to represent `nil`.
`null` is not used, because `undefined` in typescript is much more similar to `nil` in lua, and optional parameters/properties already use `undefined`.
A class attribute is marked as possibly undefined only if the _read_ type is possibly `nil`. For properties where `nil` is not possible on _read_, but is possible on _write_, you can write `nil` by using `undefined!` or `myNullableValue!`, e.g. `controlBehavior.parameters = undefined!`.
### Variant parameter types
Variant parameter types (types with "additional fields can be specified depending on ...") are handled as discriminated unions. This gives proper type checking for individual variants.
The type for a specific variant is prefixed with the either variant name or "Other" for variants without additional fields, e.g. `AmmoDamageTechnologyModifier`, `OtherTechnologyModifier`
### Events
`script.on_event()`, `script.get/set_filters()`, and `script.raise_event()` all have type checking on the event data/filter type, inferred from what is passed as the event name/id.
You can pass a type parameter to `script.generate_event_name()`, and it will return an `EventId` that holds type info of the event data. Event functions on `script` can then use the type data when the `EventId` is passed.
### Array-like types
Classes that have an index operator, a length operator, and have an array-like structure, inherit from `(Readonly)Array`. These are `LuaInventory`, `LuaFluidBox`, `LuaTransportLine`. This allows you to use these classes like arrays, meaning having array methods, and `.length` translating to the lua length operator. However, this also means, like typescript arrays, they are **0-indexed, not 1-indexed**.
### Table or array types
For table or array types (e.g. Position), there also are types such as `PositionTable` and `PositionArray` that refer to the table or array form specifically.
### LuaGuiElement
`LuaGuiElement` is broken up into a discriminated union for each gui element type (See [here](https://basarat.gitbook.io/typescript/type-system/discriminated-unions) for information on discriminated unions). The type for a specific GuiElement type is `<Type>GuiElement`, e.g. `ButtonGuiElement`.
Similarly, the table passed to `LuaGuiElement.add`, referred to as `GuiSpec`, is also broken up into a discriminated union for each gui element type. The type for a specific GuiSpec type is `<Type>GuiSpec`, e.g. `ListBoxGuiSpec`.
This is done both to provide more accurate types, and for possible integration with [JSX](https://typescripttolua.github.io/docs/jsx/).
### Examples
Check out the `test` directory on GitHub for more examples on particular type features.

View file

@ -0,0 +1,13 @@
export interface Data {
readonly raw: Record<string, Record<string, any>>
/**
* The `data` table expects a specific format for each item in the table. Missing properties will either fall back to
* default values or give an error indicating what's missing. Extra properties that the game isn't looking for are
* simply ignored.
*/
extend(prototypes: Record<string, any>[]): void
}
/** A mapping of mod names to mod version for all enabled mods. */
export type Mods = Record<string, string>

View file

@ -0,0 +1,66 @@
/** @noSelfInFile */
/**
* A floating-point number. This is a single-precision floating point number. Whilst Lua only uses double-precision
* numbers, when a function takes a float, the game engine will immediately convert the double-precision number to
* single-precision.
*
* {@link https://lua-api.factorio.com/next/Builtin-Types.html#float View documentation}
*/
type float = number
/**
* A double-precision floating-point number. This is the same data type as all Lua numbers use.
*
* {@link https://lua-api.factorio.com/next/Builtin-Types.html#double View documentation}
*/
type double = number
/**
* 32-bit signed integer. Possible values are -2,147,483,648 to 2,147,483,647.
*
* {@link https://lua-api.factorio.com/next/Builtin-Types.html#int View documentation}
*/
type int = number
/**
* 8-bit signed integer. Possible values are -128 to 127.
*
* {@link https://lua-api.factorio.com/next/Builtin-Types.html#int8 View documentation}
*/
type int8 = number
/**
* 32-bit unsigned integer. Possible values are 0 to 4,294,967,295.
*
* {@link https://lua-api.factorio.com/next/Builtin-Types.html#uint View documentation}
*/
type uint = number
/**
* 8-bit unsigned integer. Possible values are 0 to 255.
*
* {@link https://lua-api.factorio.com/next/Builtin-Types.html#uint8 View documentation}
*/
type uint8 = number
/**
* 16-bit unsigned integer. Possible values are 0 to 65535.
*
* {@link https://lua-api.factorio.com/next/Builtin-Types.html#uint16 View documentation}
*/
type uint16 = number
/**
* 64-bit unsigned integer. Possible values are 0 to 18,446,744,073,709,551,615.
*
* {@link https://lua-api.factorio.com/next/Builtin-Types.html#uint64 View documentation}
*/
type uint64 = number
/**
* Tables are enclosed in curly brackets, like this `{}`
*
* {@link https://lua-api.factorio.com/next/Builtin-Types.html#table View documentation}
*/
type table = object

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,51 @@
/** @noSelfInFile */
/**
* This is the main object, through which most of the API is accessed. It is, however, not available inside handlers
* registered with {@link LuaBootstrap.on_load LuaBootstrap::on_load}.
*
* {@link https://lua-api.factorio.com/next/ View documentation}
*/
declare const game: LuaGameScript
/**
* Provides an interface for registering event handlers.
*
* {@link https://lua-api.factorio.com/next/ View documentation}
*/
declare const script: LuaBootstrap
/**
* Allows inter-mod communication by way of providing a repository of interfaces that is shared by all mods.
*
* {@link https://lua-api.factorio.com/next/ View documentation}
*/
declare const remote: LuaRemote
/**
* Allows registering custom commands for the in-game console accessible via the grave key.
*
* {@link https://lua-api.factorio.com/next/ View documentation}
*/
declare const commands: LuaCommandProcessor
/**
* Allows reading the current mod settings.
*
* {@link https://lua-api.factorio.com/next/ View documentation}
*/
declare const settings: LuaSettings
/**
* Allows printing messages to the calling RCON instance if any.
*
* {@link https://lua-api.factorio.com/next/ View documentation}
*/
declare const rcon: LuaRCON
/**
* Allows rendering of geometric shapes, text and sprites in the game world.
*
* {@link https://lua-api.factorio.com/next/ View documentation}
*/
declare const rendering: LuaRendering

View file

@ -0,0 +1,7 @@
///<reference types="lua-types/5.2" />
///<reference path="builtin-types.d.ts" />
///<reference path="defines.d.ts" />
///<reference path="events.d.ts" />
///<reference path="classes.d.ts" />
///<reference path="concepts.d.ts" />
///<reference path="global-objects.d.ts" />

View file

@ -0,0 +1,39 @@
{
"name": "typed-factorio",
"version": "0.7.1",
"description": "Featureful typescript definitions for the the Factorio modding lua api.",
"keywords": [
"factorio",
"types",
"typescript-to-lua",
"tstl"
],
"repository": "https://github.com/GlassBricks/typed-factorio",
"license": "MIT",
"files": [
"**/*.d.ts"
],
"homepage": "https://github.com/GlassBricks/typed-factorio#readme",
"scripts": {
"generate": "cd ../generator && yarn run check && yarn run gen --in ../definitions/generatorSrc --out ../definitions/generated --warn-as-error",
"generate:dev": "cd ../generator && yarn run gen --in ../definitions/generatorSrc --out ../definitions/generated --no-format",
"clean": "rimraf ./generated",
"pretest": "yarn run generate",
"test": "jest",
"prepublishOnly": "yarn run test",
"download-latest-runtime-api": "ts-node ./scripts/downloadLatest.ts"
},
"dependencies": {
"lua-types": "^2.10.1",
"typescript": "~4.3.5",
"typescript-to-lua": "^1.0.0"
},
"devDependencies": {
"@types/jest": "^26.0.24",
"@types/node": "^16.4.13",
"jest": "^27.0.6",
"prettier": "^2.3.2",
"ts-jest": "^27.0.4",
"ts-node": "^10.1.0"
}
}

View file

@ -0,0 +1,10 @@
/// <reference types="lua-types/5.2" />
/// <reference path="../generated/index.d.ts" />
/// <reference path="librariesAndFunctions.d.ts" />
/// <reference path="pairs.d.ts" />
// lualib
/// <reference path="util.d.ts" />
/// <reference path="mod-gui.d.ts" />

View file

@ -0,0 +1,123 @@
// from https://lua-api.factorio.com/latest/Libraries.html
// last updated for 1.1.35, 1.1.36, 1.1.37
/** @noSelfInFile */
/** @noSelf */
interface SerpentOptions {
/** Indentation; triggers long multi-line output. */
indent: string
/** Provide stringified value in a comment (up to maxlevel of depth). */
comment: boolean | number
/** Sort keys. */
sortkeys: boolean | ((this: void, keys: any[], table: any) => void)
/** Force sparse encoding (no nil filling based on #t). */
sparse: boolean
/** Remove spaces. */
compact: boolean
/** Raise fatal error on non-serializable values. */
fatal: boolean
/** Disable bytecode serialization for easy comparison. */
nocode: boolean
/** Disable checking numbers against undefined and huge values. */
nohuge: boolean
/** Specify max level up to which to expand nested tables. */
maxlevel: number
/** Specify max number of elements in a table. */
maxnum: number
/** Specify max length for all table elements. */
maxlength: number
/**
* Use __tostring metamethod when serializing tables (v0.29); set to false to disable and serialize the table as is,
* even when __tostring is present.
*/
metatostring: boolean
/**
* Specify format for numeric values as shortest possible round-trippable double (v0.30). Use "%.16g" for better
* readability and "%.17g" (the default value) to preserve floating point precision.
*/
numformat: string
/** Allows to specify a list of values to ignore (as keys). */
valignore: string[]
/** Allows to specify the list of keys to be serialized. Any keys not in this list are not included in final output (as keys). */
keyallow: string[]
/** Allows to specity the list of keys to ignore in serialization. */
keyignore: string[]
/** Allows to specify a list of value types to ignore (as keys). */
valtypeignore: string[]
/** Provide custom output for tables. */
custom(opts: {
/** The name of the current element with '=' or an empty string in case of array index, */
tag: string
/** An opening table bracket { and associated indentation and newline (if any), */
head: string
/** Table elements concatenated into a string using commas and indentation/newlines (if any), */
body: string
/** A closing table bracket } and associated indentation and newline (if any), and */
tail: string
/** The current level. */
level: number
}): string
/** Name; triggers full serialization with self-ref section. */
name: string
refcomment: boolean | number
tablecomment: boolean | number
}
/**
* Factorio provides the {@link https://github.com/pkulchenko/serpent serpent library} as a global variable `serpent` for
* all mods to use. It allows for easy debugging of tables, because serpent makes it trivial to print them, for example
* by using `serpent.block()`. However, serpent cannot pretty-print LuaObjects such as LuaEntity. The serpent library
* was modified to improve determinism, e.g. comments are turned off by default to avoid returning table addresses.
* Furthermore, two options were added: `refcomment` (true/false/maxlevel) and `tablecomment` (true/false/maxlevel),
* which allow to separately control the self-reference and table value output of the `comment` option.
*/
declare namespace serpent {
/** Full serialization; sets name, compact and sparse options; */
function dump(tbl: unknown, options?: Partial<SerpentOptions>): string
/** Single line pretty printing, no self-ref section; sets sortkeys and comment options; */
function line(tbl: unknown, options?: Partial<SerpentOptions>): string
/** Multi-line indented pretty printing, no self-ref section; sets indent, sortkeys, and comment options. */
function block(tbl: unknown, options?: Partial<SerpentOptions>): string
/**
* For loading serialized fragments, serpent also provides `load` function that adds safety checks and reports an
* error if there is any executable code in the fragment.
*/
function load<T>(str: string, options?: { safe?: boolean }): LuaMultiReturn<[true, T] | [false, string]>
}
/**
* This function allows to log {@link LocalisedString} to the Factorio
* {@link https://wiki.factorio.com/Log_file log file}. This, in combination with serpent, makes debugging in the data
* stage easier, because it allows to simply inspect entire prototype tables. For example, this allows to see all
* properties of the sulfur item prototype: `log(serpent.block(data.raw["item"]["sulfur"]))`
*/
declare function log(ls: LocalisedString): void
/**
* This function allows printing {@link LocalisedString}s to stdout without polluting the logfile. This is primarily
* useful for communicating with external tools that launch Factorio as a child process.
*/
declare function localised_print(ls: LocalisedString): void
/**
* Factorio provides the function `table_size()` as a simple way to find the size of tables with non-continuous keys,
* because the standard `#` does not work correctly for these. The function is a C++-side implementation of the
* following Lua code, thus it is faster than using this code in Lua:
*
* local function size(t)
* local count = 0
* for k,v in pairs(t) do
* count = count + 1
* end
* return count
* end
*
* Note that `table_size()` does not work correctly for {@link LuaCustomTable}s, their size has to be determined with
* {@link LuaCustomTable.length LuaCustomTable::operator #} instead.
*/
declare function table_size(tbl: table): number

View file

@ -0,0 +1,11 @@
/** @noSelfInFile */
/** @noResolution */
declare module "mod-gui" {
const button_style: string
const frame_style: string
function get_button_flow(player: LuaPlayer): FrameGuiElement
function get_frame_flow(player: LuaPlayer): FlowGuiElement
}

View file

@ -0,0 +1,13 @@
/** @noSelfInFile */
/** Iterating with `pairs` will only iterate the array part of a {@link LuaCustomTable}. */
declare function pairs<V>(table: LuaCustomTable<number | string, V>): LuaIterable<LuaMultiReturn<[number, V]>>
declare function pairs<K extends keyof any, V>(table: LuaCustomTable<K, V>): LuaIterable<LuaMultiReturn<[K, V]>>
/**
* {@link LuaCustomTable} cannot be iterated with `ipairs`. Use `pairs` instead.
*
* @deprecated
*/
declare function ipairs(table: LuaCustomTable<any, any>): never

View file

@ -0,0 +1,120 @@
// "util" is declared only as a module, even though it also modifies global variables
// This is both because of limitations in `declare module`, and that modules are much friendlier to tooling.
/** @noSelfInFile */
/** @noResolution */
declare module "util" {
namespace table {
function deepcopy<T>(table: T): T
function compare<T>(tb1: T, tb2: T): boolean
}
function copy<T>(table: T): T
function distance(position1: Position, position2: Position): number
function positiontostr(position: Position): string
function formattime(ticks: number): string
/** Supports 'rrggbb', 'rgb', 'rrggbbaa', 'rgba', 'ww', 'w' */
function color(hex: string): ColorTable
function premul_color(color: Color): ColorTable
function mix_color(c1: Color, c2: Color): ColorArray
function multiply_color(c1: Color, n: number): ColorArray
function moveposition(
position: Position,
direction: defines.direction.north | defines.direction.east | defines.direction.south | defines.direction.west,
distance: number
): Position
function moveposition(
position: Position,
direction: defines.direction, //todo: cardinal only
distance: number
): Position | undefined
function oppositedirection(direction: defines.direction): defines.direction
/** Creates a new array where each element in `stripes` is duplicated `count` times */
function multiplystripes<T>(count: number, stripes: T[]): T[]
/** Gets tile position by pixel */
function by_pixel(x: number, y: number): Position
/** Gets tile position by pixel, hr */
function by_pixel_hr(x: number, y: number): Position
// omitted: foreach_sprite_definition
function add_shift(a: PositionArray | undefined, b: PositionArray): PositionArray
function add_shift(a: PositionArray, b: PositionArray | undefined): PositionArray
function add_shift(a: PositionArray | undefined, b: PositionArray | undefined): PositionArray | undefined
// omitted: add_shift_offset
function mul_shift(shift: PositionArray, scale: number | undefined): PositionArray
function mul_shift(shift: PositionArray | undefined, scale: number | undefined): PositionArray | undefined
function format_number(amount: number, append_suffix?: boolean): string
function increment(t: number[], index: number, v?: number): void
// omitted: conditional_return
/**
* Recursively merges and/or deep-copies tables. Entries in later tables override entries in earlier ones, unless both
* entries are themselves tables, in which case they are recursively merged. Non-merged tables are deep-copied, so
* that the result is brand new.
*/
function merge<T extends object>(tables: T[]): T
function insert_safe(entity: LuaEntity | undefined, item_dict: Record<string, number> | undefined): void
function remove_safe(entity: LuaEntity | undefined, item_dict: Record<string, number> | undefined): void
function split_whitespace(string: string): string[]
// omitted: split, string_starts_with. already TS functions for that
// omitted: online_players. use game.connected_players
function clamp(x: number, lower: number, upper: number): number
// omitted: get_walkable_tile
// omitted: combine_icons
// omitted: technology_icons. Create an issue if you really want to see these
function parse_energy(energy: string): number
function product_amount(
product: {
probability: number
} & (
| {
amount: number
}
| {
amount_min: number
amount_max: number
}
)
): number
function empty_sprite(): object
// omitted: draw_as_glow
// omitted: remove_tile_references
function remove_from_list<T>(list: T[], value: T): boolean
function list_to_map<T extends keyof any>(list: T[]): Record<T, true>
function list_to_map<T>(list: T[]): LuaTable<T, true>
function list_to_map<T>(list: T): LuaTable<T[keyof T], true>
}

View file

@ -0,0 +1,120 @@
// Based off of https://wiki.factorio.com/Tutorial:Mod_settings
export type SettingType = "bool-setting" | "int-setting" | "double-setting" | "string-setting"
export interface BaseSettingDefinition {
type: SettingType
/**
* The name of the settings prototype should be unique to avoid mod conflicts since the mod settings are global across
* all mods. Because of that it is recommended to prefix mod settings with your mod name,
*/
name: string
localized_name?: LocalisedString
localized_description?: LocalisedString
/**
* The order property can be used to change how the mod settings are ordered in the settings gui. Mod settings are sorted
*
* - First by mod
* - Then by the setting "order" string
* - Then finally by the setting name.
*/
order?: string
/**
* The hidden property can be used to hide mod settings from GUIs, so that they cannot be seen or changed by players.
* However, other mods can still access hidden settings. {@link https://forums.factorio.com/83316}
*/
hidden?: boolean
/**
* There are the overall kinds of settings:
*
* - **startup**: This kind of setting is available in the prototype stage, and can not be changed runtime. They have to
* be set to the same values for all players on a server.
* - **runtime-global**: This kind of setting is global to an entire save game and can be changed runtime. On servers,
* only admins can change these settings.
* - **runtime-per-user**: This kind of setting is only available runtime in the control.lua stage and each player has
* their own instance of this setting. When a player joins a server their local setting of "keep mod settings per
* save" determines if the local settings they have set are synced to the loaded save or if the save's settings are used.
*
* This "setting_type" also determines in which tab the setting is showed in the mod settings menu.
*/
setting_type: "startup" | "runtime-global" | "runtime-per-user"
}
/** A true/false checkbox */
export interface BoolSettingDefinition extends BaseSettingDefinition {
type: "bool-setting"
/** Defines the default value of the setting, in this case whether the checkbox is checked or not. */
default_value: boolean
/**
* Only loaded if `hidden = true`. This forces the setting to be of this value. This can be useful for mod
* compatibility. {@link https://forums.factorio.com/viewtopic.php?p=531322#p531322}
*/
forced_value?: boolean
}
/** A signed 64 bit integer textfield (or selection dropdown) */
export interface IntSettingDefinition extends BaseSettingDefinition {
type: "int-setting"
/** Defines the default value of the setting. */
default_value: number
/** Defines the lowest possible number. */
minimum_value?: number
/** Defines the highest possible number. */
maximum_value?: number
/**
* Makes it possible to force the player to choose between the defined numbers, creates a dropdown instead of a
* textfield. If only one allowed value is given, the settings is forced to be of that value.
*/
allowed_values?: number[]
}
/** A double precision floating point textfield (or selection dropdown) */
export interface DoubleSettingDefinition extends BaseSettingDefinition {
type: "double-setting"
/** Defines the default value of the setting. */
default_value: number
/** Defines the lowest possible number. */
minimum_value?: number
/** Defines the highest possible number. */
maximum_value?: number
/**
* Makes it possible to force the player to choose between the defined numbers, creates a dropdown instead of a
* textfield. If only one allowed value is given, the settings is forced to be of that value.
*/
allowed_values?: number[]
}
/** A string textfield (or selection dropdown) */
export interface StringSettingDefinition extends BaseSettingDefinition {
type: "string-setting"
/** Defines the default value of the setting. */
default_value: string
/** Defines whether it's possible for the user to set the textfield to empty and apply the setting. */
allow_blank?: boolean
/** Whether values that are input by the user should have whitespace removed from both ends of the string. */
auto_trim?: boolean
/**
* Makes it possible to force the player to choose between the defined strings, creates a dropdown instead of a
* textfield. The strings in the dropdown can be localized (translated) and can have a tooltip, see below. If only one
* allowed value is given, the settings is forced to be of that value.
*/
allowed_values?: string[]
}
/** Setting definitions. See {@link https://wiki.factorio.com/Tutorial:Mod_settings} for more info. */
export type SettingDefinition =
| BoolSettingDefinition
| IntSettingDefinition
| DoubleSettingDefinition
| StringSettingDefinition
export interface Data {
readonly raw: {
[T in SettingDefinition["type"]]: Record<string, Extract<SettingDefinition, { type: T }>>
}
/**
* The `data` table expects a specific format for each item in the table. Missing properties will either fall back to
* default values or give an error indicating what's missing. Extra properties that the game isn't looking for are
* simply ignored.
*/
extend(prototypes: SettingDefinition[]): void
}
/** A mapping of mod names to mod version for all enabled mods. */
export type Mods = Record<string, string>

View file

@ -1,8 +1,8 @@
rootProject.name = "factorio-web-map" rootProject.name = "factorio-web-map"
include( include(
// ":modules:mod", ":modules:mod",
":modules:mod2", // ":modules:mod2",
":modules:server", ":modules:server",
) )

View file

@ -1,3 +0,0 @@