Skip to content

Commit c09cd06

Browse files
added basic application apis
1 parent ad345d1 commit c09cd06

File tree

7 files changed

+380
-17
lines changed

7 files changed

+380
-17
lines changed

link.bat

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
mklink /j "c:\users\%username%\programs\dw20server\world\computer\0" "%~dp0src"
2+
mklink /j "c:\users\%username%\programs\dw20server\world\computer\1" "%~dp0src"
3+
mklink /j "c:\users\%username%\programs\dw20server\world\computer\2" "%~dp0src"
4+
mklink /j "c:\users\%username%\programs\dw20server\world\computer\3" "%~dp0src"
5+
mklink /j "c:\users\%username%\programs\dw20server\world\computer\4" "%~dp0src"
6+
mklink /j "c:\users\%username%\programs\dw20server\world\computer\5" "%~dp0src"
7+
mklink /j "c:\users\%username%\programs\dw20server\world\computer\6" "%~dp0src"

src/beacon

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
function net_beacon(...)
3+
print('net_beacon')
4+
print(unpack(...))
5+
end
6+
7+
application.new(getfenv())

src/lib/application

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
os.loadAPI('/lib/move')
2+
os.loadAPI('/lib/json')
3+
local defaultChannel = 7000
4+
5+
-- application.new(getfenv())
6+
7+
function new(application)
8+
application.move = move
9+
application.json = json
10+
11+
--- NETWORKING:
12+
function send(protocol, ...)
13+
local position = move.position():round()
14+
local heading = move.heading():round()
15+
local data = {
16+
protocol = protocol,
17+
['clock'] = os.clock(),
18+
label = os.getComputerLabel(),
19+
position = position,
20+
heading = heading,
21+
...
22+
}
23+
application.network.modem.transmit(application.network.channel, application.network.channel + os.getComputerID(), json.encode(data))
24+
end
25+
application.network = {
26+
channel = defaultChannel,
27+
send = send
28+
}
29+
function wirelessModem(side)
30+
local modem = peripheral.wrap(side)
31+
if modem.isWireless() then return modem end
32+
error('Not a Wireless Modem')
33+
end
34+
if not pcall(function () application.network.modem = wirelessModem('right') end) then
35+
if not pcall(function () application.network.modem = wirelessModem('left') end) then
36+
if not pcall(function () application.network.modem = wirelessModem('back') end) then
37+
if not pcall(function () application.network.modem = wirelessModem('top') end) then
38+
if not pcall(function () application.network.modem = wirelessModem('bottom') end) then
39+
if not pcall(function () application.network.modem = wirelessModem('front') end) then
40+
error('No Wireless Modem Installed?')
41+
end
42+
end
43+
end
44+
end
45+
end
46+
end
47+
application.network.modem.open(application.network.channel)
48+
application.network.modem.open(application.network.channel + os.getComputerID())
49+
50+
--- THREADING:
51+
local event
52+
local packet
53+
local arguments
54+
local threads = {
55+
coroutine.create(function ()
56+
while true do
57+
application.network.send('beacon')
58+
sleep(1 + math.random())
59+
end
60+
end)
61+
}
62+
local listeners = {}
63+
local terminated = false
64+
function resume(thread)
65+
local listener = listeners[thread]
66+
if (listener == nil) or (listener == event) then
67+
local success, result = coroutine.resume(thread, event, unpack(arguments))
68+
if success then
69+
return result
70+
else
71+
printError(result, '@ ', event, ' ', arguments[1], ' ', arguments[2], ' ', arguments[3], ' ', arguments[4])
72+
return nil
73+
end
74+
else
75+
return listener
76+
end
77+
end
78+
os.queueEvent('start')
79+
while not terminated do
80+
if packet then
81+
arguments, packet = packet, nil
82+
else
83+
arguments = {os.pullEvent()}
84+
end
85+
event = table.remove(arguments, 1)
86+
print(event, ' ', arguments[1], ' ', arguments[2], ' ', arguments[3], ' ', arguments[4])
87+
if event == 'terminate' then
88+
os.queueEvent('terminate')
89+
terminated = true
90+
else
91+
if type(application[event]) == 'function' then
92+
local thread = coroutine.create(function ()
93+
application[event](unpack(arguments))
94+
end)
95+
listeners[thread] = event
96+
table.insert(threads, thread)
97+
end
98+
local index = 1
99+
local thread = threads[index]
100+
while thread do
101+
listeners[thread] = resume(thread)
102+
if coroutine.status(thread) == 'dead' then
103+
table.remove(threads, index)
104+
else
105+
index = index + 1
106+
end
107+
thread = threads[index]
108+
end
109+
if event == 'modem_message' then
110+
xpcall(function ()
111+
local side, channel, reply, message, distance = unpack(arguments)
112+
local data = json.decode(message)
113+
local protocol = table.remove(data, 1)
114+
if application['net_'..protocol] ~= nil then
115+
local sender = {
116+
id = reply - application.network.channel,
117+
distance = distance,
118+
channel = channel,
119+
protocol = protocol,
120+
['clock'] = table.remove(data, 1),
121+
label = table.remove(data, 1),
122+
position = move.tovector(table.remove(data, 1)),
123+
heading = move.tovector(table.remove(data, 1))
124+
}
125+
data._ = nil
126+
local receiver = {
127+
id = os.getComputerID(),
128+
distance = 0.0,
129+
channel = channel,
130+
protocol = protocol,
131+
['clock'] = os.clock(),
132+
label = os.getComputerLabel(),
133+
location = move.locations.location,
134+
global = move.locations.global,
135+
side = side
136+
}
137+
packet = { 'net_'..protocol, data, sender, receiver, message }
138+
end
139+
end, function (errors)
140+
printError(errors, '\n@ ', event, ' ', arguments[1], ',', arguments[2], ',', arguments[3], ',', arguments[4])
141+
end)
142+
end
143+
end
144+
end
145+
if application.terminate then
146+
application.terminate()
147+
end
148+
end
149+
150+
--- Workaround to jumpstart the event loop on "startup":
151+
sleep()

src/lib/json

+193
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
------------------------------------------------------------------ utils
2+
local controls = {["\n"]="\\n", ["\r"]="\\r", ["\t"]="\\t", ["\b"]="\\b", ["\f"]="\\f", ["\""]="\\\"", ["\\"]="\\\\"}
3+
4+
local function isArray(t)
5+
local max = 0
6+
for k,v in pairs(t) do
7+
if type(k) ~= "number" then
8+
return false
9+
elseif k > max then
10+
max = k
11+
end
12+
end
13+
return max == #t
14+
end
15+
16+
local whites = {['\n']=true; ['r']=true; ['\t']=true; [' ']=true; [',']=true; [':']=true}
17+
function removeWhite(str)
18+
while whites[str:sub(1, 1)] do
19+
str = str:sub(2)
20+
end
21+
return str
22+
end
23+
24+
------------------------------------------------------------------ encoding
25+
26+
local function encodeCommon(val, pretty, tabLevel, tTracking)
27+
local str = ""
28+
29+
-- Tabbing util
30+
local function tab(s)
31+
str = str .. ("\t"):rep(tabLevel) .. s
32+
end
33+
34+
local function arrEncoding(val, bracket, closeBracket, iterator, loopFunc)
35+
str = str .. bracket
36+
if pretty then
37+
str = str .. "\n"
38+
tabLevel = tabLevel + 1
39+
end
40+
for k,v in iterator(val) do
41+
tab("")
42+
loopFunc(k,v)
43+
str = str .. ","
44+
if pretty then str = str .. "\n" end
45+
end
46+
if pretty then
47+
tabLevel = tabLevel - 1
48+
end
49+
if str:sub(-2) == ",\n" then
50+
str = str:sub(1, -3) .. "\n"
51+
elseif str:sub(-1) == "," then
52+
str = str:sub(1, -2)
53+
end
54+
tab(closeBracket)
55+
end
56+
57+
-- Table encoding
58+
if type(val) == "table" then
59+
assert(not tTracking[val], "Cannot encode a table holding itself recursively")
60+
tTracking[val] = true
61+
if isArray(val) then
62+
arrEncoding(val, "[", "]", ipairs, function(k,v)
63+
str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
64+
end)
65+
else
66+
arrEncoding(val, "{", "}", pairs, function(k,v)
67+
assert(type(k) == "string", "JSON object keys must be strings", 2)
68+
str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
69+
str = str .. (pretty and ": " or ":") .. encodeCommon(v, pretty, tabLevel, tTracking)
70+
end)
71+
end
72+
-- String encoding
73+
elseif type(val) == "string" then
74+
str = '"' .. val:gsub("[%c\"\\]", controls) .. '"'
75+
-- Number encoding
76+
elseif type(val) == "number" or type(val) == "boolean" then
77+
str = tostring(val)
78+
else
79+
error("JSON only supports arrays, objects, numbers, booleans, and strings", 2)
80+
end
81+
return str
82+
end
83+
84+
function encode(val)
85+
return encodeCommon(val, false, 0, {})
86+
end
87+
88+
function encodePretty(val)
89+
return encodeCommon(val, true, 0, {})
90+
end
91+
92+
------------------------------------------------------------------ decoding
93+
94+
function parseBoolean(str)
95+
if str:sub(1, 4) == "true" then
96+
return true, removeWhite(str:sub(5))
97+
else
98+
return false, removeWhite(str:sub(6))
99+
end
100+
end
101+
102+
function parseNull(str)
103+
return nil, removeWhite(str:sub(5))
104+
end
105+
106+
local numChars = {['e']=true; ['E']=true; ['+']=true; ['-']=true; ['.']=true}
107+
function parseNumber(str)
108+
local i = 1
109+
while numChars[str:sub(i, i)] or tonumber(str:sub(i, i)) do
110+
i = i + 1
111+
end
112+
local val = tonumber(str:sub(1, i - 1))
113+
str = removeWhite(str:sub(i))
114+
return val, str
115+
end
116+
117+
function parseString(str)
118+
local i,j = str:find('[^\\]"')
119+
local s = str:sub(2, j - 1)
120+
121+
for k,v in pairs(controls) do
122+
s = s:gsub(v, k)
123+
end
124+
str = removeWhite(str:sub(j + 1))
125+
return s, str
126+
end
127+
128+
function parseArray(str)
129+
str = removeWhite(str:sub(2))
130+
131+
local val = {}
132+
local i = 1
133+
while str:sub(1, 1) ~= "]" do
134+
local v = nil
135+
v, str = parseValue(str)
136+
val[i] = v
137+
i = i + 1
138+
str = removeWhite(str)
139+
end
140+
str = removeWhite(str:sub(2))
141+
return val, str
142+
end
143+
144+
function parseObject(str)
145+
str = removeWhite(str:sub(2))
146+
147+
local val = {}
148+
while str:sub(1, 1) ~= "}" do
149+
local k, v = nil, nil
150+
k, v, str = parseMember(str)
151+
val[k] = v
152+
str = removeWhite(str)
153+
end
154+
str = removeWhite(str:sub(2))
155+
return val, str
156+
end
157+
158+
function parseMember(str)
159+
local k = nil
160+
k, str = parseValue(str)
161+
local val = nil
162+
val, str = parseValue(str)
163+
return k, val, str
164+
end
165+
166+
function parseValue(str)
167+
local fchar = str:sub(1, 1)
168+
if fchar == "{" then
169+
return parseObject(str)
170+
elseif fchar == "[" then
171+
return parseArray(str)
172+
elseif tonumber(fchar) ~= nil or numChars[fchar] then
173+
return parseNumber(str)
174+
elseif str:sub(1, 4) == "true" or str:sub(1, 5) == "false" then
175+
return parseBoolean(str)
176+
elseif fchar == "\"" then
177+
return parseString(str)
178+
elseif str:sub(1, 4) == "null" then
179+
return parseNull(str)
180+
end
181+
return nil
182+
end
183+
184+
function decode(str)
185+
str = removeWhite(str)
186+
t = parseValue(str)
187+
return t
188+
end
189+
190+
function decodeFromFile(path)
191+
local file = assert(fs.open(path, "r"))
192+
return decode(file.readAll())
193+
end

0 commit comments

Comments
 (0)