From 09f5802c030de6b93ece7dae5e73ec68974ba7b0 Mon Sep 17 00:00:00 2001 From: Fredrik Robertsen Date: Fri, 29 May 2026 19:40:37 +0200 Subject: [PATCH] use flags for cli parsing --- src/main.odin | 87 ++++++++++++++++++++++++++++++++++++------------- src/server.odin | 22 +++++-------- 2 files changed, 73 insertions(+), 36 deletions(-) diff --git a/src/main.odin b/src/main.odin index 576ba25..5a0626c 100644 --- a/src/main.odin +++ b/src/main.odin @@ -1,23 +1,51 @@ package hanabi +import "core:flags" import "core:fmt" import "core:net" import "core:os" -import "core:strconv" +import "core:strings" -USAGE :: `usage: hanabi (-c[onnect] | -h[ost] ) +USAGE :: `usage: hanabi [FLAGS] -note: n players has to be between 2-5 +COMMAND can be one of the following, with args and FLAGS specified under: +* connect (c) + // server to connect to +* host (h) + // server to host on + // between 2-5 + --hints (-H) // number of hints (default=8) + --lives (-l) // number of lives (default=3). try 1 for instant death difficulty! -example host: - $ hanabi -h 127.0.0.1:42069 4 +example: + host $ hanabi host 127.0.0.1:42069 2 --lives 1 + player 1 $ hanabi connect 127.0.0.1:42069 + player 2 $ hanabi connect 127.0.0.1:42069` -example player 1: - $ hanabi -c 127.0.0.1:42069 -example player 2: - $ hanabi -c 127.0.0.1:42069` +Host_Args :: struct { + addr: net.Host_Or_Endpoint `args:"pos=0,required" usage:"ip:port to host on"`, + players: int `args:"pos=1,required" usage:"how many players (2-5)"`, + hints: int `usage:"number of hints (default=8)"`, + lives: int `usage:"number of lives (default=3). try 1 for instant death difficulty!"`, +} +Connect_Args :: struct { + addr: net.Host_Or_Endpoint `args:"pos=0,required" usage:"ip:port to connect to"`, +} + +resolve_endpoint :: proc(addr: net.Host_Or_Endpoint) -> (endpoint: net.Endpoint) { + switch v in addr { + case net.Endpoint: + endpoint = v + case net.Host: + ep, err := net.resolve_ip4(v.hostname) + if err != nil do panic(fmt.tprintln("failed to resolve endpoint", err)) + endpoint = ep + endpoint.port = v.port + } + return +} main :: proc() { ok := false @@ -25,20 +53,33 @@ main :: proc() { N := len(os.args) - 2 if N <= 0 do return - switch os.args[1] { - case "-c", "-connect", "--connect": - if N != 1 do return - addr, ok := net.parse_endpoint(os.args[2]) - if !ok do panic(fmt.tprintln("failed to parse endpoint:", os.args[2])) - run_client(addr) - case "-h", "-host", "--host": - if N != 2 do return - addr, endpoint_ok := net.parse_endpoint(os.args[2]) - if !endpoint_ok do panic(fmt.tprintln("failed to parse endpoint:", os.args[2])) - num_players, int_ok := strconv.parse_int(os.args[3]) - if !int_ok do panic(fmt.tprintln("failed to parse number of players:", os.args[3])) - if num_players < 2 || num_players > 5 do return - run_server(addr, num_players) + // aliases + args: [dynamic]string + for a in os.args { + switch a { + case "-H": + append(&args, "--hints") + case "-l": + append(&args, "--lives") + case: + append(&args, a) + } + } + + // COMMAND + switch strings.to_lower(args[1]) { + case "connect", "c": + c: Connect_Args + flags.parse(&c, args[2:], .Unix) + endpoint := resolve_endpoint(c.addr) + run_client(endpoint) + case "host", "h": + h: Host_Args + h.hints = 8 + h.lives = 3 + flags.parse(&h, args[2:], .Unix, strict = true) + endpoint := resolve_endpoint(h.addr) + run_server(endpoint, h.players, h.hints, h.lives) case: return } diff --git a/src/server.odin b/src/server.odin index 0af881e..a455073 100644 --- a/src/server.odin +++ b/src/server.odin @@ -15,6 +15,7 @@ create_comm_world :: proc( w: Comm_World, err: net.Network_Error, ) { + fmt.printfln("waiting for players (%d)...", num_conn) for len(w.sockets) < num_conn { client_sock, source := net.accept_tcp(listener) or_return append(&w.sockets, client_sock) @@ -57,27 +58,22 @@ send_payload :: proc(sock: net.TCP_Socket, pl: Payload) -> net.Network_Error { return nil } -// TODO: add cli input for these -DEFAULT_HINT_TOKENS :: 8 -DEFAULT_LIVES :: 3 - -run_server :: proc( - listen_addr: net.Endpoint, - num_players: int, - num_hints := DEFAULT_HINT_TOKENS, - num_lives := DEFAULT_LIVES, -) { +run_server :: proc(listen_addr: net.Endpoint, num_players: int, num_hints: int, num_lives: int) { listener, list_err := net.listen_tcp(listen_addr) if list_err != nil do panic(fmt.tprintln("failed to listen:", net.to_string(listen_addr))) defer net.close(listener) + fmt.println("creating game instance...") + fmt.println("number of players:", num_players) + fmt.println("number of hints:", num_hints) + fmt.println("number of lives:", num_lives) + g := create_game(num_hints, num_lives, num_players) + defer delete_game(&g) + w, comm_err := create_comm_world(listener, num_players) if comm_err != nil do panic(fmt.tprintln("failed to create comm world:", comm_err)) defer delete_comm_world(&w) - g := create_game(num_hints, num_lives, num_players) - defer delete_game(&g) - current_player := rand.int_max(num_players) GAME_LOOP: for { for i in 0 ..< num_players {