mirror of
https://github.com/demodude4u/Factorio-FBSR.git
synced 2025-02-19 19:59:54 +02:00
Almost everything but trains and other needless things
This commit is contained in:
commit
04c4c4a394
20
FactorioBlueprintStringRenderer/.classpath
Normal file
20
FactorioBlueprintStringRenderer/.classpath
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
4
FactorioBlueprintStringRenderer/.gitignore
vendored
Normal file
4
FactorioBlueprintStringRenderer/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/bin/
|
||||
/target/
|
||||
/blueprint-string_4.0.0.zip
|
||||
/test.png
|
23
FactorioBlueprintStringRenderer/.project
Normal file
23
FactorioBlueprintStringRenderer/.project
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>FactorioBlueprintStringRenderer</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@ -0,0 +1,12 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
@ -0,0 +1,59 @@
|
||||
eclipse.preferences.version=1
|
||||
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
|
||||
sp_cleanup.add_default_serial_version_id=true
|
||||
sp_cleanup.add_generated_serial_version_id=false
|
||||
sp_cleanup.add_missing_annotations=true
|
||||
sp_cleanup.add_missing_deprecated_annotations=true
|
||||
sp_cleanup.add_missing_methods=false
|
||||
sp_cleanup.add_missing_nls_tags=false
|
||||
sp_cleanup.add_missing_override_annotations=true
|
||||
sp_cleanup.add_missing_override_annotations_interface_methods=true
|
||||
sp_cleanup.add_serial_version_id=false
|
||||
sp_cleanup.always_use_blocks=true
|
||||
sp_cleanup.always_use_parentheses_in_expressions=false
|
||||
sp_cleanup.always_use_this_for_non_static_field_access=false
|
||||
sp_cleanup.always_use_this_for_non_static_method_access=false
|
||||
sp_cleanup.convert_functional_interfaces=false
|
||||
sp_cleanup.convert_to_enhanced_for_loop=false
|
||||
sp_cleanup.correct_indentation=false
|
||||
sp_cleanup.format_source_code=true
|
||||
sp_cleanup.format_source_code_changes_only=false
|
||||
sp_cleanup.insert_inferred_type_arguments=false
|
||||
sp_cleanup.make_local_variable_final=false
|
||||
sp_cleanup.make_parameters_final=false
|
||||
sp_cleanup.make_private_fields_final=true
|
||||
sp_cleanup.make_type_abstract_if_missing_method=false
|
||||
sp_cleanup.make_variable_declarations_final=true
|
||||
sp_cleanup.never_use_blocks=false
|
||||
sp_cleanup.never_use_parentheses_in_expressions=true
|
||||
sp_cleanup.on_save_use_additional_actions=true
|
||||
sp_cleanup.organize_imports=true
|
||||
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
|
||||
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
|
||||
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
|
||||
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
|
||||
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
|
||||
sp_cleanup.remove_private_constructors=true
|
||||
sp_cleanup.remove_redundant_type_arguments=false
|
||||
sp_cleanup.remove_trailing_whitespaces=false
|
||||
sp_cleanup.remove_trailing_whitespaces_all=true
|
||||
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
|
||||
sp_cleanup.remove_unnecessary_casts=true
|
||||
sp_cleanup.remove_unnecessary_nls_tags=false
|
||||
sp_cleanup.remove_unused_imports=false
|
||||
sp_cleanup.remove_unused_local_variables=false
|
||||
sp_cleanup.remove_unused_private_fields=true
|
||||
sp_cleanup.remove_unused_private_members=false
|
||||
sp_cleanup.remove_unused_private_methods=true
|
||||
sp_cleanup.remove_unused_private_types=true
|
||||
sp_cleanup.sort_members=true
|
||||
sp_cleanup.sort_members_all=false
|
||||
sp_cleanup.use_anonymous_class_creation=false
|
||||
sp_cleanup.use_blocks=false
|
||||
sp_cleanup.use_blocks_only_for_return_and_throw=false
|
||||
sp_cleanup.use_lambda=true
|
||||
sp_cleanup.use_parentheses_in_expressions=false
|
||||
sp_cleanup.use_this_for_non_static_field_access=false
|
||||
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
|
||||
sp_cleanup.use_this_for_non_static_method_access=false
|
||||
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
|
@ -0,0 +1,4 @@
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
3
FactorioBlueprintStringRenderer/LUAREADME.txt
Normal file
3
FactorioBlueprintStringRenderer/LUAREADME.txt
Normal file
@ -0,0 +1,3 @@
|
||||
To setup the lua:
|
||||
1. download blueprint string mod (4.0.0 at time of writing), extract into lua folder.
|
||||
2. download numberlua.lua from github/lua-bit-numberlua and put it in a folder named "bit" in the lua folder.
|
2
FactorioBlueprintStringRenderer/lua/.gitignore
vendored
Normal file
2
FactorioBlueprintStringRenderer/lua/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/blueprint-string_4.0.0/
|
||||
/bit/
|
13
FactorioBlueprintStringRenderer/lua/fbsr.lua
Normal file
13
FactorioBlueprintStringRenderer/lua/fbsr.lua
Normal file
@ -0,0 +1,13 @@
|
||||
require "fixmodule"
|
||||
require "demod.fbsr.FBSRBridge"
|
||||
|
||||
local inspect = require "inspect"
|
||||
local BlueprintString = require "blueprintstring"
|
||||
|
||||
require "dataloader"
|
||||
require "core.data"
|
||||
require "base.data"
|
||||
|
||||
local blueprint_table = BlueprintString.fromString(fbsr.decoded())
|
||||
--print(inspect(blueprint_table))
|
||||
fbsr.result(blueprint_table)
|
45
FactorioBlueprintStringRenderer/lua/fixmodule.lua
Normal file
45
FactorioBlueprintStringRenderer/lua/fixmodule.lua
Normal file
@ -0,0 +1,45 @@
|
||||
if not module then
|
||||
function module(modname,...)
|
||||
local function findtable(tbl,fname)
|
||||
for key in string.gmatch(fname,"([%w_]+)") do
|
||||
if key and key~="" then
|
||||
local val = rawget(tbl,key)
|
||||
if not val then
|
||||
local field = {}
|
||||
tbl[key]=field
|
||||
tbl = field
|
||||
elseif type(val)~="table" then
|
||||
return nil
|
||||
else
|
||||
tbl = val
|
||||
end
|
||||
end
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
assert(type(modname)=="string")
|
||||
local value,modul = package.loaded[modname]
|
||||
if type(value)~="table" then
|
||||
modul = findtable(_G,modname)
|
||||
assert(modul,"name conflict for module '"..modname.."'" )
|
||||
package.loaded[modname] = modul
|
||||
else
|
||||
modul = value
|
||||
end
|
||||
|
||||
local name = modul._NAME
|
||||
if not name then
|
||||
modul._M = modul
|
||||
modul._NAME = modname
|
||||
modul._PACKAGE = string.match(modname,"([%w%._]*)%.[%w_]*$")
|
||||
end
|
||||
local func = debug.getinfo(2,"f").func
|
||||
debug.setupvalue(func,1,modul)
|
||||
for _,f in ipairs{...} do f(modul) end
|
||||
end
|
||||
|
||||
function package.seeall(modul)
|
||||
setmetatable(modul,{__index=_G})
|
||||
end
|
||||
end
|
341
FactorioBlueprintStringRenderer/lua/inspect.lua
Normal file
341
FactorioBlueprintStringRenderer/lua/inspect.lua
Normal file
@ -0,0 +1,341 @@
|
||||
local inspect ={
|
||||
_VERSION = 'inspect.lua 3.1.0',
|
||||
_URL = 'http://github.com/kikito/inspect.lua',
|
||||
_DESCRIPTION = 'human-readable representations of tables',
|
||||
_LICENSE = [[
|
||||
MIT LICENSE
|
||||
|
||||
Copyright (c) 2013 Enrique García Cota
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the 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 NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 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.
|
||||
]]
|
||||
}
|
||||
|
||||
local tostring = tostring
|
||||
|
||||
inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end})
|
||||
inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end})
|
||||
|
||||
-- Apostrophizes the string if it has quotes, but not aphostrophes
|
||||
-- Otherwise, it returns a regular quoted string
|
||||
local function smartQuote(str)
|
||||
if str:match('"') and not str:match("'") then
|
||||
return "'" .. str .. "'"
|
||||
end
|
||||
return '"' .. str:gsub('"', '\\"') .. '"'
|
||||
end
|
||||
|
||||
-- \a => '\\a', \0 => '\\0', 31 => '\31'
|
||||
local shortControlCharEscapes = {
|
||||
["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
|
||||
["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v"
|
||||
}
|
||||
local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031
|
||||
for i=0, 31 do
|
||||
local ch = string.char(i)
|
||||
if not shortControlCharEscapes[ch] then
|
||||
shortControlCharEscapes[ch] = "\\"..i
|
||||
longControlCharEscapes[ch] = string.format("\\%03d", i)
|
||||
end
|
||||
end
|
||||
|
||||
local function escape(str)
|
||||
return (str:gsub("\\", "\\\\")
|
||||
:gsub("(%c)%f[0-9]", longControlCharEscapes)
|
||||
:gsub("%c", shortControlCharEscapes))
|
||||
end
|
||||
|
||||
local function isIdentifier(str)
|
||||
return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" )
|
||||
end
|
||||
|
||||
local function isSequenceKey(k, sequenceLength)
|
||||
return type(k) == 'number'
|
||||
and 1 <= k
|
||||
and k <= sequenceLength
|
||||
and math.floor(k) == k
|
||||
end
|
||||
|
||||
local defaultTypeOrders = {
|
||||
['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4,
|
||||
['function'] = 5, ['userdata'] = 6, ['thread'] = 7
|
||||
}
|
||||
|
||||
local function sortKeys(a, b)
|
||||
local ta, tb = type(a), type(b)
|
||||
|
||||
-- strings and numbers are sorted numerically/alphabetically
|
||||
if ta == tb and (ta == 'string' or ta == 'number') then return a < b end
|
||||
|
||||
local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
|
||||
-- Two default types are compared according to the defaultTypeOrders table
|
||||
if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb]
|
||||
elseif dta then return true -- default types before custom ones
|
||||
elseif dtb then return false -- custom types after default ones
|
||||
end
|
||||
|
||||
-- custom types are sorted out alphabetically
|
||||
return ta < tb
|
||||
end
|
||||
|
||||
-- For implementation reasons, the behavior of rawlen & # is "undefined" when
|
||||
-- tables aren't pure sequences. So we implement our own # operator.
|
||||
local function getSequenceLength(t)
|
||||
local len = 1
|
||||
local v = rawget(t,len)
|
||||
while v ~= nil do
|
||||
len = len + 1
|
||||
v = rawget(t,len)
|
||||
end
|
||||
return len - 1
|
||||
end
|
||||
|
||||
local function getNonSequentialKeys(t)
|
||||
local keys = {}
|
||||
local sequenceLength = getSequenceLength(t)
|
||||
for k,_ in pairs(t) do
|
||||
if not isSequenceKey(k, sequenceLength) then table.insert(keys, k) end
|
||||
end
|
||||
table.sort(keys, sortKeys)
|
||||
return keys, sequenceLength
|
||||
end
|
||||
|
||||
local function getToStringResultSafely(t, mt)
|
||||
local __tostring = type(mt) == 'table' and rawget(mt, '__tostring')
|
||||
local str, ok
|
||||
if type(__tostring) == 'function' then
|
||||
ok, str = pcall(__tostring, t)
|
||||
str = ok and str or 'error: ' .. tostring(str)
|
||||
end
|
||||
if type(str) == 'string' and #str > 0 then return str end
|
||||
end
|
||||
|
||||
local function countTableAppearances(t, tableAppearances)
|
||||
tableAppearances = tableAppearances or {}
|
||||
|
||||
if type(t) == 'table' then
|
||||
if not tableAppearances[t] then
|
||||
tableAppearances[t] = 1
|
||||
for k,v in pairs(t) do
|
||||
countTableAppearances(k, tableAppearances)
|
||||
countTableAppearances(v, tableAppearances)
|
||||
end
|
||||
countTableAppearances(getmetatable(t), tableAppearances)
|
||||
else
|
||||
tableAppearances[t] = tableAppearances[t] + 1
|
||||
end
|
||||
end
|
||||
|
||||
return tableAppearances
|
||||
end
|
||||
|
||||
local copySequence = function(s)
|
||||
local copy, len = {}, #s
|
||||
for i=1, len do copy[i] = s[i] end
|
||||
return copy, len
|
||||
end
|
||||
|
||||
local function makePath(path, ...)
|
||||
local keys = {...}
|
||||
local newPath, len = copySequence(path)
|
||||
for i=1, #keys do
|
||||
newPath[len + i] = keys[i]
|
||||
end
|
||||
return newPath
|
||||
end
|
||||
|
||||
local function processRecursive(process, item, path, visited)
|
||||
|
||||
if item == nil then return nil end
|
||||
if visited[item] then return visited[item] end
|
||||
|
||||
local processed = process(item, path)
|
||||
if type(processed) == 'table' then
|
||||
local processedCopy = {}
|
||||
visited[item] = processedCopy
|
||||
local processedKey
|
||||
|
||||
for k,v in pairs(processed) do
|
||||
processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
|
||||
if processedKey ~= nil then
|
||||
processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
|
||||
end
|
||||
end
|
||||
|
||||
local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
|
||||
setmetatable(processedCopy, mt)
|
||||
processed = processedCopy
|
||||
end
|
||||
return processed
|
||||
end
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
local Inspector = {}
|
||||
local Inspector_mt = {__index = Inspector}
|
||||
|
||||
function Inspector:puts(...)
|
||||
local args = {...}
|
||||
local buffer = self.buffer
|
||||
local len = #buffer
|
||||
for i=1, #args do
|
||||
len = len + 1
|
||||
buffer[len] = args[i]
|
||||
end
|
||||
end
|
||||
|
||||
function Inspector:down(f)
|
||||
self.level = self.level + 1
|
||||
f()
|
||||
self.level = self.level - 1
|
||||
end
|
||||
|
||||
function Inspector:tabify()
|
||||
self:puts(self.newline, string.rep(self.indent, self.level))
|
||||
end
|
||||
|
||||
function Inspector:alreadyVisited(v)
|
||||
return self.ids[v] ~= nil
|
||||
end
|
||||
|
||||
function Inspector:getId(v)
|
||||
local id = self.ids[v]
|
||||
if not id then
|
||||
local tv = type(v)
|
||||
id = (self.maxIds[tv] or 0) + 1
|
||||
self.maxIds[tv] = id
|
||||
self.ids[v] = id
|
||||
end
|
||||
return tostring(id)
|
||||
end
|
||||
|
||||
function Inspector:putKey(k)
|
||||
if isIdentifier(k) then return self:puts(k) end
|
||||
self:puts("[")
|
||||
self:putValue(k)
|
||||
self:puts("]")
|
||||
end
|
||||
|
||||
function Inspector:putTable(t)
|
||||
if t == inspect.KEY or t == inspect.METATABLE then
|
||||
self:puts(tostring(t))
|
||||
elseif self:alreadyVisited(t) then
|
||||
self:puts('<table ', self:getId(t), '>')
|
||||
elseif self.level >= self.depth then
|
||||
self:puts('{...}')
|
||||
else
|
||||
if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end
|
||||
|
||||
local nonSequentialKeys, sequenceLength = getNonSequentialKeys(t)
|
||||
local mt = getmetatable(t)
|
||||
local toStringResult = getToStringResultSafely(t, mt)
|
||||
|
||||
self:puts('{')
|
||||
self:down(function()
|
||||
if toStringResult then
|
||||
self:puts(' -- ', escape(toStringResult))
|
||||
if sequenceLength >= 1 then self:tabify() end
|
||||
end
|
||||
|
||||
local count = 0
|
||||
for i=1, sequenceLength do
|
||||
if count > 0 then self:puts(',') end
|
||||
self:puts(' ')
|
||||
self:putValue(t[i])
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
for _,k in ipairs(nonSequentialKeys) do
|
||||
if count > 0 then self:puts(',') end
|
||||
self:tabify()
|
||||
self:putKey(k)
|
||||
self:puts(' = ')
|
||||
self:putValue(t[k])
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
if mt then
|
||||
if count > 0 then self:puts(',') end
|
||||
self:tabify()
|
||||
self:puts('<metatable> = ')
|
||||
self:putValue(mt)
|
||||
end
|
||||
end)
|
||||
|
||||
if #nonSequentialKeys > 0 or mt then -- result is multi-lined. Justify closing }
|
||||
self:tabify()
|
||||
elseif sequenceLength > 0 then -- array tables have one extra space before closing }
|
||||
self:puts(' ')
|
||||
end
|
||||
|
||||
self:puts('}')
|
||||
end
|
||||
end
|
||||
|
||||
function Inspector:putValue(v)
|
||||
local tv = type(v)
|
||||
|
||||
if tv == 'string' then
|
||||
self:puts(smartQuote(escape(v)))
|
||||
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' then
|
||||
self:puts(tostring(v))
|
||||
elseif tv == 'table' then
|
||||
self:putTable(v)
|
||||
else
|
||||
self:puts('<',tv,' ',self:getId(v),'>')
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
function inspect.inspect(root, options)
|
||||
options = options or {}
|
||||
|
||||
local depth = options.depth or math.huge
|
||||
local newline = options.newline or '\n'
|
||||
local indent = options.indent or ' '
|
||||
local process = options.process
|
||||
|
||||
if process then
|
||||
root = processRecursive(process, root, {}, {})
|
||||
end
|
||||
|
||||
local inspector = setmetatable({
|
||||
depth = depth,
|
||||
level = 0,
|
||||
buffer = {},
|
||||
ids = {},
|
||||
maxIds = {},
|
||||
newline = newline,
|
||||
indent = indent,
|
||||
tableAppearances = countTableAppearances(root)
|
||||
}, Inspector_mt)
|
||||
|
||||
inspector:putValue(root)
|
||||
|
||||
return table.concat(inspector.buffer)
|
||||
end
|
||||
|
||||
setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end })
|
||||
|
||||
return inspect
|
||||
|
BIN
FactorioBlueprintStringRenderer/output.png
Normal file
BIN
FactorioBlueprintStringRenderer/output.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 MiB |
44
FactorioBlueprintStringRenderer/pom.xml
Normal file
44
FactorioBlueprintStringRenderer/pom.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>demod.fbsr</groupId>
|
||||
<artifactId>FactorioBlueprintStringRenderer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.luaj</groupId>
|
||||
<artifactId>luaj-jse</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.jopt-simple</groupId>
|
||||
<artifactId>jopt-simple</artifactId>
|
||||
<version>6.0-alpha-1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>20.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20160810</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,95 @@
|
||||
package demod.fbsr;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Point2D.Double;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
|
||||
public class BlueprintEntity {
|
||||
public static enum Direction {
|
||||
NORTH(0, -1), //
|
||||
NORTHEAST(1, -1), //
|
||||
EAST(1, 0), //
|
||||
SOUTHEAST(1, 1), //
|
||||
SOUTH(0, 1), //
|
||||
SOUTHWEST(-1, 1), //
|
||||
WEST(-1, 0), //
|
||||
NORTHWEST(-1, -1);
|
||||
|
||||
public static Direction fromCardinal(int cardinal) {
|
||||
return values()[cardinal * 2];
|
||||
}
|
||||
|
||||
private final int dx;
|
||||
private final int dy;
|
||||
|
||||
private Direction(int dx, int dy) {
|
||||
this.dx = dx;
|
||||
this.dy = dy;
|
||||
}
|
||||
|
||||
public Direction back() {
|
||||
return rotate(4);
|
||||
}
|
||||
|
||||
public int cardinal() {
|
||||
return ordinal() / 2;
|
||||
}
|
||||
|
||||
public Direction left() {
|
||||
return rotate(-2);
|
||||
}
|
||||
|
||||
public Point2D.Double offset(Point2D.Double pos) {
|
||||
return new Point2D.Double(pos.x + dx, pos.y + dy);
|
||||
}
|
||||
|
||||
public Double offset(Point2D.Double pos, double distance) {
|
||||
return new Point2D.Double(pos.x + distance * dx, pos.y + distance * dy);
|
||||
}
|
||||
|
||||
public Rectangle2D.Double offset(Rectangle2D.Double rect, double distance) {
|
||||
return new Rectangle2D.Double(rect.x + distance * dx, rect.y + distance * dy, rect.width, rect.height);
|
||||
}
|
||||
|
||||
public Direction right() {
|
||||
return rotate(2);
|
||||
}
|
||||
|
||||
public Direction rotate(int deltaIndex) {
|
||||
Direction[] values = values();
|
||||
return values[(((ordinal() + deltaIndex) % values.length) + values.length) % values.length];
|
||||
}
|
||||
}
|
||||
|
||||
private final LuaTable lua;
|
||||
private final String name;
|
||||
private final Double position;
|
||||
private final Direction direction;
|
||||
|
||||
public BlueprintEntity(LuaTable entityLua) {
|
||||
this.lua = entityLua;
|
||||
LuaTable positionLua = entityLua.get("position").checktable();
|
||||
|
||||
this.name = entityLua.get("name").toString();
|
||||
this.position = new Point2D.Double(positionLua.get("x").todouble(), positionLua.get("y").todouble());
|
||||
this.direction = Direction.values()[entityLua.get("direction").optint(0)];
|
||||
}
|
||||
|
||||
public Direction getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Double getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public LuaTable lua() {
|
||||
return lua;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package demod.fbsr;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
|
||||
public class DataPrototype {
|
||||
private final LuaTable lua;
|
||||
private final String name;
|
||||
private final String type;
|
||||
|
||||
public DataPrototype(LuaTable lua, String name, String type) {
|
||||
this.lua = lua;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public LuaTable lua() {
|
||||
return lua;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package demod.fbsr;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
|
||||
public class DataTable {
|
||||
private final Map<String, DataPrototype> entities = new HashMap<>();
|
||||
private final Map<String, DataPrototype> items = new HashMap<>();
|
||||
private final Map<String, DataPrototype> recipes = new HashMap<>();
|
||||
private final Map<String, DataPrototype> fluids = new HashMap<>();
|
||||
|
||||
public DataTable(TypeHiearchy typeHiearchy, LuaTable dataLua) {
|
||||
LuaTable rawLua = dataLua.get("raw").checktable();
|
||||
Utils.forEach(rawLua, v -> {
|
||||
Utils.forEach(v.checktable(), protoLua -> {
|
||||
// LuaUtils.debugPrintTableStructure("", protoLua);
|
||||
// System.exit(1);
|
||||
String type = protoLua.get("type").toString();
|
||||
String name = protoLua.get("name").toString();
|
||||
DataPrototype prototype = new DataPrototype(protoLua.checktable(), name, type);
|
||||
if (typeHiearchy.isAssignable("item", type)) {
|
||||
items.put(name, prototype);
|
||||
} else if (typeHiearchy.isAssignable("recipe", type)) {
|
||||
recipes.put(name, prototype);
|
||||
} else if (typeHiearchy.isAssignable("entity", type)) {
|
||||
entities.put(name, prototype);
|
||||
} else if (typeHiearchy.isAssignable("fluid", type)) {
|
||||
fluids.put(name, prototype);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public Map<String, DataPrototype> getEntities() {
|
||||
return entities;
|
||||
}
|
||||
|
||||
public Map<String, DataPrototype> getFluids() {
|
||||
return fluids;
|
||||
}
|
||||
|
||||
public Map<String, DataPrototype> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public Map<String, DataPrototype> getRecipes() {
|
||||
return recipes;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package demod.fbsr;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.TwoArgFunction;
|
||||
import org.luaj.vm2.lib.ZeroArgFunction;
|
||||
|
||||
public class FBSRBridge extends TwoArgFunction {
|
||||
|
||||
private static String blueprintDecoded;
|
||||
private static Consumer<LuaTable> blueprintListener;
|
||||
|
||||
public static void setBlueprintDecoded(String blueprintDecoded) {
|
||||
FBSRBridge.blueprintDecoded = blueprintDecoded;
|
||||
}
|
||||
|
||||
public static void setBlueprintListener(Consumer<LuaTable> blueprintListener) {
|
||||
FBSRBridge.blueprintListener = blueprintListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
LuaValue library = tableOf();
|
||||
library.set("decoded", new ZeroArgFunction() {
|
||||
@Override
|
||||
public LuaValue call() {
|
||||
return valueOf(blueprintDecoded);
|
||||
}
|
||||
});
|
||||
library.set("result", new OneArgFunction() {
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg) {
|
||||
blueprintListener.accept(arg.checktable());
|
||||
return LuaValue.NIL;
|
||||
}
|
||||
});
|
||||
env.set("fbsr", library);
|
||||
return library;
|
||||
}
|
||||
}
|
314
FactorioBlueprintStringRenderer/src/demod/fbsr/FBSRMain.java
Normal file
314
FactorioBlueprintStringRenderer/src/demod/fbsr/FBSRMain.java
Normal file
@ -0,0 +1,314 @@
|
||||
package demod.fbsr;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.luaj.vm2.Globals;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.BaseLib;
|
||||
import org.luaj.vm2.lib.DebugLib;
|
||||
import org.luaj.vm2.lib.ResourceFinder;
|
||||
import org.luaj.vm2.lib.jse.JsePlatform;
|
||||
|
||||
import demod.fbsr.render.Renderer;
|
||||
import demod.fbsr.render.TypeRendererFactory;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpec;
|
||||
|
||||
public class FBSRMain {
|
||||
|
||||
public static final String DEFAULT_FACTORIO = "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Factorio";
|
||||
public static final String DEFAULT_LUA = "lua";
|
||||
private static final String TYPE_SCHEMA = "https://raw.githubusercontent.com/jcranmer/factorio-tools/master/schema.json";
|
||||
|
||||
private static Map<String, BufferedImage> modImageCache = new HashMap<>();
|
||||
private static File factorio;
|
||||
|
||||
private static List<Point2D.Double> debugPoints = new ArrayList<>();
|
||||
|
||||
public static synchronized void debugPoint(Point2D.Double point) {
|
||||
debugPoints.add(point);
|
||||
}
|
||||
|
||||
private static String decode(String blueprint) throws IOException {
|
||||
byte[] bin = Base64.getDecoder().decode(blueprint);
|
||||
try (BufferedReader br = new BufferedReader(
|
||||
new InputStreamReader(new GZIPInputStream(new ByteArrayInputStream(bin))))) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(line);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static BufferedImage getModImage(LuaValue value) {
|
||||
String path = value.toString();
|
||||
return modImageCache.computeIfAbsent(path, p -> {
|
||||
String firstSegment = path.split("\\/")[0];
|
||||
String mod = firstSegment.substring(2, firstSegment.length() - 2);
|
||||
File modFolder = new File(factorio, "data/" + mod);
|
||||
try {
|
||||
return ImageIO.read(new File(modFolder, path.replace(firstSegment, "").substring(1)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException, IOException {
|
||||
setupWorkingDirectory();
|
||||
|
||||
OptionParser optionParser = new OptionParser();
|
||||
optionParser.accepts("?", "Shows help.").forHelp();
|
||||
OptionSpec<File> factorioOption = optionParser.accepts("factorio", "Location of the factorio folder.")
|
||||
.withRequiredArg().ofType(File.class).defaultsTo(new File(DEFAULT_FACTORIO));
|
||||
OptionSpec<File> luaOption = optionParser.accepts("lua", "Location of the needed lua files.").withRequiredArg()
|
||||
.ofType(File.class).defaultsTo(new File(DEFAULT_LUA));
|
||||
OptionSpec<File> inputOption = optionParser.accepts("input", "Location of the blueprint file.")
|
||||
.withRequiredArg().ofType(File.class);
|
||||
OptionSpec<File> outputOption = optionParser.accepts("output", "Location to save the output PNG file.")
|
||||
.withRequiredArg().ofType(File.class).defaultsTo(new File("output.png"));
|
||||
optionParser.accepts("show", "Open image immediately after being saved.");
|
||||
|
||||
OptionSet options = null;
|
||||
try {
|
||||
options = optionParser.parse(args);
|
||||
} catch (UnsupportedOperationException e1) {
|
||||
System.err.println(e1.getMessage());
|
||||
optionParser.printHelpOn(System.err);
|
||||
System.exit(0);
|
||||
}
|
||||
if (options.has("?")) {
|
||||
optionParser.printHelpOn(System.out);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
factorio = options.valueOf(factorioOption);
|
||||
File lua = options.valueOf(luaOption);
|
||||
boolean hasInput = options.has(inputOption);
|
||||
File inputBlueprint = hasInput ? options.valueOf(inputOption) : null;
|
||||
File outputImage = options.valueOf(outputOption);
|
||||
boolean showImage = options.has("show");
|
||||
|
||||
File[] luaFolders = new File[] { //
|
||||
lua, //
|
||||
new File(factorio, "data/core/luaLib"), //
|
||||
new File(factorio, "data"), //
|
||||
new File(factorio, "data/core"), //
|
||||
new File(factorio, "data/base"), //
|
||||
new File(lua, "blueprint-string_4.0.0"), //
|
||||
new File(lua, "blueprint-string_4.0.0/blueprintstring"),//
|
||||
};
|
||||
|
||||
String luaPath = Arrays.stream(luaFolders).map(f -> f.getAbsolutePath() + File.separator + "?.lua")
|
||||
.collect(Collectors.joining(";")).replace('\\', '/');
|
||||
// System.out.println("LUA_PATH: " + luaPath);
|
||||
|
||||
Globals globals = JsePlatform.standardGlobals();
|
||||
globals.load(new BaseLib());
|
||||
globals.load(new DebugLib());
|
||||
globals.load(new StringReader("package.path = package.path .. ';" + luaPath + "'"), "initLuaPath").call();
|
||||
globals.finder = new ResourceFinder() {
|
||||
@Override
|
||||
public InputStream findResource(String filename) {
|
||||
File file = new File(filename);
|
||||
// System.out.println(filename + "? " + file.exists());
|
||||
try {
|
||||
return file.exists() ? new FileInputStream(file) : null;
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
File blueprintFile = inputBlueprint;
|
||||
if (!hasInput) {
|
||||
String[] testBlueprintFiles = Stream.of(new File(".").listFiles()).map(File::getName)
|
||||
.filter(n -> n.endsWith(".blueprint")).toArray(String[]::new);
|
||||
if (testBlueprintFiles.length == 0) {
|
||||
System.err.println(
|
||||
"You have not specified an input file, and there aren't any test files in this folder!");
|
||||
System.exit(-1);
|
||||
}
|
||||
Object choice = JOptionPane.showInputDialog(null, "Test file:", "FBSR", JOptionPane.QUESTION_MESSAGE, null,
|
||||
testBlueprintFiles, testBlueprintFiles[0]);
|
||||
if (choice == null) {
|
||||
return;
|
||||
}
|
||||
blueprintFile = new File(choice.toString());
|
||||
}
|
||||
|
||||
String blueprintEncoded = Files.readAllLines(blueprintFile.toPath()).stream().collect(Collectors.joining());
|
||||
String blueprintDecoded = decode(blueprintEncoded);
|
||||
// System.out.println(blueprintDecoded);
|
||||
|
||||
TypeHiearchy typeHiearchy = new TypeHiearchy(readJsonFromStream(new URL(TYPE_SCHEMA).openStream()));
|
||||
|
||||
FBSRBridge.setBlueprintDecoded(blueprintDecoded);
|
||||
FBSRBridge.setBlueprintListener(blueprint -> {
|
||||
List<BlueprintEntity> blueprintEntities = new ArrayList<>();
|
||||
Utils.forEach(blueprint.get("entities").checktable(),
|
||||
v -> blueprintEntities.add(new BlueprintEntity(v.checktable())));
|
||||
|
||||
DataTable dataTable = new DataTable(typeHiearchy, globals.get("data").checktable());
|
||||
Map<String, DataPrototype> entities = dataTable.getEntities();
|
||||
|
||||
class RenderingTuple {
|
||||
BlueprintEntity entity;
|
||||
DataPrototype prototype;
|
||||
TypeRendererFactory factory;
|
||||
}
|
||||
List<RenderingTuple> renderingTuples = new ArrayList<RenderingTuple>();
|
||||
for (BlueprintEntity entity : blueprintEntities) {
|
||||
RenderingTuple tuple = new RenderingTuple();
|
||||
tuple.entity = entity;
|
||||
tuple.prototype = entities.get(entity.getName());
|
||||
if (tuple.prototype == null) {
|
||||
System.err.println("Cant find prototype for " + entity.getName());
|
||||
continue;
|
||||
}
|
||||
tuple.factory = TypeRendererFactory.forType(tuple.prototype.getType());
|
||||
renderingTuples.add(tuple);
|
||||
}
|
||||
|
||||
WorldMap worldState = new WorldMap();
|
||||
renderingTuples.forEach(t -> t.factory.populateWorldMap(worldState, dataTable, t.entity, t.prototype));
|
||||
|
||||
List<Renderer> renderers = new ArrayList<>();
|
||||
renderingTuples.forEach(
|
||||
t -> t.factory.createRenderers(renderers::add, worldState, dataTable, t.entity, t.prototype));
|
||||
|
||||
BufferedImage render = renderImage((int) Math.round(TypeRendererFactory.tileSize), renderers);
|
||||
try {
|
||||
ImageIO.write(render, "PNG", outputImage);
|
||||
System.out.println(outputImage.getAbsolutePath());
|
||||
if (showImage) {
|
||||
Desktop.getDesktop().open(outputImage);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
globals.load(new FileReader(new File(lua, "fbsr.lua")), "fbsr").call();
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
private static JSONObject readJsonFromStream(InputStream in) throws JSONException, IOException {
|
||||
return new JSONObject(new Scanner(in, "UTF-8").useDelimiter("\\A").next());
|
||||
}
|
||||
|
||||
private static BufferedImage renderImage(int tileSize, List<Renderer> renderers) {
|
||||
Area area = new Area();
|
||||
renderers.forEach(r -> area.add(new Area(r.getBounds())));
|
||||
Rectangle2D bounds = area.getBounds2D();
|
||||
bounds.setFrameFromDiagonal(Math.floor(bounds.getMinX()) - 1, Math.floor(bounds.getMinY()) - 1,
|
||||
Math.ceil(bounds.getMaxX()) + 1, Math.ceil(bounds.getMaxY()) + 1);
|
||||
BufferedImage image = new BufferedImage((int) (bounds.getWidth() * tileSize),
|
||||
(int) (bounds.getHeight() * tileSize), BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
g.scale(image.getWidth() / bounds.getWidth(), image.getHeight() / bounds.getHeight());
|
||||
g.translate(-bounds.getX(), -bounds.getY());
|
||||
g.setColor(new Color(40, 40, 40));
|
||||
g.fill(bounds);
|
||||
g.setStroke(new BasicStroke((float) (3 / TypeRendererFactory.tileSize)));
|
||||
g.setColor(new Color(60, 60, 60));
|
||||
g.setFont(new Font("Courier New", Font.PLAIN, 1).deriveFont(0.3f));
|
||||
for (double x = Math.round(bounds.getMinX()); x <= bounds.getMaxX(); x++) {
|
||||
g.draw(new Line2D.Double(x, bounds.getMinY(), x, bounds.getMaxY()));
|
||||
g.drawString("" + (int) x, (float) x + 0.1f, (float) (bounds.getMinY() + 0.35f));
|
||||
}
|
||||
for (double y = Math.round(bounds.getMinY()); y <= bounds.getMaxY(); y++) {
|
||||
g.draw(new Line2D.Double(bounds.getMinX(), y, bounds.getMaxX(), y));
|
||||
g.drawString("" + (int) y, (float) (bounds.getMinX() + 0.1f), (float) y + 0.35f);
|
||||
}
|
||||
|
||||
renderers.stream().sorted((r1, r2) -> {
|
||||
int ret;
|
||||
|
||||
Rectangle2D.Double b1 = r1.getBounds();
|
||||
Rectangle2D.Double b2 = r2.getBounds();
|
||||
|
||||
ret = Double.compare(b1.getMinY(), b2.getMinY());
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = Double.compare(b1.getMinX(), b2.getMinX());
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = r1.getLayer().compareTo(r2.getLayer());
|
||||
return ret;
|
||||
}).forEach(r -> r.render(g));
|
||||
|
||||
g.setColor(Color.magenta);
|
||||
for (Point2D.Double debugPoint : debugPoints) {
|
||||
g.draw(new Ellipse2D.Double(debugPoint.x - 0.25, debugPoint.y - 0.25, 0.5, 0.5));
|
||||
}
|
||||
|
||||
g.dispose();
|
||||
return image;
|
||||
}
|
||||
|
||||
private static void setupWorkingDirectory() {
|
||||
String className = FBSRMain.class.getName().replace('.', '/');
|
||||
String classJar = FBSRMain.class.getResource("/" + className + ".class").toString();
|
||||
if (classJar.startsWith("jar:")) {
|
||||
try {
|
||||
File jarFolder = new File(
|
||||
FBSRMain.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath())
|
||||
.getParentFile();
|
||||
// System.out.println("Jar Folder: " +
|
||||
// jarFolder.getAbsolutePath());
|
||||
System.setProperty("user.dir", jarFolder.getAbsolutePath());
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package demod.fbsr;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class TypeHiearchy {
|
||||
private final Map<String, String> parents = new HashMap<>();
|
||||
|
||||
public TypeHiearchy(JSONObject json) {
|
||||
for (String key : json.keySet()) {
|
||||
JSONObject typeJson = json.getJSONObject(key);
|
||||
parents.put(key, typeJson.optString("parent"));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAssignable(String type, String subType) {
|
||||
String checkType = subType;
|
||||
while (checkType != null) {
|
||||
if (type.equals(checkType)) {
|
||||
return true;
|
||||
}
|
||||
checkType = parents.get(checkType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
120
FactorioBlueprintStringRenderer/src/demod/fbsr/Utils.java
Normal file
120
FactorioBlueprintStringRenderer/src/demod/fbsr/Utils.java
Normal file
@ -0,0 +1,120 @@
|
||||
package demod.fbsr;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Point2D.Double;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Comparator;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.Varargs;
|
||||
|
||||
public final class Utils {
|
||||
public static int compareRange(double min1, double max1, double min2, double max2) {
|
||||
if (max1 <= min2) {
|
||||
return -1;
|
||||
}
|
||||
if (max2 <= min1) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void debugPrintTable(LuaValue table) {
|
||||
debugPrintTable("", table);
|
||||
}
|
||||
|
||||
private static void debugPrintTable(String prefix, LuaValue table) {
|
||||
forEach(table, (k, v) -> {
|
||||
if (v.istable()) {
|
||||
debugPrintTable(prefix + k + ".", v.checktable());
|
||||
} else {
|
||||
System.out.println(prefix + k + " = " + v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void forEach(LuaValue table, BiConsumer<LuaValue, LuaValue> consumer) {
|
||||
LuaValue k = LuaValue.NIL;
|
||||
while (true) {
|
||||
Varargs n = table.next(k);
|
||||
if ((k = n.arg1()).isnil())
|
||||
break;
|
||||
LuaValue v = n.arg(2);
|
||||
consumer.accept(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
public static void forEach(LuaValue table, Consumer<LuaValue> consumer) {
|
||||
LuaValue k = LuaValue.NIL;
|
||||
while (true) {
|
||||
Varargs n = table.next(k);
|
||||
if ((k = n.arg1()).isnil())
|
||||
break;
|
||||
LuaValue v = n.arg(2);
|
||||
consumer.accept(v);
|
||||
}
|
||||
}
|
||||
|
||||
public static Double parsePoint2D(LuaValue luaValue) {
|
||||
if (luaValue.isnil()) {
|
||||
return new Point2D.Double();
|
||||
}
|
||||
return new Point2D.Double(luaValue.get(1).checkdouble(), luaValue.get(2).checkdouble());
|
||||
}
|
||||
|
||||
public static Rectangle2D.Double parseRectangle(LuaValue value) {
|
||||
LuaTable table = value.checktable();
|
||||
LuaValue p1 = table.get(1);
|
||||
LuaValue p2 = table.get(2);
|
||||
double x1 = p1.get(1).checkdouble();
|
||||
double y1 = p1.get(2).checkdouble();
|
||||
double x2 = p2.get(1).checkdouble();
|
||||
double y2 = p2.get(2).checkdouble();
|
||||
return new Rectangle2D.Double(x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
public static <T> void sortWithNonTransitiveComparator(T[] array, Comparator<T> comparator) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T[] tmp = (T[]) new Object[array.length];
|
||||
sortWithNonTransitiveComparator_MergeSort(array, comparator, tmp, 0, array.length - 1);
|
||||
}
|
||||
|
||||
private static <T> void sortWithNonTransitiveComparator_Merge(T[] a, Comparator<T> comparator, T[] tmp, int left,
|
||||
int right, int rightEnd) {
|
||||
int leftEnd = right - 1;
|
||||
int k = left;
|
||||
int num = rightEnd - left + 1;
|
||||
|
||||
while (left <= leftEnd && right <= rightEnd)
|
||||
if (comparator.compare(a[left], a[right]) <= 0)
|
||||
tmp[k++] = a[left++];
|
||||
else
|
||||
tmp[k++] = a[right++];
|
||||
|
||||
while (left <= leftEnd) // Copy rest of first half
|
||||
tmp[k++] = a[left++];
|
||||
|
||||
while (right <= rightEnd) // Copy rest of right half
|
||||
tmp[k++] = a[right++];
|
||||
|
||||
// Copy tmp back
|
||||
for (int i = 0; i < num; i++, rightEnd--)
|
||||
a[rightEnd] = tmp[rightEnd];
|
||||
}
|
||||
|
||||
private static <T> void sortWithNonTransitiveComparator_MergeSort(T[] a, Comparator<T> comparator, T[] tmp,
|
||||
int left, int right) {
|
||||
if (left < right) {
|
||||
int center = (left + right) / 2;
|
||||
sortWithNonTransitiveComparator_MergeSort(a, comparator, tmp, left, center);
|
||||
sortWithNonTransitiveComparator_MergeSort(a, comparator, tmp, center + 1, right);
|
||||
sortWithNonTransitiveComparator_Merge(a, comparator, tmp, left, center + 1, right);
|
||||
}
|
||||
}
|
||||
|
||||
private Utils() {
|
||||
}
|
||||
}
|
93
FactorioBlueprintStringRenderer/src/demod/fbsr/WorldMap.java
Normal file
93
FactorioBlueprintStringRenderer/src/demod/fbsr/WorldMap.java
Normal file
@ -0,0 +1,93 @@
|
||||
package demod.fbsr;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Table;
|
||||
|
||||
import demod.fbsr.BlueprintEntity.Direction;
|
||||
|
||||
public class WorldMap {
|
||||
|
||||
private final Table<Integer, Integer, Direction> belts = HashBasedTable.create();
|
||||
private final Table<Integer, Integer, Integer> pipes = HashBasedTable.create();
|
||||
private final Table<Integer, Integer, Object> walls = HashBasedTable.create();
|
||||
private final Table<Integer, Integer, Boolean> gates = HashBasedTable.create();
|
||||
|
||||
private int flag(Direction facing) {
|
||||
return 1 << facing.cardinal();
|
||||
}
|
||||
|
||||
public Optional<Direction> getBelt(Point2D.Double pos) {
|
||||
int kr = keyOf(pos.x);
|
||||
int kc = keyOf(pos.y);
|
||||
return Optional.ofNullable(belts.get(kr, kc));
|
||||
}
|
||||
|
||||
public boolean isHorizontalGate(Point2D.Double pos) {
|
||||
int kr = keyOf(pos.x);
|
||||
int kc = keyOf(pos.y);
|
||||
return gates.contains(kr, kc) && (gates.get(kr, kc) == false);
|
||||
}
|
||||
|
||||
public boolean isPipe(Point2D.Double pos, Direction facing) {
|
||||
int kr = keyOf(pos.x);
|
||||
int kc = keyOf(pos.y);
|
||||
return pipes.contains(kr, kc) && (pipes.get(kr, kc) & flag(facing)) > 0;
|
||||
}
|
||||
|
||||
public boolean isVerticalGate(Point2D.Double pos) {
|
||||
int kr = keyOf(pos.x);
|
||||
int kc = keyOf(pos.y);
|
||||
return gates.contains(kr, kc) && (gates.get(kr, kc) == true);
|
||||
}
|
||||
|
||||
public boolean isWall(Point2D.Double pos) {
|
||||
int kr = keyOf(pos.x);
|
||||
int kc = keyOf(pos.y);
|
||||
return walls.contains(kr, kc);
|
||||
}
|
||||
|
||||
private int keyOf(double pos) {
|
||||
return (int) Math.round(pos - 0.5);
|
||||
}
|
||||
|
||||
public void setBelt(Point2D.Double pos, Direction direction) {
|
||||
int kr = keyOf(pos.x);
|
||||
int kc = keyOf(pos.y);
|
||||
belts.put(kr, kc, direction);
|
||||
}
|
||||
|
||||
public void setHorizontalGate(Point2D.Double pos) {
|
||||
int kr = keyOf(pos.x);
|
||||
int kc = keyOf(pos.y);
|
||||
gates.put(kr, kc, false);
|
||||
}
|
||||
|
||||
public void setPipe(Point2D.Double pos, Direction... facings) {
|
||||
int kr = keyOf(pos.x);
|
||||
int kc = keyOf(pos.y);
|
||||
int flags = 0;
|
||||
if (facings.length == 0) {
|
||||
flags = 0b1111;
|
||||
} else {
|
||||
for (Direction facing : facings) {
|
||||
flags |= flag(facing);
|
||||
}
|
||||
}
|
||||
pipes.put(kr, kc, flags);
|
||||
}
|
||||
|
||||
public void setVerticalGate(Point2D.Double pos) {
|
||||
int kr = keyOf(pos.x);
|
||||
int kc = keyOf(pos.y);
|
||||
gates.put(kr, kc, true);
|
||||
}
|
||||
|
||||
public void setWall(Point2D.Double pos) {
|
||||
int kr = keyOf(pos.x);
|
||||
int kc = keyOf(pos.y);
|
||||
walls.put(kr, kc, pos);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class AccumulatorRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("picture"));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class AmmoTurretRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite baseSprite = getSpriteFromAnimation(prototype.lua().get("base_picture").get("layers").get(1));
|
||||
register.accept(spriteRenderer(baseSprite, entity, prototype));
|
||||
LuaValue turretLayers = prototype.lua().get("folded_animation").get("layers");
|
||||
Sprite turretSprite = getSpriteFromAnimation(turretLayers.get(1));
|
||||
turretSprite.source.y += turretSprite.source.height * entity.getDirection().cardinal();
|
||||
register.accept(spriteRenderer(turretSprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class ArithmeticCombinatorRendering extends TypeRendererFactory {
|
||||
public static final Map<String, String> operationSprites = new HashMap<>();
|
||||
static {
|
||||
operationSprites.put("+", "plus_symbol_sprites");
|
||||
operationSprites.put("-", "minus_symbol_sprites");
|
||||
operationSprites.put("*", "multiply_symbol_sprites");
|
||||
operationSprites.put("/", "divide_symbol_sprites");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(
|
||||
prototype.lua().get("sprites").get(entity.getDirection().name().toLowerCase()));
|
||||
Sprite operatorSprite = getSpriteFromAnimation(prototype.lua()
|
||||
.get(operationSprites.get(
|
||||
entity.lua().get("control_behavior").get("arithmetic_conditions").get("operation").toString()))
|
||||
.get(entity.getDirection().name().toLowerCase()));
|
||||
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
register.accept(spriteRenderer(operatorSprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.BlueprintEntity.Direction;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.FBSRMain;
|
||||
import demod.fbsr.Utils;
|
||||
import demod.fbsr.WorldMap;
|
||||
import demod.fbsr.render.Renderer.Layer;
|
||||
|
||||
public class AssemblingMachineRendering extends TypeRendererFactory {
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
super.createRenderers(register, map, dataTable, entity, prototype);
|
||||
|
||||
Sprite sprite = new Sprite();
|
||||
|
||||
LuaValue recipe = entity.lua().get("recipe");
|
||||
if (!recipe.isnil()) {
|
||||
DataPrototype protoRecipe = dataTable.getRecipes().get(recipe.toString());
|
||||
if (protoRecipe.lua().get("icon") != LuaValue.NIL) {
|
||||
sprite.image = FBSRMain.getModImage(protoRecipe.lua().get("icon"));
|
||||
} else {
|
||||
String name;
|
||||
if (protoRecipe.lua().get("results") != LuaValue.NIL) {
|
||||
name = protoRecipe.lua().get("results").get(1).get("name").toString();
|
||||
} else {
|
||||
name = protoRecipe.lua().get("result").toString();
|
||||
}
|
||||
DataPrototype protoProduct = dataTable.getItems().get(name);
|
||||
if (protoProduct == null) {
|
||||
protoProduct = dataTable.getFluids().get(name);
|
||||
}
|
||||
sprite.image = FBSRMain.getModImage(protoProduct.lua().get("icon"));
|
||||
}
|
||||
|
||||
sprite.source = new Rectangle(0, 0, sprite.image.getWidth(), sprite.image.getHeight());
|
||||
sprite.bounds = new Rectangle2D.Double(-0.7, -1.0, 1.4, 1.4);
|
||||
|
||||
Renderer delegate = spriteRenderer(sprite, entity, prototype);
|
||||
register.accept(new Renderer(Layer.OVERLAY2, delegate.getBounds()) {
|
||||
@Override
|
||||
public void render(Graphics2D g) {
|
||||
g.setColor(new Color(0, 0, 0, 180));
|
||||
g.fill(sprite.bounds);
|
||||
delegate.render(g);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
LuaValue recipe = entity.lua().get("recipe");
|
||||
boolean hasFluid = false;
|
||||
if (!recipe.isnil()) {
|
||||
DataPrototype protoRecipe = dataTable.getRecipes().get(recipe.toString());
|
||||
|
||||
List<LuaValue> items = new ArrayList<>();
|
||||
Utils.forEach(protoRecipe.lua().get("ingredients"), (Consumer<LuaValue>) items::add);
|
||||
LuaValue resultsLua = protoRecipe.lua().get("results");
|
||||
if (resultsLua != LuaValue.NIL) {
|
||||
items.add(resultsLua);
|
||||
}
|
||||
hasFluid = items.stream().anyMatch(lua -> {
|
||||
LuaValue typeLua = lua.get("type");
|
||||
return typeLua != LuaValue.NIL && typeLua.toString().equals("fluid");
|
||||
});
|
||||
}
|
||||
|
||||
LuaValue fluidBoxesLua = prototype.lua().get("fluid_boxes");
|
||||
boolean offWhenNoFluidRecipe = fluidBoxesLua.isnil() ? true
|
||||
: fluidBoxesLua.get("off_when_no_fluid_recipe").optboolean(false);
|
||||
|
||||
if (!fluidBoxesLua.isnil() && (!offWhenNoFluidRecipe || hasFluid)) {
|
||||
Utils.forEach(fluidBoxesLua, fluidBoxLua -> {
|
||||
if (!fluidBoxLua.istable()) {
|
||||
return;
|
||||
}
|
||||
Utils.forEach(fluidBoxLua.get("pipe_connections"), pipeConnectionLua -> {
|
||||
Point2D.Double offset = Utils.parsePoint2D(pipeConnectionLua.get("position"));
|
||||
if (Math.abs(offset.y) > Math.abs(offset.x)) {
|
||||
offset.y += -Math.signum(offset.y);
|
||||
} else {
|
||||
offset.x += -Math.signum(offset.x);
|
||||
}
|
||||
Point2D.Double pos = entity.getDirection().left()
|
||||
.offset(entity.getDirection().back().offset(entity.getPosition(), offset.y), offset.x);
|
||||
Direction direction = offset.y > 0 ? entity.getDirection().back() : entity.getDirection();
|
||||
map.setPipe(pos, direction);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class BeaconRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite baseSprite = getSpriteFromAnimation(prototype.lua().get("base_picture"));
|
||||
Sprite antennaSpriteShadow = getSpriteFromAnimation(prototype.lua().get("animation_shadow"));
|
||||
Sprite antennaSprite = getSpriteFromAnimation(prototype.lua().get("animation"));
|
||||
register.accept(spriteRenderer(baseSprite, entity, prototype));
|
||||
register.accept(spriteRenderer(antennaSpriteShadow, entity, prototype));
|
||||
register.accept(spriteRenderer(antennaSprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.BlueprintEntity.Direction;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class BoilerRendering extends TypeRendererFactory {
|
||||
|
||||
public static final String[] pipeSpriteNameMapping = //
|
||||
new String[/* bits WSEN */] { //
|
||||
"down", // ....
|
||||
"down", // ...N
|
||||
"left", // ..E.
|
||||
"right_up", // ..EN
|
||||
"down", // .S..
|
||||
"down", // .S.N
|
||||
"right_down", // .SE.
|
||||
"right_down", // .SEN
|
||||
"left", // W...
|
||||
"left_up", // W..N
|
||||
"left", // W.E.
|
||||
"t_up", // W.EN
|
||||
"left_down", // WS..
|
||||
"t_down", // WS.N
|
||||
"t_down", // WSE.
|
||||
"t_down",// WSEN
|
||||
};
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
int adjCode = 0;
|
||||
adjCode |= ((pipeFacingMeFrom(Direction.NORTH, map, entity) ? 1 : 0) << 0);
|
||||
adjCode |= ((pipeFacingMeFrom(Direction.EAST, map, entity) ? 1 : 0) << 1);
|
||||
adjCode |= ((pipeFacingMeFrom(Direction.SOUTH, map, entity) ? 1 : 0) << 2);
|
||||
adjCode |= ((pipeFacingMeFrom(Direction.WEST, map, entity) ? 1 : 0) << 3);
|
||||
String spriteName = pipeSpriteNameMapping[adjCode];
|
||||
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("structure").get(spriteName));
|
||||
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
|
||||
public boolean pipeFacingMeFrom(Direction direction, WorldMap map, BlueprintEntity entity) {
|
||||
return map.isPipe(direction.offset(entity.getPosition()), direction.back());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
map.setPipe(entity.getPosition());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class ConstantCombinatorRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(
|
||||
prototype.lua().get("sprites").get(entity.getDirection().name().toLowerCase()));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
public class ContainerRendering extends TypeRendererFactory {
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class DeciderCombinatorRendering extends TypeRendererFactory {
|
||||
public static final Map<String, String> operationSprites = new HashMap<>();
|
||||
static {
|
||||
operationSprites.put("=", "equal_symbol_sprites");
|
||||
operationSprites.put(">", "greater_symbol_sprites");
|
||||
operationSprites.put("<", "less_symbol_sprites");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(
|
||||
prototype.lua().get("sprites").get(entity.getDirection().name().toLowerCase()));
|
||||
Sprite operatorSprite = getSpriteFromAnimation(prototype.lua()
|
||||
.get(operationSprites.get(
|
||||
entity.lua().get("control_behavior").get("decider_conditions").get("comparator").toString()))
|
||||
.get(entity.getDirection().name().toLowerCase()));
|
||||
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
register.accept(spriteRenderer(operatorSprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
import demod.fbsr.render.Renderer.Layer;
|
||||
|
||||
public class ElectricPoleRendering extends TypeRendererFactory {
|
||||
|
||||
private static final int SpriteIndex = 2;
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
super.createRenderers(register, map, dataTable, entity, prototype);
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("pictures"));
|
||||
sprite.source.x = sprite.source.width * SpriteIndex;
|
||||
register.accept(spriteRenderer(Layer.ENTITY3, sprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class ElectricTurretRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite baseSprite = getSpriteFromAnimation(prototype.lua().get("base_picture").get("layers").get(1));
|
||||
register.accept(spriteRenderer(baseSprite, entity, prototype));
|
||||
LuaValue turretLayers = prototype.lua().get("folded_animation").get("layers");
|
||||
Sprite turretSprite = getSpriteFromAnimation(turretLayers.get(1));
|
||||
turretSprite.source.y += turretSprite.source.height * entity.getDirection().cardinal();
|
||||
register.accept(spriteRenderer(turretSprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.BlueprintEntity.Direction;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class FluidTurretRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite baseSprite = getSpriteFromAnimation(prototype.lua().get("base_picture")
|
||||
.get(entity.getDirection().name().toLowerCase()).get("layers").get(1));
|
||||
register.accept(spriteRenderer(baseSprite, entity, prototype));
|
||||
LuaValue turretLayers = prototype.lua().get("folded_animation").get(entity.getDirection().name().toLowerCase())
|
||||
.get("layers");
|
||||
Sprite turretSprite = getSpriteFromAnimation(turretLayers.get(1));
|
||||
register.accept(spriteRenderer(turretSprite, entity, prototype));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
Direction dir = entity.getDirection();
|
||||
map.setPipe(dir.right().offset(dir.back().offset(entity.getPosition()), 0.5), dir.right());
|
||||
map.setPipe(dir.left().offset(dir.back().offset(entity.getPosition()), 0.5), dir.left());
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
public class FurnaceRendering extends TypeRendererFactory {
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class GateRendering extends TypeRendererFactory {
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
boolean vertical = isVerticalGate(entity);
|
||||
|
||||
// Point2D.Double pos = entity.getPosition();
|
||||
// boolean northPatch = vertical &&
|
||||
// map.isWall(Direction.NORTH.offset(pos));
|
||||
// boolean eastPatch = !vertical &&
|
||||
// map.isWall(Direction.EAST.offset(pos));
|
||||
// boolean southPatch = vertical &&
|
||||
// map.isWall(Direction.SOUTH.offset(pos));
|
||||
// boolean westPatch = !vertical &&
|
||||
// map.isWall(Direction.WEST.offset(pos));
|
||||
|
||||
String orientation = vertical ? "vertical" : "horizontal";
|
||||
|
||||
LuaValue spriteLayersLua = prototype.lua().get(orientation + "_animation").get("layers");
|
||||
// LuaValue wallPatchLua = prototype.lua().get("wall_patch");
|
||||
// LuaValue northPatchLayersLua = null, eastPatchLayersLua = null,
|
||||
// westPatchLayersLua = null,
|
||||
// southPatchLayersLua = null;
|
||||
|
||||
Sprite spriteShadow = getSpriteFromAnimation(spriteLayersLua.get(2));
|
||||
register.accept(spriteRenderer(spriteShadow, entity, prototype));
|
||||
|
||||
Sprite baseSprite = getSpriteFromAnimation(prototype.lua().get(orientation + "_base").get("layers").get(1));
|
||||
register.accept(spriteRenderer(baseSprite, entity, prototype));
|
||||
|
||||
// TODO Patches need to be rendered on the wall pieces!
|
||||
|
||||
// if (northPatch) {
|
||||
// northPatchLayersLua = wallPatchLua.get("north").get("layers");
|
||||
// Sprite patchSpriteShadow =
|
||||
// getSpriteFromAnimation(northPatchLayersLua.get(2));
|
||||
// register.accept(spriteRenderer(patchSpriteShadow, entity,
|
||||
// prototype));
|
||||
// }
|
||||
// if (eastPatch) {
|
||||
// eastPatchLayersLua = wallPatchLua.get("east").get("layers");
|
||||
// Sprite patchSpriteShadow =
|
||||
// getSpriteFromAnimation(eastPatchLayersLua.get(2));
|
||||
// register.accept(spriteRenderer(patchSpriteShadow, entity,
|
||||
// prototype));
|
||||
// }
|
||||
// if (southPatch) {
|
||||
// southPatchLayersLua = wallPatchLua.get("south").get("layers");
|
||||
// Sprite patchSpriteShadow =
|
||||
// getSpriteFromAnimation(southPatchLayersLua.get(2));
|
||||
// register.accept(spriteRenderer(patchSpriteShadow, entity,
|
||||
// prototype));
|
||||
// }
|
||||
// if (westPatch) {
|
||||
// westPatchLayersLua = wallPatchLua.get("west").get("layers");
|
||||
// Sprite patchSpriteShadow =
|
||||
// getSpriteFromAnimation(westPatchLayersLua.get(2));
|
||||
// register.accept(spriteRenderer(patchSpriteShadow, entity,
|
||||
// prototype));
|
||||
// }
|
||||
//
|
||||
// if (northPatch) {
|
||||
// Sprite patchSprite =
|
||||
// getSpriteFromAnimation(northPatchLayersLua.get(1));
|
||||
// register.accept(spriteRenderer(patchSprite, entity, prototype));
|
||||
// }
|
||||
|
||||
Sprite sprite = getSpriteFromAnimation(spriteLayersLua.get(1));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
|
||||
// if (eastPatch) {
|
||||
// Sprite patchSprite =
|
||||
// getSpriteFromAnimation(eastPatchLayersLua.get(1));
|
||||
// register.accept(spriteRenderer(patchSprite, entity, prototype));
|
||||
// }
|
||||
// if (southPatch) {
|
||||
// Sprite patchSprite =
|
||||
// getSpriteFromAnimation(southPatchLayersLua.get(1));
|
||||
// register.accept(spriteRenderer(patchSprite, entity, prototype));
|
||||
// }
|
||||
// if (westPatch) {
|
||||
// Sprite patchSprite =
|
||||
// getSpriteFromAnimation(westPatchLayersLua.get(1));
|
||||
// register.accept(spriteRenderer(patchSprite, entity, prototype));
|
||||
// }
|
||||
|
||||
// TODO Rail Base if over rail
|
||||
}
|
||||
|
||||
private boolean isVerticalGate(BlueprintEntity entity) {
|
||||
return entity.getDirection().cardinal() % 2 == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
if (isVerticalGate(entity)) {
|
||||
map.setVerticalGate(entity.getPosition());
|
||||
} else {
|
||||
map.setHorizontalGate(entity.getPosition());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.BlueprintEntity.Direction;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class GeneratorRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
debugPrintContext(entity, prototype);
|
||||
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua()
|
||||
.get((entity.getDirection().cardinal() % 2) == 0 ? "vertical_animation" : "horizontal_animation"));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
Direction dir = entity.getDirection();
|
||||
Point2D.Double position = entity.getPosition();
|
||||
map.setPipe(dir.offset(position, 2), dir);
|
||||
map.setPipe(dir.back().offset(position, 2), dir.back());
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class InserterRendering extends TypeRendererFactory {
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
// Utils.debugPrintTable(entity.lua());
|
||||
// System.exit(1);
|
||||
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("platform_picture").get("sheet"));
|
||||
sprite.source.x += sprite.source.width * (entity.getDirection().back().cardinal());
|
||||
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
|
||||
// register.accept(new Renderer(Layer.OVERLAY, entity.getPosition()) {
|
||||
// @Override
|
||||
// public void render(Graphics2D g) {
|
||||
// Point2D.Double pos = entity.getPosition();
|
||||
// Direction forward = entity.getDirection().back();
|
||||
// Direction left = forward.left();
|
||||
//
|
||||
// Point2D.Double pickupOffset =
|
||||
// LuaUtils.parsePoint2D(prototype.lua().get("pickup_position"));
|
||||
// Point2D.Double insertOffset =
|
||||
// LuaUtils.parsePoint2D(prototype.lua().get("insert_position"));
|
||||
//
|
||||
// Point2D.Double pickupPosition = left.offset(forward.offset(pos,
|
||||
// pickupOffset.y), pickupOffset.x);
|
||||
// Point2D.Double insertPosition = left.offset(forward.offset(pos,
|
||||
// insertOffset.y), insertOffset.x);
|
||||
//
|
||||
// Ellipse2D.Double pickupShape = new Ellipse2D.Double(pickupPosition.x
|
||||
// - 0.3, pickupPosition.y - 0.3, 0.6,
|
||||
// 0.6);
|
||||
// Ellipse2D.Double insertShape = new Ellipse2D.Double(insertPosition.x
|
||||
// - 0.2, insertPosition.y - 0.2, 0.4,
|
||||
// 0.4);
|
||||
//
|
||||
// g.setColor(new Color(128, 128, 0, 100));
|
||||
// g.fill(pickupShape);
|
||||
// g.fill(insertShape);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
public class LabRendering extends TypeRendererFactory {
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class LampRendering extends TypeRendererFactory {
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("picture_off"));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
public class LandMineRendering extends TypeRendererFactory {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
public class LogisticContainerRendering extends TypeRendererFactory {
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.Utils;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class MiningDrillRendering extends TypeRendererFactory {
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
if (entity.getName().equals("pumpjack")) {
|
||||
Sprite baseSprite = getSpriteFromAnimation(prototype.lua().get("base_picture").get("sheet"));
|
||||
baseSprite.source.x = baseSprite.source.width * entity.getDirection().cardinal();
|
||||
Sprite jackSprite = getSpriteFromAnimation(prototype.lua().get("animations").get("north"));
|
||||
|
||||
register.accept(spriteRenderer(baseSprite, entity, prototype));
|
||||
register.accept(spriteRenderer(jackSprite, entity, prototype));
|
||||
} else {
|
||||
Sprite sprite = getSpriteFromAnimation(
|
||||
prototype.lua().get("animations").get(entity.getDirection().name().toLowerCase()));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
if (entity.getName().equals("pumpjack")) {
|
||||
|
||||
List<Point2D.Double> positions = new ArrayList<>();
|
||||
Utils.forEach(prototype.lua().get("fluid_box").get("pipe_connections").get(1).get("positions"), l -> {
|
||||
positions.add(Utils.parsePoint2D(l));
|
||||
});
|
||||
|
||||
Point2D.Double entityPos = entity.getPosition();
|
||||
Point2D.Double pipePos = entity.getDirection().back()
|
||||
.offset(positions.get(entity.getDirection().cardinal()));
|
||||
pipePos.x += entityPos.x;
|
||||
pipePos.y += entityPos.y;
|
||||
|
||||
map.setPipe(pipePos, entity.getDirection());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class OffshorePumpRendering extends TypeRendererFactory {
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(
|
||||
prototype.lua().get("picture").get(entity.getDirection().name().toLowerCase()));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
map.setPipe(entity.getPosition(), entity.getDirection().back());
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.BlueprintEntity.Direction;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class PipeRendering extends TypeRendererFactory {
|
||||
|
||||
public static final String[] pipeSpriteNameMapping = //
|
||||
new String[/* bits WSEN */] { //
|
||||
"straight_horizontal", // ....
|
||||
"ending_up", // ...N
|
||||
"ending_right", // ..E.
|
||||
"corner_up_right", // ..EN
|
||||
"ending_down", // .S..
|
||||
"straight_vertical", // .S.N
|
||||
"corner_down_right", // .SE.
|
||||
"t_right", // .SEN
|
||||
"ending_left", // W...
|
||||
"corner_up_left", // W..N
|
||||
"straight_horizontal", // W.E.
|
||||
"t_up", // W.EN
|
||||
"corner_down_left", // WS..
|
||||
"t_left", // WS.N
|
||||
"t_down", // WSE.
|
||||
"cross",// WSEN
|
||||
};
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
int adjCode = 0;
|
||||
adjCode |= ((pipeFacingMeFrom(Direction.NORTH, map, entity) ? 1 : 0) << 0);
|
||||
adjCode |= ((pipeFacingMeFrom(Direction.EAST, map, entity) ? 1 : 0) << 1);
|
||||
adjCode |= ((pipeFacingMeFrom(Direction.SOUTH, map, entity) ? 1 : 0) << 2);
|
||||
adjCode |= ((pipeFacingMeFrom(Direction.WEST, map, entity) ? 1 : 0) << 3);
|
||||
String spriteName = pipeSpriteNameMapping[adjCode];
|
||||
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("pictures").get(spriteName));
|
||||
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
|
||||
public boolean pipeFacingMeFrom(Direction direction, WorldMap map, BlueprintEntity entity) {
|
||||
return map.isPipe(direction.offset(entity.getPosition()), direction.back());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
map.setPipe(entity.getPosition());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class PipeToGroundRendering extends TypeRendererFactory {
|
||||
|
||||
public static String[] pipeToGroundCardinalNaming = { //
|
||||
"up", "right", "down", "left"//
|
||||
};
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(
|
||||
prototype.lua().get("pictures").get(pipeToGroundCardinalNaming[entity.getDirection().cardinal()]));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
map.setPipe(entity.getPosition(), entity.getDirection());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class PowerSwitchRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("power_on_animation"));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class PumpRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(
|
||||
prototype.lua().get("animations").get(entity.getDirection().name().toLowerCase()));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
map.setPipe(entity.getPosition(), entity.getDirection(), entity.getDirection().back());
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class RadarRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("pictures"));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
public abstract class Renderer {
|
||||
public static enum Layer {
|
||||
ENTITY, ENTITY2, ENTITY3, OVERLAY, OVERLAY2;
|
||||
}
|
||||
|
||||
protected final Rectangle2D.Double bounds;
|
||||
protected final Layer layer;
|
||||
|
||||
public Renderer(Layer layer, Point2D.Double position) {
|
||||
this(layer, new Rectangle2D.Double(position.x, position.y, 0, 0));
|
||||
}
|
||||
|
||||
public Renderer(Layer layer, Rectangle2D.Double bounds) {
|
||||
this.layer = layer;
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
public Rectangle2D.Double getBounds() {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public Layer getLayer() {
|
||||
return layer;
|
||||
}
|
||||
|
||||
public abstract void render(Graphics2D g);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class RoboportRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
register.accept(spriteRenderer(getSpriteFromAnimation(prototype.lua().get("base")), entity, prototype));
|
||||
register.accept(
|
||||
spriteRenderer(getSpriteFromAnimation(prototype.lua().get("door_animation_down")), entity, prototype));
|
||||
register.accept(
|
||||
spriteRenderer(getSpriteFromAnimation(prototype.lua().get("door_animation_up")), entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
import demod.fbsr.render.Renderer.Layer;
|
||||
|
||||
public class RocketSiloRendering extends TypeRendererFactory {
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite baseSprite = getSpriteFromAnimation(prototype.lua().get("base_day_sprite"));
|
||||
Sprite shadowSprite = getSpriteFromAnimation(prototype.lua().get("shadow_sprite"));
|
||||
Sprite doorFrontSprite = getSpriteFromAnimation(prototype.lua().get("door_front_sprite"));
|
||||
Sprite doorBackSprite = getSpriteFromAnimation(prototype.lua().get("door_back_sprite"));
|
||||
|
||||
register.accept(spriteRenderer(Layer.ENTITY, shadowSprite, entity, prototype));
|
||||
register.accept(spriteRenderer(Layer.ENTITY, doorFrontSprite, entity, prototype));
|
||||
register.accept(spriteRenderer(Layer.ENTITY, doorBackSprite, entity, prototype));
|
||||
register.accept(spriteRenderer(Layer.ENTITY2, baseSprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class SolarPanelRendering extends TypeRendererFactory {
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("picture"));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.BlueprintEntity.Direction;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
import demod.fbsr.render.Renderer.Layer;
|
||||
|
||||
public class SplitterRendering extends TypeRendererFactory {
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
int[] beltSpriteMapping = TransportBeltRendering.transportBeltSpriteMapping[entity.getDirection()
|
||||
.cardinal()][1];
|
||||
Sprite belt1Sprite = getSpriteFromAnimation(prototype.lua().get("belt_horizontal"));
|
||||
belt1Sprite.source.y = belt1Sprite.source.height * beltSpriteMapping[0];
|
||||
Sprite belt2Sprite = new Sprite(belt1Sprite);
|
||||
|
||||
Point2D.Double beltShift = entity.getDirection().left().offset(new Point2D.Double(), 0.5);
|
||||
|
||||
belt1Sprite.bounds.x += beltShift.x;
|
||||
belt1Sprite.bounds.y += beltShift.y;
|
||||
belt2Sprite.bounds.x -= beltShift.x;
|
||||
belt2Sprite.bounds.y -= beltShift.y;
|
||||
|
||||
Sprite sprite = getSpriteFromAnimation(
|
||||
prototype.lua().get("structure").get(entity.getDirection().toString().toLowerCase()));
|
||||
|
||||
register.accept(spriteRenderer(Layer.ENTITY, belt1Sprite, entity, prototype));
|
||||
register.accept(spriteRenderer(Layer.ENTITY, belt2Sprite, entity, prototype));
|
||||
register.accept(spriteRenderer(Layer.ENTITY2, sprite, entity, prototype));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
Direction direction = entity.getDirection();
|
||||
Point2D.Double belt1Pos = direction.left().offset(entity.getPosition(), 0.5);
|
||||
Point2D.Double belt2Pos = direction.right().offset(entity.getPosition(), 0.5);
|
||||
map.setBelt(belt1Pos, direction);
|
||||
map.setBelt(belt2Pos, direction);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class StorageTankRendering extends TypeRendererFactory {
|
||||
|
||||
public static final int[][][] storageTankPipes = //
|
||||
new int[/* NESW */][/* Points */][/* XY */] { //
|
||||
{ { 1, 1 }, { -1, -1 } }, // North
|
||||
{ { 1, -1 }, { -1, 1 } }, // East
|
||||
{ { 1, 1 }, { -1, -1 } }, // South
|
||||
{ { 1, -1 }, { -1, 1 } },// West
|
||||
};
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("pictures").get("picture").get("sheet"));
|
||||
sprite.source.x = sprite.source.width * (entity.getDirection().cardinal() % 2);
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
// FIXME maybe should use the fluid box
|
||||
|
||||
Point2D.Double position = entity.getPosition();
|
||||
|
||||
int[][] pipePoints = storageTankPipes[entity.getDirection().cardinal()];
|
||||
|
||||
for (int[] point : pipePoints) {
|
||||
map.setPipe(new Point2D.Double(position.x + point[0], position.y + point[1]));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.BlueprintEntity.Direction;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class TransportBeltRendering extends TypeRendererFactory {
|
||||
|
||||
public static final int[][][] transportBeltSpriteMapping = //
|
||||
new int[/* NESW */][/* LNR */][/* SXY */] { //
|
||||
{ { 8, 1, 0 }, { 1, 0, 0 }, { 8, 0, 0 } }, // North
|
||||
{ { 9, 0, 0 }, { 0, 0, 0 }, { 11, 0, 0 } }, // East
|
||||
{ { 10, 1, 0 }, { 1, 0, 1 }, { 10, 0, 0 } }, // South
|
||||
{ { 11, 1, 0 }, { 0, 1, 0 }, { 9, 1, 0 } }, // West
|
||||
};
|
||||
|
||||
public boolean beltFacingMeFrom(UnaryOperator<Direction> rotateFunction, WorldMap map, BlueprintEntity entity) {
|
||||
Point2D.Double adjacentPosition = rotateFunction.apply(entity.getDirection()).offset(entity.getPosition());
|
||||
Optional<Direction> adjacentDirection = map.getBelt(adjacentPosition);
|
||||
return adjacentDirection.map(d -> entity.getPosition().distance(d.offset(adjacentPosition)) < 0.1)
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
boolean left = beltFacingMeFrom(Direction::left, map, entity);
|
||||
boolean right = beltFacingMeFrom(Direction::right, map, entity);
|
||||
boolean back = beltFacingMeFrom(Direction::back, map, entity);
|
||||
|
||||
int bend;
|
||||
if (back || (left && right)) {
|
||||
bend = 1; // none
|
||||
} else if (left) {
|
||||
bend = 0; // from the left
|
||||
} else if (right) {
|
||||
bend = 2; // from the right
|
||||
} else {
|
||||
bend = 1; // none
|
||||
}
|
||||
int[] spriteMapping = transportBeltSpriteMapping[entity.getDirection().cardinal()][bend];
|
||||
|
||||
Sprite sprite = getSpriteFromAnimation(prototype.lua().get("animations"));
|
||||
sprite.source.y = sprite.source.height * spriteMapping[0];
|
||||
if (spriteMapping[1] == 1) {
|
||||
sprite.source.x += sprite.source.width;
|
||||
sprite.source.width *= -1;
|
||||
}
|
||||
if (spriteMapping[2] == 1) {
|
||||
sprite.source.y += sprite.source.height;
|
||||
sprite.source.height *= -1;
|
||||
}
|
||||
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
map.setBelt(entity.getPosition(), entity.getDirection());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,216 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.FBSRMain;
|
||||
import demod.fbsr.Utils;
|
||||
import demod.fbsr.WorldMap;
|
||||
import demod.fbsr.render.Renderer.Layer;
|
||||
|
||||
public class TypeRendererFactory {
|
||||
|
||||
protected static class Sprite {
|
||||
public BufferedImage image;
|
||||
public Rectangle source;
|
||||
public Rectangle2D.Double bounds;
|
||||
|
||||
public Sprite() {
|
||||
}
|
||||
|
||||
public Sprite(Sprite other) {
|
||||
image = other.image;
|
||||
source = new Rectangle(other.source);
|
||||
bounds = new Rectangle2D.Double(other.bounds.x, other.bounds.y, other.bounds.width, other.bounds.height);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> defaultProperties = ImmutableList.of("animation", "off_animation", "structure");
|
||||
protected static final TypeRendererFactory DEFAULT = new TypeRendererFactory() {
|
||||
Set<String> defaultedTypes = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable,
|
||||
BlueprintEntity entity, DataPrototype prototype) {
|
||||
super.createRenderers(register, map, dataTable, entity, prototype);
|
||||
register.accept(new Renderer(Layer.OVERLAY2, entity.getPosition()) {
|
||||
@Override
|
||||
public void render(Graphics2D g) {
|
||||
g.setColor(new Color(255, 0, 255, 128));
|
||||
g.fill(new Rectangle2D.Double(bounds.x - 0.5, bounds.y - 0.5, 1, 1));
|
||||
if (defaultedTypes.add(prototype.getType())) {
|
||||
g.setFont(g.getFont().deriveFont(0.5f));
|
||||
g.setColor(Color.white);
|
||||
g.drawString(prototype.getType(), (float) bounds.x, (float) bounds.y);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private static Map<String, TypeRendererFactory> byType = new HashMap<>();
|
||||
static {
|
||||
byType.put("", DEFAULT);
|
||||
byType.put("accumulator", new AccumulatorRendering());
|
||||
byType.put("ammo-turret", new AmmoTurretRendering());
|
||||
byType.put("arithmetic-combinator", new ArithmeticCombinatorRendering());
|
||||
byType.put("assembling-machine", new AssemblingMachineRendering());
|
||||
byType.put("beacon", new BeaconRendering());
|
||||
byType.put("boiler", new BoilerRendering());
|
||||
byType.put("constant-combinator", new ConstantCombinatorRendering());
|
||||
byType.put("container", new ContainerRendering());
|
||||
byType.put("decider-combinator", new DeciderCombinatorRendering());
|
||||
byType.put("electric-pole", new ElectricPoleRendering());
|
||||
byType.put("electric-turret", new ElectricTurretRendering());
|
||||
byType.put("fluid-turret", new FluidTurretRendering());
|
||||
byType.put("furnace", new FurnaceRendering());
|
||||
byType.put("gate", new GateRendering());
|
||||
byType.put("generator", new GeneratorRendering());
|
||||
byType.put("inserter", new InserterRendering());
|
||||
byType.put("lab", new LabRendering());
|
||||
byType.put("lamp", new LampRendering());
|
||||
byType.put("land-mine", new LandMineRendering());
|
||||
byType.put("logistic-container", new LogisticContainerRendering());
|
||||
byType.put("mining-drill", new MiningDrillRendering());
|
||||
byType.put("offshore-pump", new OffshorePumpRendering());
|
||||
byType.put("pipe", new PipeRendering());
|
||||
byType.put("pipe-to-ground", new PipeToGroundRendering());
|
||||
byType.put("power-switch", new PowerSwitchRendering());
|
||||
byType.put("pump", new PumpRendering());
|
||||
byType.put("radar", new RadarRendering());
|
||||
byType.put("roboport", new RoboportRendering());
|
||||
byType.put("rocket-silo", new RocketSiloRendering());
|
||||
byType.put("solar-panel", new SolarPanelRendering());
|
||||
byType.put("splitter", new SplitterRendering());
|
||||
byType.put("storage-tank", new StorageTankRendering());
|
||||
byType.put("transport-belt", new TransportBeltRendering());
|
||||
byType.put("underground-belt", new UndergroundBeltRendering());
|
||||
byType.put("wall", new WallRendering());
|
||||
}
|
||||
|
||||
public static final double tileSize = 32.0;
|
||||
|
||||
protected static void drawImageInBounds(BufferedImage image, Rectangle source, Rectangle2D.Double bounds,
|
||||
Graphics2D g) {
|
||||
AffineTransform pat = g.getTransform();
|
||||
g.translate(bounds.x, bounds.y);
|
||||
g.scale(bounds.width, bounds.height);
|
||||
g.drawImage(image, 0, 0, 1, 1, source.x, source.y, source.x + source.width, source.y + source.height, null);
|
||||
g.setTransform(pat);
|
||||
}
|
||||
|
||||
protected static void drawSprite(Sprite sprite, Graphics2D g) {
|
||||
drawImageInBounds(sprite.image, sprite.source, sprite.bounds, g);
|
||||
}
|
||||
|
||||
public static TypeRendererFactory forType(String type) {
|
||||
return byType.getOrDefault(type, DEFAULT);
|
||||
}
|
||||
|
||||
protected static Sprite getSpriteFromAnimation(LuaValue lua) {
|
||||
Sprite ret = new Sprite();
|
||||
ret.image = FBSRMain.getModImage(lua.get("filename"));
|
||||
int srcX = lua.get("x").optint(0);
|
||||
int srcY = lua.get("y").optint(0);
|
||||
int srcWidth = lua.get("width").checkint();
|
||||
double width = srcWidth / tileSize;
|
||||
int srcHeight = lua.get("height").checkint();
|
||||
double height = srcHeight / tileSize;
|
||||
Point2D.Double shift = Utils.parsePoint2D(lua.get("shift"));
|
||||
ret.source = new Rectangle(srcX, srcY, srcWidth, srcHeight);
|
||||
ret.bounds = new Rectangle2D.Double(shift.x - width / 2.0, shift.y - height / 2.0, width, height);
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected static Renderer spriteRenderer(Layer layer, Sprite sprite, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Point2D.Double pos = entity.getPosition();
|
||||
sprite.bounds.x += pos.x;
|
||||
sprite.bounds.y += pos.y;
|
||||
Rectangle2D.Double groundBounds = Utils.parseRectangle(prototype.lua().get("collision_box"));
|
||||
groundBounds.x += pos.x;
|
||||
groundBounds.y += pos.y;
|
||||
return new Renderer(layer, groundBounds) {
|
||||
@Override
|
||||
public void render(Graphics2D g) {
|
||||
drawSprite(sprite, g);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected static Renderer spriteRenderer(Sprite sprite, BlueprintEntity entity, DataPrototype prototype) {
|
||||
return spriteRenderer(Layer.ENTITY, sprite, entity, prototype);
|
||||
}
|
||||
|
||||
// protected final String type;
|
||||
|
||||
// protected TypeRendererFactory(String type) {
|
||||
// this.type = type;
|
||||
// }
|
||||
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
try {
|
||||
Sprite sprite;
|
||||
|
||||
Optional<LuaValue> findSpriteLua = defaultProperties.stream().map(p -> prototype.lua().get(p))
|
||||
.filter(l -> l != LuaValue.NIL).findAny();
|
||||
|
||||
if (findSpriteLua.isPresent()) {
|
||||
LuaValue spriteLua = findSpriteLua.get();
|
||||
|
||||
boolean hasDir = spriteLua.get(entity.getDirection().name().toLowerCase()) != LuaValue.NIL;
|
||||
if (hasDir) {
|
||||
spriteLua = spriteLua.get(entity.getDirection().name().toLowerCase());
|
||||
}
|
||||
|
||||
sprite = getSpriteFromAnimation(spriteLua);
|
||||
} else {
|
||||
sprite = new Sprite();
|
||||
sprite.image = FBSRMain.getModImage(prototype.lua().get("icon"));
|
||||
sprite.source = new Rectangle(0, 0, sprite.image.getWidth(), sprite.image.getHeight());
|
||||
sprite.bounds = Utils.parseRectangle(prototype.lua().get("selection_box"));
|
||||
}
|
||||
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
} catch (RuntimeException e) {
|
||||
debugPrintContext(entity, prototype);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
protected void debugPrintContext(BlueprintEntity entity, DataPrototype prototype) {
|
||||
System.out.println("=================================================================");
|
||||
System.out.println("=========================== PROTOTYPE ===========================");
|
||||
System.out.println("=================================================================");
|
||||
Utils.debugPrintTable(prototype.lua());
|
||||
System.out.println("=================================================================");
|
||||
System.out.println("============================ ENTITY =============================");
|
||||
System.out.println("=================================================================");
|
||||
Utils.debugPrintTable(entity.lua());
|
||||
}
|
||||
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
// default do nothing
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.BlueprintEntity.Direction;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.WorldMap;
|
||||
import demod.fbsr.render.Renderer.Layer;
|
||||
|
||||
public class UndergroundBeltRendering extends TypeRendererFactory {
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
// LuaUtils.debugPrintTable("", prototype.lua());
|
||||
// System.exit(1);
|
||||
|
||||
boolean input = entity.lua().get("type").toString().equals("input");
|
||||
Direction structDir = input ? entity.getDirection() : entity.getDirection().back();
|
||||
|
||||
int[] beltSpriteMapping = TransportBeltRendering.transportBeltSpriteMapping[entity.getDirection()
|
||||
.cardinal()][1];
|
||||
Sprite beltSprite = getSpriteFromAnimation(prototype.lua().get("belt_horizontal"));
|
||||
beltSprite.source.y = beltSprite.source.height * beltSpriteMapping[0];
|
||||
if (beltSpriteMapping[1] == 1) {
|
||||
beltSprite.source.x += beltSprite.source.width;
|
||||
beltSprite.source.width *= -1;
|
||||
}
|
||||
if (beltSpriteMapping[2] == 1) {
|
||||
beltSprite.source.y += beltSprite.source.height;
|
||||
beltSprite.source.height *= -1;
|
||||
}
|
||||
switch (structDir) {
|
||||
case NORTH:
|
||||
beltSprite.source.height /= 2;
|
||||
beltSprite.source.y += beltSprite.source.height;
|
||||
beltSprite.bounds.height /= 2;
|
||||
beltSprite.bounds.y += beltSprite.bounds.height;
|
||||
break;
|
||||
case WEST:
|
||||
beltSprite.source.width /= 2;
|
||||
beltSprite.source.x += beltSprite.source.width;
|
||||
beltSprite.bounds.width /= 2;
|
||||
beltSprite.bounds.x += beltSprite.bounds.width;
|
||||
break;
|
||||
case EAST:
|
||||
beltSprite.source.width /= 2;
|
||||
beltSprite.bounds.width /= 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Sprite sprite = getSpriteFromAnimation(
|
||||
prototype.lua().get("structure").get(input ? "direction_in" : "direction_out").get("sheet"));
|
||||
sprite.source.x += sprite.source.width * (structDir.cardinal());
|
||||
|
||||
register.accept(spriteRenderer(Layer.ENTITY, beltSprite, entity, prototype));
|
||||
register.accept(spriteRenderer(Layer.ENTITY2, sprite, entity, prototype));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
boolean input = entity.lua().get("type").toString().equals("input");
|
||||
if (!input) {
|
||||
map.setBelt(entity.getPosition(), entity.getDirection());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package demod.fbsr.render;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
import demod.fbsr.BlueprintEntity;
|
||||
import demod.fbsr.BlueprintEntity.Direction;
|
||||
import demod.fbsr.DataPrototype;
|
||||
import demod.fbsr.DataTable;
|
||||
import demod.fbsr.Utils;
|
||||
import demod.fbsr.WorldMap;
|
||||
|
||||
public class WallRendering extends TypeRendererFactory {
|
||||
|
||||
public static final String[] wallSpriteNameMapping = //
|
||||
new String[/* bits WSEN */] { //
|
||||
"single", // ....
|
||||
"single", // ...N
|
||||
"ending_right", // ..E.
|
||||
"ending_right", // ..EN
|
||||
"straight_vertical", // .S..
|
||||
"straight_vertical", // .S.N
|
||||
"corner_right_down", // .SE.
|
||||
"corner_right_down", // .SEN
|
||||
"ending_left", // W...
|
||||
"ending_left", // W..N
|
||||
"straight_horizontal", // W.E.
|
||||
"straight_horizontal", // W.EN
|
||||
"corner_left_down", // WS..
|
||||
"corner_left_down", // WS.N
|
||||
"t_up", // WSE.
|
||||
"t_up",// WSEN
|
||||
};
|
||||
|
||||
@Override
|
||||
public void createRenderers(Consumer<Renderer> register, WorldMap map, DataTable dataTable, BlueprintEntity entity,
|
||||
DataPrototype prototype) {
|
||||
Point2D.Double pos = entity.getPosition();
|
||||
|
||||
boolean northGate = map.isVerticalGate(Direction.NORTH.offset(pos));
|
||||
boolean eastGate = map.isHorizontalGate(Direction.EAST.offset(pos));
|
||||
boolean southGate = map.isVerticalGate(Direction.SOUTH.offset(pos));
|
||||
boolean westGate = map.isHorizontalGate(Direction.WEST.offset(pos));
|
||||
|
||||
int adjCode = 0;
|
||||
adjCode |= ((map.isWall(Direction.NORTH.offset(pos)) || northGate ? 1 : 0) << 0);
|
||||
adjCode |= ((map.isWall(Direction.EAST.offset(pos)) || eastGate ? 1 : 0) << 1);
|
||||
adjCode |= ((map.isWall(Direction.SOUTH.offset(pos)) || southGate ? 1 : 0) << 2);
|
||||
adjCode |= ((map.isWall(Direction.WEST.offset(pos)) || westGate ? 1 : 0) << 3);
|
||||
String spriteName = wallSpriteNameMapping[adjCode];
|
||||
|
||||
LuaValue spriteLua = prototype.lua().get("pictures").get(spriteName);
|
||||
|
||||
List<LuaValue> layersChoices = new ArrayList<>();
|
||||
if (spriteLua.get("layers") != LuaValue.NIL) {
|
||||
layersChoices.add(spriteLua.get("layers"));
|
||||
} else {
|
||||
Utils.forEach(spriteLua, l -> layersChoices.add(l.get("layers")));
|
||||
}
|
||||
LuaValue layersLua = layersChoices.get(Math.abs((int) pos.x + (int) pos.y) % layersChoices.size());
|
||||
|
||||
Sprite sprite = getSpriteFromAnimation(layersLua.get(1));
|
||||
Sprite spriteShadow = getSpriteFromAnimation(layersLua.get(2));
|
||||
|
||||
register.accept(spriteRenderer(spriteShadow, entity, prototype));
|
||||
register.accept(spriteRenderer(sprite, entity, prototype));
|
||||
|
||||
if (northGate || eastGate || southGate || westGate) {
|
||||
Sprite wallDiodeSprite = getSpriteFromAnimation(prototype.lua().get("wall_diode_red"));
|
||||
register.accept(spriteRenderer(wallDiodeSprite, entity, prototype));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateWorldMap(WorldMap map, DataTable dataTable, BlueprintEntity entity, DataPrototype prototype) {
|
||||
map.setWall(entity.getPosition());
|
||||
}
|
||||
}
|
34
FactorioBlueprintStringRenderer/testAll.blueprint
Normal file
34
FactorioBlueprintStringRenderer/testAll.blueprint
Normal file
@ -0,0 +1,34 @@
|
||||
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
|
@ -0,0 +1,65 @@
|
||||
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
|
||||
49P/A4luUqQBJQEA
|
26
FactorioBlueprintStringRenderer/testHeavyWall.blueprint
Normal file
26
FactorioBlueprintStringRenderer/testHeavyWall.blueprint
Normal file
@ -0,0 +1,26 @@
|
||||
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
|
||||
p+PvfNhtPnz+1G9u/wEgF0qJcncAAA==
|
@ -0,0 +1,16 @@
|
||||
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
|
20
FactorioBlueprintStringRenderer/testYRBBeltComplex.blueprint
Normal file
20
FactorioBlueprintStringRenderer/testYRBBeltComplex.blueprint
Normal file
@ -0,0 +1,20 @@
|
||||
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
|
||||
6Z5UAAA=
|
Loading…
x
Reference in New Issue
Block a user