Actually use version control

This commit is contained in:
osmarks 2018-04-29 15:17:41 +01:00
commit d30317b8e8
4 changed files with 285 additions and 0 deletions

45
README.md Normal file
View File

@ -0,0 +1,45 @@
# Dragon
A centralized storage management system for Minecraft.
Requires Plethora Peripherals by SquidDev and ideally CC: Tweaked.
## Setup
### Networking & Hardware
```
Chests ───────┐
│ │
Server ─── Buffer
│ │
└────┬─────┘
├────────── Processing (not implemented yet)
├────────── Introspection Module in manipulator (optional)
┌────┴──┬───────┐
Client Client Client
```
**Chests** is a set of chests and/or shulker boxes, connected via networking cables and modems, to the **Server** and **Buffer**.
**Buffer** is a set of two droppers, each with two wired connections - one on the internal side, connected to the chests, and one on the external side, connected to the clients.
**Server** is a computer running `server.lua`. It must be connected to the chests, clients, and both sides of the buffers.
**Client** is a crafty turtle running `client.lua`. It must be connected to the server and external side of the buffers.
**Processing** will be used for autocrafting systems. It is not yet implemented.
**Introspection Module** is an introspection module, bound to a user, in a manipulator. To use it, it must be connected to a client with it configured, and the external side of the buffers. It is recommended that you interact with the client connected to it via a Plethora keyboard.
### Configuration
Configuration must be saved in a file called `conf` (no `.lua` extension). It is in lua table/textutils.serialise syntax.
#### Server/Client
Both server and client require `modem` keys indicating which side their (connected) modems are on.
#### Client
A client requires a `name` key indicating its name on the network. This should be displayed when you rightclick its modem.
If you are using an introspection module, an `introspection` key must be added, indicating the network name of the manipulator it is in.
#### Server
`buffer(In/Out)(External/Internal)` keys must contain the network names of each buffer dropper on the chest-side and client-side networks.
Which buffer is external or internal does not matter, as long as the internal and external network names for out and in point to the same inventory.
## Warnings
* Inserting/extracting items manually into/out of chests will result in the index being desynchronised with the actual items. To remedy this, run `r` in the CLI after doing so.
* Items with different names but the same ID/metadata may be labelled under the wrong name, as the system uses caching to avoid lag-inducing calls on every slot of chests.
* Errors are likely to be very cryptic in this version, as I have not implemented proper error handling.

98
client.lua Normal file
View File

@ -0,0 +1,98 @@
local util = require "util"
local conf = util.conf
rednet.open(conf.modem)
if conf.introspection then
conf.introspection = peripheral.call(conf.introspection, "getInventory")
end
local function split(str, sep)
local t = {}
for sub in str:gmatch("[^" .. sep .. "]+") do
table.insert(t, sub)
end
return t
end
local function fetchItem(item, toGet)
local result
repeat
local toGetNow = 64
if toGet < 64 then toGetNow = toGet end
result = query { cmd = "extract", dname = item, destInv = conf.name, qty = toGetNow }
if result and type(result) == "table" and result[1] then
toGet = toGet - result[1]
end
if conf.introspection then
conf.introspection.pullItems(conf.name, 1)
end
until toGet <= 0 or result == "ERROR"
end
function dump(slot)
if conf.introspection then
conf.introspection.pushItems(conf.name, slot)
slot = 1
end
query { cmd = "insert", fromInv = conf.name, fromSlot = slot }
end
function tryNumber(tokens)
local fst = table.remove(tokens, 1)
local qty = tonumber(fst)
if not qty then
table.insert(tokens, 1, fst)
end
return qty
end
local help = [[
Welcome to the Dragon CLI.
Commands:
w [name] - withdraw all items whose names contain [name]
w [qty] [name] - withdraw [qty] items whose names contain [name]
c - Craft item, using the turtle's inventory as a grid (turtle.craft)
d - Dump all items into storage
d [slot] - Dump items in [slot] into storage
r - Force connected storage server to reindex
help - Display this
This is an unstable version and does not support a GUI or multiple storage servers.]]
print "Dragon CLI"
while true do
write "|> "
local tokens = split(read(), " ")
local cmd = table.remove(tokens, 1)
if cmd == "w" then
local qty = tryNumber(tokens)
if not qty then
qty = math.huge
end
local item = table.concat(tokens, " ")
fetchItem(item, qty)
elseif cmd == "c" then
turtle.craft()
elseif cmd == "d" then
local slot = tryNumber(tokens)
if slot then dump(slot) else
local size = 16
if conf.introspection then size = conf.introspection.size() end
for i = 1, size do
dump(i)
end
end
elseif cmd == "r" then
query { cmd = "reindex" }
elseif cmd == "help" then
textutils.pagedPrint(help)
end
end

