diff options
| author | Alexander M Pickering <alex@cogarr.net> | 2024-12-09 21:48:17 -0600 |
|---|---|---|
| committer | Alexander M Pickering <alex@cogarr.net> | 2024-12-09 21:48:17 -0600 |
| commit | 00a3451004d664a5386f3750540facddc0d2686b (patch) | |
| tree | 7fbe672c24b3721d95a5bb932760e120ba040799 | |
| parent | 541ef6aaee248626c1a1c6e0db05f5980d09c7a5 (diff) | |
| download | ggj25-00a3451004d664a5386f3750540facddc0d2686b.tar.gz ggj25-00a3451004d664a5386f3750540facddc0d2686b.tar.bz2 ggj25-00a3451004d664a5386f3750540facddc0d2686b.zip | |
Add a channel abstraction to use for networking
| -rw-r--r-- | spec/channel_spec.lua | 80 | ||||
| -rw-r--r-- | src/channel.moon | 25 | ||||
| -rw-r--r-- | src/js_bridge.js | 54 | ||||
| -rw-r--r-- | tools/rewrite.lua | 4 |
4 files changed, 138 insertions, 25 deletions
diff --git a/spec/channel_spec.lua b/spec/channel_spec.lua index 252c12e..d8dbb13 100644 --- a/spec/channel_spec.lua +++ b/spec/channel_spec.lua @@ -44,10 +44,18 @@ describe("channel module", function() assert(#fc.buffer == 1) assert(fc:recv() == "a") end) + it("has a normal() function that does normal distribution", function() + local normal = channel.FaultyChannel.normal + for i = 1, 20 do + math.randomseed(i) + local res = normal(nil,1,0.1) + assert(res > 0.5 and res < 1.5) + end + end) it("can pump() with no side effects if time has not changed", function() channel.FaultyChannel.time = 0 local fc = channel.FaultyChannel({ - loss_std = 0, + loss = 0, avg_latency = 5 }) fc:send("a") @@ -56,28 +64,27 @@ describe("channel module", function() fc:pump() assert(#fc.to_deliver == 1) assert(#fc.buffer == 0) - + channel.FaultyChannel.time = 4 + fc:pump() + fc:send("b") + assert(#fc.to_deliver == 2) + assert(#fc.buffer == 0) + channel.FaultyChannel.time = 6 + fc:pump() + assert(#fc.to_deliver == 1) + assert(#fc.buffer == 1) end) - --[[ it("can be configured to not drop messages", function() channel.FaultyChannel.time = 0 local fc = channel.FaultyChannel({ avg_latency = 5, - loss_std = 0 + loss = 0 }) local i = 100 for _ = 1,i do fc:send("a") end - print(#fc.to_deliver) - print(#fc.buffer) - fc:pump() - print(#fc.to_deliver) - print(#fc.buffer) channel.FaultyChannel.time = 10 - fc:pump() - print(#fc.to_deliver) - print(#fc.buffer) local j = 0 while fc:poll() do j = j + 1 @@ -100,6 +107,53 @@ describe("channel module", function() end assert(j < i) end) - ]] + it("should keep a queue of messages", function() + channel.FaultyChannel.time = 0 + local fc = channel.FaultyChannel({ + loss = 0, + avg_latency=0, + latency_std=0, + }) + local i = 100 + for j = 1, i do + fc:send(tostring(j)) + end + channel.FaultyChannel.time = 1 + fc:pump() + assert(#fc.to_deliver == 0) + assert(#fc.buffer == i) + for j = 1, i do + assert(tonumber(fc:recv()) == j) + end + assert(not fc:poll()) + end) + it("should deliver messages with different latencies", function() + channel.FaultyChannel.time = 0 + local fc = channel.FaultyChannel({ + loss = 0, + avg_latency = 20, + latency_std = 5, + }) + local i = 100 + for j = 1, i do + fc:send(tostring(j)) + end + local received = 0 + local increment = 0.5 + local last_received = nil + local found_out_of_order = false + while received < i do + while fc:poll() do + local recv = tonumber(fc:recv()) + if last_received and last_received < recv then + found_out_of_order = true + end + last_received = recv + received = received + 1 + end + channel.FaultyChannel.time = channel.FaultyChannel.time + increment + end + assert(found_out_of_order) + end) end) end) diff --git a/src/channel.moon b/src/channel.moon index 968ae09..6f87d46 100644 --- a/src/channel.moon +++ b/src/channel.moon @@ -34,26 +34,31 @@ class FaultyChannel extends Channel @avg_latency = 0 -- in ms @latency_std = 0 -- Latency can never be below 0, but can go up as much as it likes - @avg_loss = 0 -- between 0 (never) and 1 (always) - @loss_std = 0.1 - -- Loss is always a percentage between 0 and 1 + @loss = 0.1 -- between 0 (never) and 1 (always) super(settings) - normal: (avg, std, n) => + @normal_at: (avg, std, n) -> assert(avg and std and n, string.format("normal(avg, std, n) called with %q %q %q", tostring(avg), tostring(std), tostring(n))) -- Normal curve probability at N (1/ (math.sqrt(2*math.pi) * avg)) * math.exp(-(n - avg)^2 / (2 * (std^2))) + @normal: (avg, std) => + -- Box-Muller transform + bm = math.sqrt(-2 * math.log(math.random())) * math.cos(2 * math.pi * math.random()) + -- Box-Muller gives us std = e^-0.5 , avg = 0 + ((bm / math.exp(-1/2)) * std) + avg poll: => @pump! #@buffer > 0 send: (message) => -- Do we deliver? - if @normal(@avg_loss, @loss_std, math.random()) < 0.5 + rng = math.random() + if @loss > rng return -- How long does it take? - time = @normal(@avg_latency, @latency_std, math.random()) + -- Only uses the positive half of the normal distribution, double the standard deviation? + time = @@normal(@avg_latency, @latency_std * 2, math.random()) if time < 0 then time = 0 -- We can't deliver messages in the past - table.insert(@to_deliver, {message,time}) + table.insert(@to_deliver, {message,@@time + time}) recv: => @pump! table.remove(@buffer, 1) @@ -62,11 +67,11 @@ class FaultyChannel extends Channel deliver_len = #@to_deliver for k,tbl in ipairs(@to_deliver) {m, t} = tbl + @to_deliver[defrag] = tbl if @@time > t - @to_deliver[k] = nil table.insert(@buffer, m) - if @to_deliver[defrag] == nil - @to_deliver[defrag] = tbl + else + defrag = defrag + 1 for i = defrag, deliver_len do @to_deliver[i] = nil diff --git a/src/js_bridge.js b/src/js_bridge.js new file mode 100644 index 0000000..2d32739 --- /dev/null +++ b/src/js_bridge.js @@ -0,0 +1,54 @@ +var s = document.createElement('script'); +s.setAttribute('src','https://unpkg.com/peerjs@1.5.2/dist/peerjs.min.js'); +document.body.appendChild(s); +function genRanHex(size) { + return Array.apply(null,Array(size)).map(() => Math.floor(Math.random() * 16).toString(16)).join(''); +} +PEER = {} +PEER.event_queue = {} +PEER.peers = {} +PEER.message_queue = {} +PEER["create"] = function(name, options) { + var peer = new Peer(name, options) + PEER.peers[name] = peer +} +PEER["on"] = function(name, e, message) { + PEER.peers[name].on(e, function(conn) { + PEER.message_queue.push(message) + } +} +PEER["connect"] = function(name, id, options) { + PEER.peers[name].connect(id, options) +} +var peer = new Peer("ANGRY_ADVENTURE_" + GLOBAL.lobby_id, {"debug": 3}); +var peer_id = null; +var poo = peer.on('open', function(id) { + console.log('My peer ID is: ' + id); + peer.on("connection",function(conn){ + console.log("Got a connection!") + GLOBAL.connections[conn.peer] = conn + conn.send("Hello!") + GLOBAL.message_queue.push({ + "msg": "data", + "peer": conn.peer, + "data": '{"msg":"player_joined"}' + }) + conn.on("data",function(data){ + console.log("Got some data from a peer!:" + data) + GLOBAL.message_queue.push({ + "msg": "data", + "peer": conn.peer, + "data": data + }) + }) + conn.on("error",function(err){ + console.log("Error on a connection:" + err) + GLOBAL.message_queue.push({ + "msg": "error", + "peer": conn.peer, + "err": err + }) + }) + }) + GLOBAL.peer_id = id; +}); diff --git a/tools/rewrite.lua b/tools/rewrite.lua index 503a0c8..e26a8c3 100644 --- a/tools/rewrite.lua +++ b/tools/rewrite.lua @@ -1,7 +1,7 @@ --[[Script to rewrite a stack traceback in terms of moonscript instead of lua]] for data in io.lines() do - local filename, linenum, rest = data:gmatch("%s+(.*%.lua):(%d+):(.*)")() + local spaces, filename, linenum, rest = data:gmatch("(%s*)(.*%.lua):(%d+):(.*)")() if filename and linenum and rest then local moonfilename = filename:gsub(".lua$",".moon") @@ -18,7 +18,7 @@ for data in io.lines() do for line in debugfile:lines() do _,_,pos,lua,moon = line:find("(%d+)%s+(%d+):%b[] >> (%d+)") if tonumber(linenum) == tonumber(lua) then - print(string.format("\t%s:%d: %s",moonfilename,moon,rest)) + print(string.format("%s%s:%d: %s",spaces,moonfilename,moon,rest)) goto next end end |
