mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 15:14:52 +09:00
Add Transmit/Receive Combinators. Transmit combinators are Deciders which also output into txbuffer.txt. Receive Combinators are Constants which replay frames received from external sources via remote calls to receiveFrame and recieveMany.
This commit is contained in:
1 parent
4f8ad5eec6
commit
f9d6d9e001
5 files changed
+267
-72
No files matched your search
@@ -18,9 +18,15 @@ OUTPUT_TANK_NAME = "get-tank"
|
||||
OUTPUT_TANK_PICTURE_PATH = nil
|
||||
OUTPUT_TANK_ICON_PATH = nil
|
||||
|
||||
MAX_RX_BUFFER_SIZE = 40 -- slightly more than one second
|
||||
RX_COMBINATOR_NAME = "get-combinator"
|
||||
TX_COMBINATOR_NAME = "put-combinator"
|
||||
|
||||
|
||||
OUTPUT_FILE = "output.txt"
|
||||
ORDER_FILE = "orders.txt"
|
||||
TX_BUFFER_FILE = "txbuffer.txt"
|
||||
|
||||
|
||||
UPATE_RATE = 60
|
||||
UPATE_RATE = 60
|
||||
CIRCUIT_UPATE_RATE = 5
|
||||
+156
-42
@@ -43,12 +43,17 @@ function AddEntity(entity)
|
||||
--add the chests to a lists if these chests so they can be interated over
|
||||
global.outputTanks[HashPosition(entity.position)] = entity
|
||||
entity.active = false
|
||||
elseif entity.name == TX_COMBINATOR_NAME then
|
||||
table.insert(global.txControls, entity.get_or_create_control_behavior())
|
||||
elseif entity.name == RX_COMBINATOR_NAME then
|
||||
table.insert(global.rxControls, entity.get_or_create_control_behavior())
|
||||
entity.operable=false
|
||||
end
|
||||
end
|
||||
|
||||
function OnKilledEntity(event)
|
||||
local entity = event.entity
|
||||
if entity.type ~= "entity-ghost" then
|
||||
if entity.type ~= "entity-ghost" then
|
||||
--remove the entities from the tables as they are dead
|
||||
if entity.name == INPUT_CHEST_NAME then
|
||||
global.inputChests[HashPosition(entity.position)] = nil
|
||||
@@ -85,23 +90,29 @@ end)
|
||||
|
||||
|
||||
script.on_event(defines.events.on_tick, function(event)
|
||||
|
||||
|
||||
global.inputChests = global.inputChests or {}
|
||||
global.outputChests = global.outputChests or {}
|
||||
global.inputTanks = global.inputTanks or {}
|
||||
global.outputTanks = global.outputTanks or {}
|
||||
global.outputList = global.outputList or {}
|
||||
global.inputList = global.inputList or {}
|
||||
|
||||
global.rxControls = global.rxControls or {}
|
||||
global.txControls = global.txControls or {}
|
||||
|
||||
|
||||
-- TX Combinators must run every tick to catch single pulses
|
||||
HandleTXCombinators()
|
||||
|
||||
local todo = game.tick % UPATE_RATE
|
||||
|
||||
|
||||
local onlinePlayers = GetOnlinePlayerCount()
|
||||
|
||||
|
||||
if global.previousPlayerCount == nil or global.previousPlayerCount ~= onlinePlayers then
|
||||
Reset()
|
||||
end
|
||||
global.previousPlayerCount = onlinePlayers
|
||||
|
||||
|
||||
if todo == 0 then
|
||||
HandleInputChests()
|
||||
elseif todo == 1 then
|
||||
@@ -114,6 +125,14 @@ script.on_event(defines.events.on_tick, function(event)
|
||||
ExportInputList()
|
||||
elseif todo == 5 then
|
||||
ExportOutputList()
|
||||
end
|
||||
|
||||
local rxstate = game.tick % CIRCUIT_UPATE_RATE
|
||||
-- RX Combinators are set and then cleared on sequential ticks to create pulses
|
||||
if rxstate == 0 then
|
||||
SetRXCombinators()
|
||||
elseif rxstate == 1 then
|
||||
ClearRXCombinators()
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -131,12 +150,12 @@ function Reset()
|
||||
global.outputList = {}
|
||||
global.inputList = {}
|
||||
global.itemStorage = {}
|
||||
|
||||
|
||||
global.inputChests = {}
|
||||
global.outputChests = {}
|
||||
global.inputTanks = {}
|
||||
global.outputTanks = {}
|
||||
|
||||
|
||||
AddAllEntitiesOfName(INPUT_CHEST_NAME)
|
||||
AddAllEntitiesOfName(OUTPUT_CHEST_NAME)
|
||||
AddAllEntitiesOfName(INPUT_TANK_NAME)
|
||||
@@ -171,7 +190,7 @@ function HandleInputTanks()
|
||||
v.fluidbox[1] = fluid
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
function HandleOutputChests()
|
||||
@@ -195,7 +214,7 @@ function HandleOutputChests()
|
||||
--insert the missing items
|
||||
local insertedItemsCount = chestInventory.insert(simpleItemStack)
|
||||
local itemsNotInsertedCount = itemCountAllowedToInsert - insertedItemsCount
|
||||
|
||||
|
||||
if itemsNotInsertedCount > 0 then
|
||||
GiveItemsToStorage(requestItem.name, itemsNotInsertedCount)
|
||||
end
|
||||
@@ -214,16 +233,15 @@ function HandleOutputTanks()
|
||||
local MAX_FLUID_AMOUNT = 1000
|
||||
for k,v in pairs(global.outputTanks) do
|
||||
--.recipe.products[1].name
|
||||
|
||||
if v.recipe ~= nil then
|
||||
local fluidName = v.recipe.products[1].name
|
||||
|
||||
|
||||
--either get the fluid or reset it to the requested fluid
|
||||
local fluid = v.fluidbox[1] or {type = fluidName, amount = 0}
|
||||
if fluid.type ~= fluidName then
|
||||
fluid = {type = fluidName, amount = 0}
|
||||
end
|
||||
|
||||
|
||||
--if any fluid is missing then request the fluid
|
||||
--from store and give either what it's missing or
|
||||
--the rest of the liquid in the system
|
||||
@@ -237,11 +255,11 @@ function HandleOutputTanks()
|
||||
AddItemToOutputList(fluid.type, fluidToRequestAmount)
|
||||
end
|
||||
end
|
||||
|
||||
v.fluidbox[1] = fluid
|
||||
end
|
||||
|
||||
v.fluidbox[1] = fluid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function AddItemToInputList(itemName, itemCount)
|
||||
@@ -261,9 +279,9 @@ function ExportInputList()
|
||||
end
|
||||
global.inputList = {}
|
||||
if #exportStrings > 0 then
|
||||
|
||||
|
||||
--only write to file once as i/o is slow
|
||||
--it's much faster to concatenate all the lines with table.concat
|
||||
--it's much faster to concatenate all the lines with table.concat
|
||||
--instead of doing it with the .. operator
|
||||
game.write_file(OUTPUT_FILE, table.concat(exportStrings), true)
|
||||
end
|
||||
@@ -276,9 +294,9 @@ function ExportOutputList()
|
||||
end
|
||||
global.outputList = {}
|
||||
if #exportStrings > 0 then
|
||||
|
||||
|
||||
--only write to file once as i/o is slow
|
||||
--it's much faster to concatenate all the lines with table.concat
|
||||
--it's much faster to concatenate all the lines with table.concat
|
||||
--instead of doing it with the .. operator
|
||||
game.write_file(ORDER_FILE, table.concat(exportStrings), true)
|
||||
end
|
||||
@@ -296,7 +314,7 @@ function RequestItemsFromStorage(itemName, itemCount)
|
||||
--requested then take the number of items there are left otherwise take the requested amount
|
||||
local itemsTakenFromStorage = math.min(global.itemStorage[itemName], itemCount)
|
||||
global.itemStorage[itemName] = global.itemStorage[itemName] - itemsTakenFromStorage
|
||||
|
||||
|
||||
return itemsTakenFromStorage
|
||||
end
|
||||
|
||||
@@ -311,10 +329,110 @@ end
|
||||
|
||||
|
||||
|
||||
function AddFrameToRXBuffer(frame)
|
||||
-- Add a frame to the buffer. return remaining space in buffer
|
||||
local validsignals = {
|
||||
["virtual"] = game.virtual_signal_prototypes,
|
||||
["fluid"] = game.fluid_prototypes,
|
||||
["item"] = game.item_prototypes
|
||||
}
|
||||
|
||||
global.rxBuffer = global.rxBuffer or {}
|
||||
|
||||
-- if buffer is full, drop frame
|
||||
if #global.rxBuffer >= MAX_RX_BUFFER_SIZE then return 0 end
|
||||
|
||||
-- frame = {{count=42,name="signal-grey",type="virtual"},{...},...}
|
||||
local signals = {}
|
||||
local index = 1
|
||||
|
||||
for _,signal in pairs(frame) do
|
||||
if validsignals[signal.type] and validsignals[signal.type][signal.name] then
|
||||
signals[index] =
|
||||
{
|
||||
index=index,
|
||||
count=signal.count,
|
||||
signal={ name=signal.name, type=signal.type }
|
||||
}
|
||||
index = index + 1
|
||||
--TODO: break if too many?
|
||||
--TODO: error token on mismatched signals? maybe mismatch1-n signals?
|
||||
end
|
||||
end
|
||||
|
||||
if index > 1 then table.insert(global.rxBuffer,signals) end
|
||||
|
||||
return MAX_RX_BUFFER_SIZE - #global.rxBuffer
|
||||
end
|
||||
|
||||
function HandleTXCombinators()
|
||||
-- Check all TX Combinators, and if condition satisfied, add frame to transmit buffer
|
||||
|
||||
-- frame = {{count=42,name="signal-grey",type="virtual"},{...},...}
|
||||
local signals = {["item"]={},["virtual"]={},["fluid"]={}}
|
||||
for i,txControl in pairs(global.txControls) do
|
||||
if txControl.valid then
|
||||
local frame = txControl.signals_last_tick
|
||||
if frame then
|
||||
for _,signal in pairs(frame) do
|
||||
signals[signal.signal.type][signal.signal.name]=
|
||||
(signals[signal.signal.type][signal.signal.name] or 0) + signal.count
|
||||
end
|
||||
end
|
||||
else
|
||||
table.remove(global.txControls,i)
|
||||
end
|
||||
end
|
||||
|
||||
local frame = {}
|
||||
for type,arr in pairs(signals) do
|
||||
for name,count in pairs(arr) do
|
||||
table.insert(frame,{count=count,name=name,type=type})
|
||||
end
|
||||
end
|
||||
|
||||
if #frame > 0 then
|
||||
table.insert(frame,{count=game.tick,name="signal-srctick",type="virtual"})
|
||||
game.write_file(TX_BUFFER_FILE, json:encode(frame).."\n", true)
|
||||
|
||||
-- Loopback for testing
|
||||
--AddFrameToRXBuffer(frame)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function SetRXCombinators()
|
||||
-- if the RX buffer is not empty, get a frame from it and output on all RX Combinators
|
||||
if global.rxBuffer and #global.rxBuffer > 0 then
|
||||
local frame = table.remove(global.rxBuffer)
|
||||
for i,rxControl in pairs(global.rxControls) do
|
||||
if rxControl.valid then
|
||||
rxControl.parameters={parameters=frame}
|
||||
rxControl.enabled=true
|
||||
else
|
||||
table.remove(global.rxControls,i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ClearRXCombinators()
|
||||
-- Clear all RX Combinators.
|
||||
-- This makes them emit pulses, which are easier to
|
||||
-- detect than slowly changing continusous signals.
|
||||
for i,rxControl in pairs(global.rxControls) do
|
||||
if rxControl.valid then
|
||||
rxControl.enabled=false
|
||||
else
|
||||
table.remove(global.rxControls,i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Remote Thing ]]--
|
||||
remote.add_interface("clusterio",
|
||||
remote.add_interface("clusterio",
|
||||
{
|
||||
import = function(itemName, itemCount)
|
||||
import = function(itemName, itemCount)
|
||||
GiveItemsToStorage(itemName, itemCount)
|
||||
end,
|
||||
importMany = function(jsonString)
|
||||
@@ -332,23 +450,19 @@ remote.add_interface("clusterio",
|
||||
end
|
||||
game.print(items)
|
||||
end,
|
||||
reset = Reset
|
||||
reset = Reset,
|
||||
receiveFrame = function(jsonframe)
|
||||
local frame = json:decode(jsonframe)
|
||||
-- frame = {tick=123456,frame={{count=42,name="signal-grey",type="virtual"},{...},...}}
|
||||
return AddFrameToRXBuffer(frame)
|
||||
end,
|
||||
receiveMany = function(jsonframes)
|
||||
local frames = json:decode(jsonframes)
|
||||
local buffer
|
||||
for _,frame in pairs(frames) do
|
||||
buffer = AddFrameToRXBuffer(frame)
|
||||
if buffer==0 then return 0 end
|
||||
end
|
||||
return buffer
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+97
-25
@@ -18,10 +18,10 @@ function MakeLogisticEntity(entity, name, pictureFilename, pictureTablePath, ico
|
||||
ChangePictureFilename(entity, pictureTablePath, pictureFilename)
|
||||
--if no icon is defined then use the default one
|
||||
entity.icon = iconPath or entity.icon
|
||||
|
||||
|
||||
-- add the entity to a technology so it can be unlocked
|
||||
--local wasAddedToTech = AddEntityToTech("construction-robotics", name)
|
||||
|
||||
|
||||
data:extend(
|
||||
{
|
||||
-- add the entity
|
||||
@@ -70,7 +70,7 @@ function AddEntityToTech(techName, name)
|
||||
type = "unlock-recipe",
|
||||
recipe = name
|
||||
}
|
||||
--if a new table for the effects is made then the effects has to be attached to the
|
||||
--if a new table for the effects is made then the effects has to be attached to the
|
||||
-- tech again because the table won't otherwise be owned by the tech
|
||||
data.raw["technology"][techName].effects = effects
|
||||
return true
|
||||
@@ -86,22 +86,10 @@ MakeLogisticEntity(table.deepcopy(data.raw["container"]["iron-chest"]),
|
||||
--make tanks
|
||||
MakeLogisticEntity(table.deepcopy(data.raw["storage-tank"]["storage-tank"]), INPUT_TANK_NAME, INPUT_TANK_PICTURE_PATH, { "pictures", "picture", "sheet" }, INPUT_TANK_ICON_PATH)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------
|
||||
--[[This section is purely to create the output tank]]--
|
||||
--------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local CRAFING_FLUID_CATEGORY_NAME = "crafting-fluids"
|
||||
|
||||
data:extend(
|
||||
@@ -121,10 +109,10 @@ fluidCreator.fluid_boxes =
|
||||
pipe_covers = pipecoverspictures(),
|
||||
base_area = 250,
|
||||
base_level = 1,
|
||||
pipe_connections =
|
||||
pipe_connections =
|
||||
{
|
||||
{
|
||||
type="output", position = {0, 2}
|
||||
{
|
||||
type="output", position = {0, 2}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -157,12 +145,96 @@ for k,v in pairs(data.raw.fluid) do
|
||||
end
|
||||
|
||||
|
||||
-- Virtual signals
|
||||
data:extend{
|
||||
{
|
||||
type = "item-subgroup",
|
||||
name = "virtual-signal-clusterio",
|
||||
group = "signals",
|
||||
order = "e"
|
||||
},
|
||||
{
|
||||
type = "virtual-signal",
|
||||
name = "signal-srctick",
|
||||
icon = "__base__/graphics/icons/signal/signal_grey.png",
|
||||
subgroup = "virtual-signal-clusterio",
|
||||
order = "e[clusterio]-[1srctick]"
|
||||
},
|
||||
--[[{
|
||||
type = "virtual-signal",
|
||||
name = "signal-srcid",
|
||||
icon = "__base__/graphics/icons/signal/signal_grey.png",
|
||||
subgroup = "virtual-signal-clusterio",
|
||||
order = "e[clusterio]-[2srcid]"
|
||||
},]]
|
||||
--[[{
|
||||
type = "virtual-signal",
|
||||
name = "signal-localid",
|
||||
icon = "__base__/graphics/icons/signal/signal_grey.png",
|
||||
subgroup = "virtual-signal-clusterio",
|
||||
order = "e[clusterio]-[3localid]"
|
||||
},]]
|
||||
}
|
||||
|
||||
-- TX Combinator
|
||||
local tx = table.deepcopy(data.raw["decider-combinator"]["decider-combinator"])
|
||||
tx.name = TX_COMBINATOR_NAME
|
||||
tx.minable.result = TX_COMBINATOR_NAME
|
||||
data:extend{
|
||||
tx,
|
||||
{
|
||||
type = "item",
|
||||
name = TX_COMBINATOR_NAME,
|
||||
icon = tx.icon,
|
||||
flags = {"goes-to-quickbar"},
|
||||
subgroup = "storage",
|
||||
place_result=TX_COMBINATOR_NAME,
|
||||
order = "a[items]-b["..TX_COMBINATOR_NAME.."]",
|
||||
stack_size = 50,
|
||||
},
|
||||
{
|
||||
type = "recipe",
|
||||
name = TX_COMBINATOR_NAME,
|
||||
enabled = true, -- TODO do this on a tech somewhere
|
||||
ingredients =
|
||||
{
|
||||
{"decider-combinator", 1},
|
||||
{"electronic-circuit", 3},
|
||||
{"advanced-circuit", 1}
|
||||
},
|
||||
result = TX_COMBINATOR_NAME,
|
||||
requester_paste_multiplier = 1
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- RX Combinator
|
||||
local rx = table.deepcopy(data.raw["constant-combinator"]["constant-combinator"])
|
||||
rx.name = RX_COMBINATOR_NAME
|
||||
rx.minable.result = RX_COMBINATOR_NAME
|
||||
rx.item_slot_count = 100
|
||||
data:extend{
|
||||
rx,
|
||||
{
|
||||
type = "item",
|
||||
name = RX_COMBINATOR_NAME,
|
||||
icon = rx.icon,
|
||||
flags = {"goes-to-quickbar"},
|
||||
subgroup = "storage",
|
||||
place_result=RX_COMBINATOR_NAME,
|
||||
order = "a[items]-b["..RX_COMBINATOR_NAME.."]",
|
||||
stack_size = 50,
|
||||
},
|
||||
{
|
||||
type = "recipe",
|
||||
name = RX_COMBINATOR_NAME,
|
||||
enabled = true, -- TODO do this on a tech somewhere
|
||||
ingredients =
|
||||
{
|
||||
{"constant-combinator", 1},
|
||||
{"electronic-circuit", 3},
|
||||
{"advanced-circuit", 1}
|
||||
},
|
||||
result = RX_COMBINATOR_NAME,
|
||||
requester_paste_multiplier = 1
|
||||
},
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
"title": "Clusterio",
|
||||
"version": "0.0.2",
|
||||
"date": "19-08-2016",
|
||||
"author": "Danielv123 & Keyboardhack",
|
||||
"author": "Danielv123 & Keyboardhack & justarandomgeek",
|
||||
"dependencies": ["base >= 0.13"],
|
||||
"factorio_version": "0.14",
|
||||
"description": "Adds 2 chests to transfer items between saves and servers over the internet."
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,13 @@ put-chest=Put chest
|
||||
get-chest=Get chest
|
||||
put-tank=Put tank
|
||||
get-tank=Get tank
|
||||
|
||||
put-combinator=Transmit combinator
|
||||
get-combinator=Receive combinator
|
||||
|
||||
[item-name]
|
||||
put-chest=Put chest
|
||||
get-chest=Get chest
|
||||
put-tank=Put tank
|
||||
get-tank=Get tank
|
||||
get-tank=Get tank
|
||||
put-combinator=Transmit combinator
|
||||
get-combinator=Receive combinator
|
||||
Reference in new issue
Block a user