Skip to content

Instantly share code, notes, and snippets.

@tiffany352
Created December 14, 2012 22:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tiffany352/4289185 to your computer and use it in GitHub Desktop.
Save tiffany352/4289185 to your computer and use it in GitHub Desktop.
My ComputerCraft BBS cilent/server
ARGS = {...}
COLORCTL = string.char(3)
HOMESCREEN = {
screen = "hello, world!",
click = function(x,y) end,
line = function(str) end
}
function log(chan, msg)
if true then
print(chan, msg)
end
end
function announce()
rednet.broadcast("TIFFNET Tiffany's BBS")
os.startTimer(30)
end
announce()
clients = {}
function updateScreen(client)
rednet.send(client, "SCREEN "..tostring(clients[client].screen.screen))
end
function accept(sender, message, dist)
if message == "CONNECT" then
clients[sender] = {screen = HOMESCREEN, x = 0, y = 0};
updateScreen(sender)
print("New client from "..sender);
end
end
function handleMsg(sender, message, dist)
log(sender, message)
if message:sub(1,5) == "CLICK" then
local x, y = message:match("CLICK (%d+) (%d+)");
clients[sender].x = tonumber(x);
clients[sender].y = tonumber(y);
clients[sender].screen.click(tonumber(x), tonumber(y));
elseif message:sub(1,4) == "LINE" then
local str = message:sub(6, -1);
clients[sender].screen.line(str);
elseif message:sub(1,10) == "DISCONNECT" then
clients[sender] = nil;
print("Goodbye, "..sender);
end
end
function main()
if #ARGS < 1 then
print "Usage: bbs <side>"
return;
end
rednet.open(ARGS[1])
while true do
local args = {os.pullEventRaw()};
--print("Event:",unpack(args));
local ev = args[1];
if ev == "rednet_message" then
local _, sender, message, dist = unpack(args);
if clients[sender] == nil then
accept(sender, message, dist)
else
handleMsg(sender, message, dist)
end
elseif ev == "timer" then
announce()
end
end
end
main()
COLORCTL = string.char(3);
servers = {}
selected = 1;
offset = 1;
current_server = nil
function log(msg)
if false then
rednet.broadcast("DEBUG "..msg)
end
end
function connect(s)
current_server = s;
if not s then
error "No server to connect to!"
end
local id = s.id;
screen = "Connecting...";
rednet.send(id, "CONNECT");
while server() do
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
term.clear()
draw_server();
end
end
screen = ""
function isColor(c)
return c == COLORCTL
end
function decodeColor(str)
if not isColor(str:sub(1,1)) then return 1, 32768, 0; end;
local f, b, o1, o2 = str:match(COLORCTL .. "(%d+),()?(%d*)()");
if not f then f = 1 end
if not b then b = 32768 end
return f,b, o2 or o1 or 0;
end
function draw_server()
local w,h = term.getSize()
for i = 1, #screen do
if isColor(screen:sub(i,i)) then
local f, b, o = decodeColor(screen:sub(i,-1))
term.setTextColor(2^f)
term.setBackgroundColor(2^b)
i = i + o
end
term.write(screen:sub(i,i))
term.setCursorPos(i%w + 1, math.floor(i/h) + 1)
end
end
function servermsg(sender, message, dist)
if sender ~= current_server.id then return; end
if message:sub(1,6) == "SCREEN" then
screen = message:sub(7,-1)
end
end
server_str = "";
function server()
local args = {os.pullEventRaw()};
if args[1] == "mouse_click" then
rednet.send(current_server.id, "CLICK "..tostring(args[2])..tostring(args[3]))
elseif args[1] == "char" then
server_str = server_str .. args[2];
elseif args[1] == "key" then
if args[2] == 28 then -- enter
rednet.send(current_server.id, "LINE "..server_str);
server_str = "";
elseif args[2] == 14 then -- backspace
rednet.send(current_server.id, "DISCONNECT");
current_server = nil;
return false;
end
elseif args[1] == "rednet_message" then
servermsg(args[2], args[3], args[4])
end
return true;
end
function rednet_message(sender, message, dist)
if message:sub(1,7) == "TIFFNET" then
servers[sender] = {id = sender, description = message:sub(9, -1), distance = dist};
end
end
function draw_list()
term.setBackgroundColor(colors.black)
term.clear()
local i = offset;
local w,h = term.getSize();
if selected > offset+h+1 then
offset = selected-h-1
elseif selected < offset+1 then
offset = selected-1
end
offset = math.min(offset, #servers - h)
offset = math.max(offset, 0)
term.setCursorPos(1, 1)
term.setTextColor(colors.white)
term.setBackgroundColor(colors.blue)
term.clearLine()
term.setCursorPos(1, 1)
term.write("ID Description")
term.setCursorPos(w-5, 1)
term.write("Dist ")
term.setBackgroundColor(colors.black)
for k, v in pairs(servers) do
i = i + 1;
if i > offset+h then
break;
end
term.setCursorPos(1, i+1)
if i == selected then
term.setBackgroundColor(colors.gray)
term.clearLine()
else
term.setBackgroundColor(colors.black)
end
log("Drawing server "..k.." at "..i.." (offset "..offset..")")
term.setCursorPos(1, i+1)
term.write(tostring(k))
term.setCursorPos(5, i+1)
term.write(v.description)
term.setCursorPos(w-5, i+1)
term.write(v.distance)
end
term.setBackgroundColor(colors.black)
end
function list()
local args = {os.pullEventRaw()};
local event = args[1];
if event == "char" then
if args[2] == "q" then
return false
end
elseif event == "key" then
if args[2] == 200 then -- up
selected = selected - 1;
if selected < 1 then selected = 1 end
elseif args[2] == 208 then -- down
selected = selected + 1;
if selected > #servers then selected = #servers end
elseif args[2] == 28 then -- enter
local i = 0;
log("selected: "..selected)
for k,v in pairs(servers) do
i = i+1
log(i.." "..k.." "..tostring(v))
if i == selected then
connect(v)
end
end
end
elseif event == "mouse_scroll" then
selected = selected + args[4];
elseif event == "rednet_message" then
rednet_message(args[2], args[3], args[4])
end
return true;
end
arg = {...}
function main()
if #arg < 1 then
print "Usage: tiffnet <side>"
return;
end
rednet.open(arg[1]);
draw_list();
while list() do
draw_list()
end
rednet.close(arg[1]);
term.clear()
term.setCursorPos(1,1)
end
main()

Tiffnet 0.0.1 Protocol

States Connected, Disconnected

Scope: Individual relationship between a client and a server.

Server Messages:

TIFFNET <description>

Broadcasts the server to disconnected clients. State: Any (Use multicast or similar for this message)

SCREEN <message>

Sets the screen of a client. State: Connected

Client messages:

CONNECT

Sets the state from Disconnected to Connected. State: Disconnected

CLICK <x> <y>

Should correspond to a mouse click event on the client's screen. State: Connected

LINE <message>

Should correspond to a user entering text and hitting ENTER or RETURN. State: Connected

DISCONNECT

Sets the state from Connected to Disconnected. State: Connected

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment