Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
L0laapk3 committed Jun 18, 2019
2 parents 682f8cd + f549644 commit 84157cc
Show file tree
Hide file tree
Showing 18 changed files with 773 additions and 509 deletions.
1 change: 1 addition & 0 deletions API_ExampleMod_0.0.1/control.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require "factoriomaps"
61 changes: 61 additions & 0 deletions API_ExampleMod_0.0.1/factoriomaps.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@

-- require this file in control.lua


local function handle_factoriomaps()
if remote.interfaces.factoriomaps then
script.on_event(remote.call("factoriomaps", "get_start_event"), function()


-- example parameters:
local from = {{10, 10}, {20, 20}} -- Use short notation for points: {x, y} and areas: {top_left_point, bottom_right_point}
from.surface = "nauvis" -- Pass surfaces by id (prefered) or name.
local to = {25, 25}
-- to.surface = "nauvis" -- when the destiny surface is not specified, its assumed to be the same as the source surface.


-- link_box_point: link from clickable box, to a point on the map, the zoom level stays the same.
remote.call("factoriomaps", "link_box_point", {
from = from,
to = to
})



-- link_box_area: link from clickable box, to an area of the map. The zoom will be adjusted to fit the area.
-- the 'to' parameter now has to be an area instead of a point, otherwise exactly the same.
remote.call("factoriomaps", "link_box_area", {
from = { {20, 10}, {30, 20}, surface = "nauvis" },
to = { surface = "Factory floor 1", {30, 30}, {40, 40} } -- both notations work.
})



-- link_renderbox_area: clickable box that renders the 'to' surface on the place of the 'from' surface.
remote.call("factoriomaps", "link_renderbox_area", {
from = { {40, 10}, {50, 20}, surface = "nauvis" },
to = { {30, 30}, {40, 40}, surface = "Factory floor 1" }
})



-- link_renderbox_area: clickable box that renders the 'to' surface on the place of the 'from' surface.
remote.call("factoriomaps", "link_renderbox_area", {
from = { {30, 30}, {40, 40}, surface = "Factory floor 1" },
to = { {10, 10}, {40, 20}, surface = "nauvis" }
})



-- surface_set_hidden: This prevents the user from navigating "to" the surface. Links will also not work.
-- Parts of the surface can still be rendered using renderboxes.
-- parameters: surface (id (prefered) or name), hidden: boolean, default to true.
remote.call("factoriomaps", "surface_set_hidden", "Factory floor 1", true)



end)
end
end
script.on_init(handle_factoriomaps)
script.on_load(handle_factoriomaps)
12 changes: 12 additions & 0 deletions API_ExampleMod_0.0.1/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "API_ExampleMod",
"version": "0.0.1",
"title": "FactorioMaps API ExampleMod",
"author": "L0laapk3",
"contact": "https://github.com/L0laapk3/",
"homepage": "https://github.com/L0laapk3/FactorioMaps",
"description": "Example API mod for factoriomaps",
"license": "CC BY-NC-SA 4.0",
"factorio_version": "0.17",
"dependencies": []
}
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,19 @@ Heres a list of flags that `auto.py` can accept:
| `--build-range=5.2` | The maximum range from buildings around which pictures are saved (in chunks, 32 by 32 in-game tiles). |
| `--connect-range=1.2` | The maximum range from connection buildings (rails, electric poles) around which pictures are saved. |
| `--tag-range=5.2` | The maximum range from mapview tags around which pictures are saved. |
| `--surface=nauvis` | Used to capture other surfaces. If left empty, the surface the player is standing on will be used. To capture multiple surfaces, use the argument multiple times: `--surface=nauvis --surface="Factory floor 1"`. To find out the names of surfaces, use the command `/c for _,s in pairs(game.surfaces) do game.print(s.name) end`. |
| `--factorio=PATH` | Use `factorio.exe` from *PATH* instead of attempting to find it in common locations. |
| `--modpath=PATH` | Use *PATH* as the mod folder. |
| `--basepath=RELPATH` | Output to `script-output\RELPATH` instead of `script-output\FactorioMaps`. (Factorio cannot output outside of `script-output`) |
| `--date=dd/mm/yy` | Date attached to the snapshot, default is today. |
| `--verbose` | Displays factoriomaps script logs. |
| `--verbosegame` | Displays *all* game logs. |
| `--noupdate` | Skips the update check. |
| `--maxthreads=N` | Sets the number of threads used for all steps. By default this is equal to the amount of logical processor cores available. |
| `--cropthreads=N` | Sets the number of threads used for the crop step. |
| `--refthreads=N` | Sets the number of threads used for the crossreferencing step. |
| `--zoomthreads=N` | Sets the number of threads used for the zoom step. |
| `--screenshotthreads=N` | Set the number of screenshotting threads factorio uses. |
| `--screenshotqueuesize=N` | Set the size of the factorio screenshotting queue. Too high values may cause high RAM usage and I haven't found any benefits to high values so I recommend not changing this. |
| `--delete` | Deletes the output folder specified before running the script. |
| `--dry` | Skips starting factorio, making screenshots and doing the main steps, only execute setting up and finishing of script. |

Expand Down
183 changes: 183 additions & 0 deletions api.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@

fm.API = {}
fm.API.startEvent = script.generate_event_name()

fm.API.linkData = {}
fm.API.hiddenSurfaces = {}


local ERRORPRETEXT = "\n\nFACTORIOMAPS HAS DETECTED AN INVALID USAGE OF THE FACTORIOMAPS API BY ANOTHER MOD.\nTHIS IS LIKELY NOT A PROBLEM WITH FACTORIOMAPS, BUT WITH THE OTHER MOD.\n\n"

local function resolveSurface(surface, default, errorText)
errorText = errorText or ""
if surface ~= nil then
if type(surface) == "string" or type(surface) == "number" then
surface = game.surfaces[surface]
if not surface then
error(ERRORPRETEXT .. errorText .. "surface does not exist\n")
elseif not surface.valid then
error(ERRORPRETEXT .. errorText .. "surface.valid is false\n")
end
return surface
else
error(ERRORPRETEXT .. errorText .. "surface is not a string or number\n")
end
else
if not default then
error(ERRORPRETEXT .. errorText .. "no surface specified\n")
else
return default
end
end
end

local function parseLocation(options, optionName, isArea, canHaveSurface, defaultSurface)

assert(options, "no options specified")
local obj = options[optionName]
assert(obj, "no '" .. optionName .. "' option specified")
assert(type(obj) == "table", "option '" .. optionName .. "' must be a table with coordinates")

local surface = nil
if canHaveSurface then
surface = resolveSurface(obj["surface"], defaultSurface, "option '" .. optionName .. "': ")
if obj["surface"] then
obj.surface = nil
end
end

for k, v in pairs(obj) do
if k ~= 1 and k ~= 2 then
error(ERRORPRETEXT .. "option '" .. optionName .. "': invalid key '" .. k .. "'\n")
end
end
if obj[1] and obj[2] then
if isArea then
return { parseLocation(obj, 1), parseLocation(obj, 2) }, surface
else
return { obj[1], obj[2] }, surface
end
else
error(ERRORPRETEXT .. "option '" .. optionName .. "': invalid " .. (isArea and "area" or "point") .. " '" .. serpent.block(obj) .. "'\n")
end

end


-- because of unknown scaling (powers of 2 only allowed, this could change in the future), do not test which parts
-- of the renderbox are a problem, only test if any part of the renderbox can form a chain back to the origin.
local function hasPartialOverlap(a, b)
return b[2][1] > a[1][1] and b[1][1] < a[2][1]
and b[2][2] > a[1][2] and b[1][2] < a[2][2]
end
local function testChainCausality(link, sourceSurface, sourceIndex)
for _, nextLinkIndex in pairs(link.chain or {}) do
local nextLink = fm.API.linkData[link.toSurface][nextLinkIndex]
log(nextLinkIndex .. " " .. sourceIndex)
log(sourceSurface .. " " .. link.toSurface)
if (nextLinkIndex == sourceIndex and sourceSurface == link.toSurface) or not testChainCausality(nextLink, sourceSurface, sourceIndex) then
return false
end
end
return true
end
local function populateRenderChain(newLink, newLinkIndex, fromSurface)

-- scan if other links contain this link in their destination and update them
for _, linkList in pairs(fm.API.linkData or {}) do
for i, link in pairs(linkList) do
if link.chain and link.toSurface == fromSurface and hasPartialOverlap(link.to, newLink.from) then
link.chain[#link.chain+1] = newLinkIndex
end
end
end

-- find other links that are in the destination of this link
newLink.chain = {}
for i, link in pairs(fm.API.linkData[newLink.toSurface] or {}) do
if hasPartialOverlap(newLink.to, link.from) then
newLink.chain[#newLink.chain+1] = i
if not testChainCausality(link, fromSurface, newLinkIndex) then
error(ERRORPRETEXT .. "Renderbox bad causality: can cause an infinite rendering loop\n")
end
end
end
end


local function addLink(type, from, fromSurface, to, toSurface)
if fm.API.linkData[fromSurface.name] == nil then
fm.API.linkData[fromSurface.name] = {}
end
local newLink = {
type = type,
from = from,
to = to,
toSurface = toSurface.name
}
log("adding link type " .. type .. " from " .. fromSurface.name .. " to " .. toSurface.name)
local linkIndex = #fm.API.linkData[fromSurface.name]+1
fm.API.linkData[fromSurface.name][linkIndex] = newLink

if type == "link_renderbox_area" then
populateRenderChain(newLink, linkIndex, fromSurface.name)
end
end




remote.add_interface("factoriomaps", {
get_start_event = function()
return fm.API.startEvent
end,
link_box_point = function(options)
local from, fromSurface = parseLocation(options, "from", true, true)
local to, toSurface = parseLocation(options, "to", false, true, fromSurface)

addLink("link_box_point", from, fromSurface, to, toSurface)
end,
link_box_area = function(options)
local from, fromSurface = parseLocation(options, "from", true, true)
local to, toSurface = parseLocation(options, "to", true, true, fromSurface)

addLink("link_box_area", from, fromSurface, to, toSurface)
end,
link_renderbox_area = function(options)
local from, fromSurface = parseLocation(options, "from", true, true)
local to, toSurface = parseLocation(options, "to", true, true, fromSurface)

local link = addLink("link_renderbox_area", from, fromSurface, to, toSurface)
end,
surface_set_hidden = function(surface, isHidden)
surface = resolveSurface(surface)
if isHidden == true or isHidden == nil then
for _, s in pairs(fm.API.hiddenSurfaces) do
if s == surface then
return
end
end
fm.API.hiddenSurfaces[#fm.API.hiddenSurfaces+1] = surface
elseif isHidden == false then
for i, s in pairs(fm.API.hiddenSurfaces) do
if s == surface then
fm.API.hiddenSurfaces.remove(i)
return
end
end
else
error(ERRORPRETEXT .. "invalid isHidden parameter\n")
end
end
})



function fm.API.pull()
script.raise_event(fm.API.startEvent, {})

remote.remove_interface("factoriomaps")

log(serpent.block(fm.API.linkData))
end

Loading

0 comments on commit 84157cc

Please sign in to comment.