128
server.lua Normal file
View File

@ -0,0 +1,128 @@
local util = require "util"
local conf = util.conf
rednet.open(conf.modem)
local inventories = {}
for _, n in pairs(peripheral.getNames()) do
local p = peripheral.wrap(n)
if
string.find(n, "chest") or
string.find(n, "shulker") then
inventories[n] = p
end
end
local nameCache = {}
function cache(item, chest, slot)
local idx = item.name .. ":" .. item.damage
if nameCache[idx] then
return nameCache[idx]
else
local n = chest.getItemMeta(slot).displayName
nameCache[idx] = n
return n
end
end
local index = {}
function updateIndexFor(name)
local inv = inventories[name]
local data = inv.list()
for slot, item in pairs(data) do
data[slot].displayName = cache(item, inv, slot)
end
index[name] = data
end
function updateIndex()
for n in pairs(inventories) do
updateIndexFor(n)
sleep()
end
print "Indexing complete."
end
function find(predicate)
for name, items in pairs(index) do
for slot, item in pairs(items) do
if predicate(item) then
return name, slot, item
end
end
end
end
function findSpace()
for name, items in pairs(index) do
if #items < inventories[name].size() then
return name
end
end
end
function processRequest(msg)
print(textutils.serialise(msg))
if msg.cmd == "extract" then
local inv, slot, item = find(function(item)
return
(not msg.meta or item.damage == msg.meta) and
(not msg.name or item.name == msg.name) and
(not msg.dname or string.find(item.displayName:lower(), msg.dname:lower()))
end)
index[inv][slot] = nil
local moved = peripheral.call(conf.bufferOutInternal, "pullItems", inv, slot, msg.qty or 64, 1)
if msg.destInv then
moved = peripheral.call(conf.bufferOutExternal, "pushItems", msg.destInv, 1)
end
return {moved, item}
elseif msg.cmd == "insert" then
if msg.fromInv and msg.fromSlot then
peripheral.call(conf.bufferInExternal, "pullItems", msg.fromInv, msg.fromSlot, msg.qty or 64, 1)
end
local toInv = findSpace()
if not toInv then return "ERROR" end
peripheral.call(conf.bufferInInternal, "pushItems", toInv, 1)
updateIndexFor(toInv) -- I don't know a good way to figure out where exactly the items went
return "OK"
elseif msg.cmd == "buffers" then
return { conf.bufferInExternal, conf.bufferOutExternal }
elseif msg.cmd == "reindex" then
updateIndex()
return "OK"
elseif msg.cmd == "list" then
return index
elseif msg.cmd == "name" then
msg.meta = msg.meta or 0
return msg.name and msg.meta and nameCache[msg.name .. ":" .. msg.meta]
end
end
function processRequests()
while true do
local id, msg = rednet.receive "dragon"
if msg and msg.cmd then
local ok, r = pcall(processRequest, msg)
if not ok then r = "ERROR" end
rednet.send(id, r, "dragon")
end
end
end
updateIndex()
processRequests()

14
util.lua Normal file
View File

@ -0,0 +1,14 @@
local f = fs.open("conf", "r")
local conf = textutils.unserialise(f.readAll())
f.close()
local function query(m)
local msg
repeat
rednet.broadcast(m, "dragon")
_, msg = rednet.receive("dragon", 1)
until msg
return msg
end
return { conf = conf, query = query }