From df26827a3f00d64f5af01271818c7c8bd7eaa387 Mon Sep 17 00:00:00 2001 From: ubq323 Date: Fri, 5 Apr 2024 00:57:56 +0100 Subject: start of networking, and packet_reader --- Makefile | 10 ++++ client/drawing.ha | 35 +++++++++++-- client/main.ha | 2 + server/main.ha | 143 +++++++++++++++++++++++++++++++++++++++++------------- spec | 13 ++--- 5 files changed, 157 insertions(+), 46 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..411f03c --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +nothing: + true + +client: + hare run -lSDL2 client/ + +server: + hare run server/ + +.PHONY: client server diff --git a/client/drawing.ha b/client/drawing.ha index e164d33..2d093ae 100644 --- a/client/drawing.ha +++ b/client/drawing.ha @@ -1,5 +1,8 @@ use sdl2; use fmt; +use io; +use endian; +use math::random; // 2d position, x and y export type pos = (i32, i32); @@ -9,6 +12,9 @@ export type drawing_state = struct { drawing: bool, pos: pos, pictures: []picture, + + // hack. change this + conn: io::file, }; export type picture = struct { @@ -90,11 +96,32 @@ export fn circle(picture: *picture, c: pos, r: i32, color: u32) void = { }; }; + + export fn do_drawing(dstate: *drawing_state) void = { - if (dstate.drawing) for (let i = 0z; i < 4; i+=1) { - const pic = &dstate.pictures[i]; - const p = (dstate.pos.0 - pic.pos.0, dstate.pos.1 - pic.pos.1); - circle(pic, p, 20, 0xff0088); + if (dstate.drawing) { + for (let i = 0z; i < 4; i+=1) { + const pic = &dstate.pictures[i]; + const p = (dstate.pos.0 - pic.pos.0, dstate.pos.1 - pic.pos.1); + circle(pic, p, 20, 0xff0088); + }; + // hack, change this + // let buf: [8]u8 = [0...]; + // fmt::printfln("C {},{}",dstate.pos.0,dstate.pos.1)!; + // endian::leputu32(buf[0..4],dstate.pos.0: u32); + // endian::leputu32(buf[4..8],dstate.pos.1: u32); + // io::write(dstate.conn, buf)!; + + static let rand: u64 = 12345; + static let cur = 0; + let buf: [20]u8 = [0...]; + const n = random::u32n(&rand, 10) : int; + for (let i = 0; i < n; i += 1) { + buf[i] = (cur+i) : u8; + }; + cur += n; + fmt::println(n)!; + io::writeall(dstate.conn, buf[..n])!; }; }; diff --git a/client/main.ha b/client/main.ha index ba1736e..a0c25d8 100644 --- a/client/main.ha +++ b/client/main.ha @@ -1,6 +1,7 @@ use fmt; use sdl2; use math; +use net::dial; def CHUNKSIZE = 512; def NCHUNKS = 4; @@ -29,6 +30,7 @@ export fn main() void = { drawing = false, pos = (0,0), pictures = pictures, + conn = dial::dial("tcp","localhost:41460","unknown")!, }; let camera_pos: pos = (25, 50); diff --git a/server/main.ha b/server/main.ha index 43bdf34..f1eec0a 100644 --- a/server/main.ha +++ b/server/main.ha @@ -1,43 +1,118 @@ use fmt; -use os; +use net; +use net::tcp; +use net::ip; use io; -use fs; -use errors; -use drawing::{pos}; +use os; +use unix::poll; +use bufio; -// type chunk = struct { -// fd: io::file, -// d: []u32, -// }; +def PORT: u16 = 41460; -// def CHUNKSIZE: size = 512; -// def CHUNK_LENGTH: size = CHUNKSIZE*CHUNKSIZE*size(u32); - -// fn open_chunk_file(chunkpos: pos) (chunk | fs::error) = { -// const path = fmt::asprintf("c.{}.{}.dat", chunkpos.0, chunkpos.1); -// defer free(path); -// const fd = fs::create_file(os::cwd, path, -// fs::mode::USER_RW | fs::mode::GROUP_RW, -// fs::flag::RDWR)?; -// io::trunc(fd, CHUNK_LENGTH)?; -// const dp = io::mmap(null, CHUNK_LENGTH, -// io::prot::READ | io::prot::WRITE, -// io::mflag::SHARED, -// fd, 0)?; -// const d = (dp: *[*]u32)[..CHUNKSIZE*CHUNKSIZE]; -// return chunk { fd = fd, d = d }; -// }; +type conn = net::socket; + +type packet = []u8; +def PCKSZ: size = 4; + +type packet_reader = struct { + buf: [256]u8, + good: []u8, +}; + +fn packet_reader_new() packet_reader = { + let pr = packet_reader { + buf = [0...], + ... + }; + pr.good = pr.buf[0..0]; + return pr; + +}; + +// call when input is ready. could block otherwise +fn packet_reader_read(pr: *packet_reader, sock: net::socket) (void | io::error | io::EOF) = { + const remaining_amt = len(pr.good); + const read_pos = if (remaining_amt > 0) { + // still some unconsumed content in the buffer + // move unconsumed stuff to start of buffer + fmt::printfln("moving {} remaining bytes",remaining_amt)!; + pr.buf[0..remaining_amt] = pr.good; + yield remaining_amt; + } else 0z; + const nread = match(io::read(sock, pr.buf[read_pos..])?) { + case io::EOF => return io::EOF; + case let n: size => yield n; + }; + fmt::printfln("read {} bytes",nread)!; + const total_amt = read_pos + nread; + pr.good = pr.buf[0..total_amt]; + fmt::printfln("now {} bytes in buffer",total_amt)!; +}; + + +fn packet_reader_next(pr: *packet_reader) (packet | done) = { + // either parse a full packet out of the front of good, + // move good along that many bytes, + // and return the packet, + // or, ascertain there is no full packet, and return done + if (len(pr.good) < PCKSZ) return done; + const packet_bytes = pr.good[..PCKSZ]; + pr.good = pr.good[PCKSZ..]; + return packet_bytes; +}; export fn main() void = { - // match (open_chunk_file((-3,12))) { - // case let e: fs::error => - // fmt::fatal(fs::strerror(e)); - // case let ch: chunk => - // ch.d[0] = 0x12345678; - // ch.d[CHUNKSIZE*CHUNKSIZE - 1]=0xdeadbeef; - // }; + const listener = tcp::listen(ip::ANY_V4, PORT)!; + const conn = tcp::accept(listener)!; - const t = test2 { a=4, b=5 }; - thethe(&t); + const pr = packet_reader_new(); + for :mainloop (true) { + if (packet_reader_read(&pr, conn)! is io::EOF) + fmt::fatal("disconnected"); + let i = 0; + for (const packet => packet_reader_next(&pr)) { + fmt::printf("#{} got {}:",i,len(packet))!; + i+=1; + for (let byte .. packet) fmt::printf(" {:x}",byte)!; + fmt::println("")!; + }; + }; }; + + +// fn loop(listener: net::socket) void = { +// const buf: [256]u8 = [0...]; +// let pollfds: []poll::pollfd = alloc([ poll::pollfd { +// fd = listener, events = poll::event::POLLIN, revents = 0 +// }]); + +// for (true) { +// poll::poll(pollfds, poll::INDEF)!; +// if (0 != pollfds[0].revents & poll::event::POLLIN) { +// fmt::println("new conn")!; +// append(pollfds, poll::pollfd { +// fd = tcp::accept(pollfds[0].fd)!, +// events = poll::event::POLLIN, revents = 0 +// }); +// }; +// for (let i = 1z; i < len(pollfds); i += 1) { +// if (0 != pollfds[i].revents & poll::event::POLLIN) { +// match (io::read(pollfds[i].fd, buf)!) { +// case io::EOF => +// fmt::println("disconnect", i)!; +// delete(pollfds[i]); +// i -= 1; +// case let n: size => +// io::write(os::stdout_file, buf[..n])!; +// for (let j = 1z; j < len(pollfds); j += 1) { +// if (i != j) { +// io::writeall(pollfds[j].fd, buf[..n])!; +// }; +// }; +// }; +// }; + +// }; +// }; +// }; diff --git a/spec b/spec index 1630116..58ac330 100644 --- a/spec +++ b/spec @@ -1,9 +1,6 @@ -program where you can draw with the mouse - DONE -program where you can draw with the mouse and it draws lines between the points -program where you can draw with the mouse and it interpolates nicely with beziers -program where you can do that multiplayerly - hard! -program where you can switch between drawing and moving around -program where you can do that and also see each other's positions +next thing to do: client sends circle positions to server. +server just prints that out +only one client connected to server +then expand to multiple clients, server mirrorring, etc... +then actually that's mostly there mpvwise -- cgit v1.2.3