From 760c66477dba42169a9c7d93151912f9135c2244 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Fri, 22 Apr 2022 09:38:21 -0500 Subject: [PATCH] restructing / cleaning up client side code --- src/client/build.onyx | 2 + src/client/game.onyx | 26 +-- src/client/main.onyx | 5 +- src/client/{ => menu}/connect_menu.onyx | 13 +- src/client/net.onyx | 251 ------------------------ src/client/net/handlers.onyx | 88 +++++++++ src/client/net/net.onyx | 82 ++++++++ src/client/net/outbound.onyx | 78 ++++++++ src/client/world/player.onyx | 4 +- src/client/world/player_manager.onyx | 47 +++++ 10 files changed, 319 insertions(+), 277 deletions(-) rename src/client/{ => menu}/connect_menu.onyx (89%) delete mode 100644 src/client/net.onyx create mode 100644 src/client/net/handlers.onyx create mode 100644 src/client/net/net.onyx create mode 100644 src/client/net/outbound.onyx create mode 100644 src/client/world/player_manager.onyx diff --git a/src/client/build.onyx b/src/client/build.onyx index 3c7bdc5..788adfc 100644 --- a/src/client/build.onyx +++ b/src/client/build.onyx @@ -10,6 +10,8 @@ #load_all "./." #load_all "./gfx" +#load_all "./menu" +#load_all "./net" #load_all "./utils" #load_all "./world" diff --git a/src/client/game.onyx b/src/client/game.onyx index d2f200f..b29d17d 100644 --- a/src/client/game.onyx +++ b/src/client/game.onyx @@ -12,9 +12,11 @@ use package stb_truetype fog_color :: Vector3.{ 0.6, 0.6, 0.6 }; } +@Relocate // this global variables font: Font; player: Player; world: ^World; +player_manager: ^Player_Manager; selected_block: Vector3i; player_shader: Shader; @@ -60,12 +62,12 @@ game_init :: (_: rawptr) { } game_deinit :: (_: rawptr) { - net_send_disconnect(); - net_disconnect(); + game_net.send_disconnect(); + game_net.disconnect(); } game_update :: (_: rawptr, dt: f32) { - net_pulse(); + game_net.pulse(); if is_key_just_down(GLFW_KEY_ESCAPE) { if cursor_grabbed { @@ -88,13 +90,10 @@ game_update :: (_: rawptr, dt: f32) { send_movement_timeout -= dt; if send_movement_timeout < 0 { send_movement_timeout = 0.1f; - net_send_movement_update(player.body.pos, player.body.vel, .{1,0,0}, player.body.on_ground); + game_net.send_movement_update(player.body.pos, player.body.vel, .{1,0,0}, player.body.on_ground); } - for ^other_players.entries { - if it.value.on_ground do it.value.velocity.y = 0; - it.value.position += it.value.velocity * dt; - } + player_manager->move_players(dt); if is_key_just_down(GLFW_KEY_F7) { debug_screen = !debug_screen; @@ -140,14 +139,7 @@ draw_scene :: () { glLineWidth(2); chunk_highlight_block(~~selected_block.x, ~~selected_block.y, ~~selected_block.z); - shader_use(player_shader); - shader_set_uniform(player_shader, #cstr "color", Color.{1,0,0}); - for^ other_players.entries { - if (it.value.position - player.body.pos)->square_mag() >= 70 * 70 do continue; - - update_model_matrix(it.value.position - .{0,0.8,0}, .{0.3, 1, 0.3}); - mesh_draw(Meshes.white_box); - } + player_manager->draw_players(); } @Temporary @@ -172,7 +164,7 @@ draw_chat :: () { #persist pending_message: [..] u8; if ui.draw_textbox(.{0, ~~(wh - 32), 400, 32}, ^pending_message) == .Enter_Pressed { if pending_message.count > 0 { - net_send_chat_message(string.alloc_copy(pending_message)); + game_net.send_chat_message(string.alloc_copy(pending_message)); array.clear(^pending_message); } } diff --git a/src/client/main.onyx b/src/client/main.onyx index 99eece8..be9fb52 100644 --- a/src/client/main.onyx +++ b/src/client/main.onyx @@ -6,7 +6,8 @@ use package core.intrinsics.onyx { __initialize } #local runtime :: package runtime #package { - ui :: package ui + ui :: package ui + game_net :: package game_net } State :: struct { @@ -67,7 +68,7 @@ init :: () { shaders_init(); fonts_init(); immediate_init(); - net_register_handles(); + game_net.register_handles(); __initialize(^camera); camera_set_fov(^camera, 75); diff --git a/src/client/connect_menu.onyx b/src/client/menu/connect_menu.onyx similarity index 89% rename from src/client/connect_menu.onyx rename to src/client/menu/connect_menu.onyx index 52d9fbf..cb7cdbb 100644 --- a/src/client/connect_menu.onyx +++ b/src/client/menu/connect_menu.onyx @@ -18,10 +18,13 @@ Connect_Menu :: struct { string.concat(^port, conv.format(port_buffer, "{}", (package runtime.vars).Game_Port)); title_font = font_lookup(.{"./assets/fonts/calibri.ttf", 64}); + + @HACK @HACK @HACK + player_manager = new(Player_Manager); } join :: (_: rawptr) { - net_connect(ip_addr, ~~ conv.str_to_i64(port)); + game_net.connect(ip_addr, ~~ conv.str_to_i64(port)); pop_game_state(); push_game_state(Connecting_Menu, null); @@ -62,13 +65,13 @@ Connecting_Menu :: struct { init :: (_: rawptr) { font = font_lookup(.{"./assets/fonts/calibri.ttf", 32}); - net_set_on_connect_callback(.{ _, on_connect }); + game_net.set_on_connect_callback(.{ _, on_connect }); connection_timeout = 10.0; // 10 second timeout } on_connect :: (_: rawptr) { - net_send_connect(name); + game_net.send_connect(name); } leave :: (_: rawptr) { @@ -78,7 +81,7 @@ Connecting_Menu :: struct { } update :: (_: rawptr, dt: f32) { - net_pulse(); + game_net.pulse(); connection_timeout -= dt; if connection_timeout < 0 { @@ -89,7 +92,7 @@ Connecting_Menu :: struct { draw :: (_: rawptr) { if is_key_just_down(GLFW_KEY_ESCAPE) { - net_disconnect(); + game_net.disconnect(); glfwSetWindowShouldClose(window, true); } diff --git a/src/client/net.onyx b/src/client/net.onyx deleted file mode 100644 index 8244f7c..0000000 --- a/src/client/net.onyx +++ /dev/null @@ -1,251 +0,0 @@ - -net_register_handles :: () { - use type_info; - - for_all_types() { - if struct_inherits(type_idx, Packet_Handler) { - func := get_struct_method(type_idx, "handle"); - if func == null do continue; - - struct_type_info := cast(^Type_Info_Struct) type_info; - packet_type := *cast(^packets.Type) struct_type_info.members[0].default; - packet_handles[packet_type] = *cast(^(rawptr) -> void) func.data; - } - } - - println(packet_handles); -} - -net_connect :: (ip_addr: [] u8, port: u16) { - addr: net.Socket_Address; - addr.addr = net.str_to_ipv4(ip_addr); - addr.port = port; - host', _ := onet.host_create(null, 1); - peer = onet.host_connect(host, ^addr, 2); -} - -net_disconnect :: () { - onet.peer_send_disconnect(peer); - onet.peer_flush_outgoing_commands(peer); - onet.peer_disconnect(peer); -} - -net_set_on_connect_callback :: (callback: On_Connect_Callback) { - on_connect_callback = callback; -} - -net_pulse :: () { - for host->get_events(timeout=0) { - if it.type == .Connection { - if on_connect_callback.func != null_proc { - on_connect_callback.func(on_connect_callback.data); - } - } - - if it.type == .Message { - net_handle_packet(it.data); - } - } -} - -#local packet_handles: Map(packets.Type, (rawptr) -> void); - -Packet_Handler :: struct { - type: packets.Type; -} - -#local Verify_Connect_Handle :: struct { - use base := Packet_Handler.{ .Verify_Connect }; - - handle :: (packet: ^packets.Verify_Connect) { - player_id = packet.player_id; - - push_game_state(Game_State, null); - } -} - -#local Player_Joined_Handle :: struct { - use base := Packet_Handler.{ .Player_Joined }; - - handle :: (packet: ^packets.Player_Joined) { - name := string.alloc_copy(packet->name()); - - other_players[~~ packet.player_id] = .{ - name, - .{0, 0, 0}, .{0, 0, 0}, .{0, 0, 0}, - false - }; - - if packet.player_id != player_id { - buf: [1024] u8; - chat_messages << (conv.format(buf, "{} joined the server!", name) |> string.alloc_copy()); - } - } -} - -#local Connection_Rejected_Handle :: struct { - use base := Packet_Handler.{ .Connection_Rejected }; - - handle :: (packet: ^packets.Connection_Rejected) { - @NetworkErrors // Handle this case. - printf("Connection refused: {}\n", packet.reason); - - pop_game_state(); - push_game_state(Connect_Menu, null); - } -} - -#local Chat_Message_Handle :: struct { - use base := Packet_Handler.{ .Chat_Message }; - - handle :: (packet: ^packets.Chat_Message) { - buf: [1024] u8; - msg: str; - - sender := map.get_ptr(^other_players, ~~ packet.sender_id); - if sender != null { - msg = conv.format(buf, "[{}] {}\n", sender.name, packet->message()); - } else { - msg = packet->message(); - } - - chat_messages << string.alloc_copy(msg); - } -} - -#local Player_Moved_Handle :: struct { - use base := Packet_Handler.{ .Player_Moved }; - - handle :: (packet: ^packets.Player_Moved) { - if packet.player_id == player_id do return; - - player := map.get_ptr(^other_players, ~~ packet.player_id); - player.position = packet.position; - player.velocity = packet.velocity; - player.facing = packet.facing; - player.on_ground = packet.on_ground; - } -} - -#local Block_Updates_Handle :: struct { - use base := Packet_Handler.{ .Block_Updates }; - - handle :: (packet: ^packets.Block_Updates) { - updates := packet->updates(); - for updates { - pos := it.position; - world_set_block(world, pos.x, pos.y, pos.z, it.new_block); - } - } -} - -net_handle_packet :: (packet_data: [] u8) { - packet := cast(^packets.Packet_Base) packet_data.data; - if packet_handles[~~ packet.type] != null_proc { - packet_handles[~~ packet.type](packet); - } -} - -net_send_connect :: (name: str) { - msg := cast(^packets.Connect) calloc(sizeof packets.Connect + name.count); - msg.type = .Connect; - msg.client_version = (package runtime.vars).Game_Version; - msg.name_length = ~~ name.count; - memory.copy(~~ ^msg.name_data, name.data, name.count); - - p := new(onet.Packet); - p.flags |= .Reliable; - p.data = .{ ~~msg, sizeof packets.Connect + name.count }; - p.free_data = true; - onet.peer_send(peer, 0, p); -} - -net_send_disconnect :: () { - disconnect := new(packets.Disconnect); - disconnect.player_id = player_id; - - p := new(onet.Packet); - p.data = .{ ~~disconnect, sizeof typeof *disconnect }; - p.free_data = true; - onet.peer_send(peer, 0, p); -} - -net_send_chat_message :: (message: str) { - msg := cast(^packets.Chat_Message) calloc(sizeof packets.Chat_Message + message.count); - msg.type = .Chat_Message; - msg.sender_id = player_id; - msg.message_length = ~~ message.count; - memory.copy(~~ ^msg.message_data, message.data, message.count); - - p := new(onet.Packet); - p.flags |= .Reliable; - p.data = .{ ~~msg, sizeof packets.Chat_Message + message.count }; - p.free_data = true; - onet.peer_send(peer, 0, p); -} - -net_send_movement_update :: (position: Vector3, velocity: Vector3, facing: Vector3, on_ground: bool) { - movement := new(packets.Player_Moved); - movement.player_id = player_id; - movement.position = position; - movement.velocity = velocity; - movement.facing = facing; - movement.on_ground = on_ground; - - p := new(onet.Packet); - p.data = .{ ~~movement, sizeof typeof *movement }; - p.free_data = true; - onet.peer_send(peer, 0, p); -} - -net_send_block_updates :: (updates: [] packets.Block_Updates.Update) { - size := sizeof packets.Block_Updates + updates.count * sizeof packets.Block_Updates.Update; - block_updates := cast(^packets.Block_Updates) calloc(size); - block_updates.type = .Block_Updates; - block_updates.update_count = ~~updates.count; - - block_update := cast(^packets.Block_Updates.Update) ^block_updates.update_data; - for updates.count { - block_update[it].position = updates[it].position; - block_update[it].new_block = updates[it].new_block; - } - - p := new(onet.Packet); - p.data = .{ ~~block_updates, size }; - p.free_data = true; - onet.peer_send(peer, 0, p); -} - -Remote_Player :: struct { - name: str; - - position: Vector3; - velocity: Vector3; - facing: Vector3; - on_ground: bool; -} - -@TEMPORARY -other_players: Map(u32, Remote_Player); - -#local { - use package core - onet :: package onyx_net - packets :: package packets - - host: ^onet.Host; - peer: ^onet.Peer; - - @TEMPORARY @HACK - player_id: u16; - - On_Connect_Callback :: struct { - data: rawptr; - func: (rawptr) -> void; - } - on_connect_callback: On_Connect_Callback; - - any_to_buffer :: macro (x: ^$T) => ([] u8).{ ~~x, sizeof T }; -} - - diff --git a/src/client/net/handlers.onyx b/src/client/net/handlers.onyx new file mode 100644 index 0000000..c1c02c3 --- /dev/null +++ b/src/client/net/handlers.onyx @@ -0,0 +1,88 @@ +package game_net + +#local { + use package core + use package main + onet :: package onyx_net + packets :: package packets +} + +#local Verify_Connect_Handle :: struct { + use base := Packet_Handler.{ .Verify_Connect }; + + handle :: (packet: ^packets.Verify_Connect) { + player_manager.player_id = packet.player_id; + + push_game_state(Game_State, null); + } +} + +#local Player_Joined_Handle :: struct { + use base := Packet_Handler.{ .Player_Joined }; + + handle :: (packet: ^packets.Player_Joined) { + name := packet->name(); + player_manager->add_player(packet.player_id, name); + + if packet.player_id != player_manager.player_id { + buf: [1024] u8; + chat_messages << (conv.format(buf, "{} joined the server!", name) |> string.alloc_copy()); + } + } +} + +#local Connection_Rejected_Handle :: struct { + use base := Packet_Handler.{ .Connection_Rejected }; + + handle :: (packet: ^packets.Connection_Rejected) { + @NetworkErrors // Handle this case. + printf("Connection refused: {}\n", packet.reason); + + pop_game_state(); + push_game_state(Connect_Menu, null); + } +} + +#local Chat_Message_Handle :: struct { + use base := Packet_Handler.{ .Chat_Message }; + + handle :: (packet: ^packets.Chat_Message) { + buf: [1024] u8; + msg: str; + + sender := player_manager->get_player(packet.sender_id); + if sender != null { + msg = conv.format(buf, "[{}] {}\n", sender.name, packet->message()); + } else { + msg = packet->message(); + } + + chat_messages << string.alloc_copy(msg); + } +} + +#local Player_Moved_Handle :: struct { + use base := Packet_Handler.{ .Player_Moved }; + + handle :: (packet: ^packets.Player_Moved) { + if packet.player_id == player_manager.player_id do return; + + player := player_manager->get_player(packet.player_id); + player.position = packet.position; + player.velocity = packet.velocity; + player.facing = packet.facing; + player.on_ground = packet.on_ground; + } +} + +#local Block_Updates_Handle :: struct { + use base := Packet_Handler.{ .Block_Updates }; + + handle :: (packet: ^packets.Block_Updates) { + updates := packet->updates(); + for updates { + pos := it.position; + world_set_block(world, pos.x, pos.y, pos.z, it.new_block); + } + } +} diff --git a/src/client/net/net.onyx b/src/client/net/net.onyx new file mode 100644 index 0000000..9fd9c48 --- /dev/null +++ b/src/client/net/net.onyx @@ -0,0 +1,82 @@ +package game_net + +#local { + use package core + use package main + onet :: package onyx_net + packets :: package packets +} + +register_handles :: () { + use type_info; + + for_all_types() { + if struct_inherits(type_idx, Packet_Handler) { + func := get_struct_method(type_idx, "handle"); + if func == null do continue; + + struct_type_info := cast(^Type_Info_Struct) type_info; + packet_type := *cast(^packets.Type) struct_type_info.members[0].default; + packet_handles[packet_type] = *cast(^(rawptr) -> void) func.data; + } + } + + println(packet_handles); +} + +connect :: (ip_addr: [] u8, port: u16) { + addr: net.Socket_Address; + addr.addr = net.str_to_ipv4(ip_addr); + addr.port = port; + host', _ := onet.host_create(null, 1); + peer = onet.host_connect(host, ^addr, 2); +} + +disconnect :: () { + onet.peer_send_disconnect(peer); + onet.peer_flush_outgoing_commands(peer); + onet.peer_disconnect(peer); +} + +set_on_connect_callback :: (callback: On_Connect_Callback) { + on_connect_callback = callback; +} + +pulse :: () { + for host->get_events(timeout=0) { + if it.type == .Connection { + if on_connect_callback.func != null_proc { + on_connect_callback.func(on_connect_callback.data); + } + } + + if it.type == .Message { + handle_packet(it.data); + } + } +} + +#package packet_handles: Map(packets.Type, (rawptr) -> void); +Packet_Handler :: struct { + type: packets.Type; +} + +#local handle_packet :: (packet_data: [] u8) { + packet := cast(^packets.Packet_Base) packet_data.data; + if packet_handles[~~ packet.type] != null_proc { + packet_handles[~~ packet.type](packet); + } +} + +#package { + host: ^onet.Host; + peer: ^onet.Peer; + + On_Connect_Callback :: struct { + data: rawptr; + func: (rawptr) -> void; + } + on_connect_callback: On_Connect_Callback; + + any_to_buffer :: macro (x: ^$T) => ([] u8).{ ~~x, sizeof T }; +} \ No newline at end of file diff --git a/src/client/net/outbound.onyx b/src/client/net/outbound.onyx new file mode 100644 index 0000000..c2d58df --- /dev/null +++ b/src/client/net/outbound.onyx @@ -0,0 +1,78 @@ +package game_net + +#local { + use package core + use package main + onet :: package onyx_net + packets :: package packets +} + +send_connect :: (name: str) { + msg := cast(^packets.Connect) calloc(sizeof packets.Connect + name.count); + msg.type = .Connect; + msg.client_version = (package runtime.vars).Game_Version; + msg.name_length = ~~ name.count; + memory.copy(~~ ^msg.name_data, name.data, name.count); + + p := new(onet.Packet); + p.flags |= .Reliable; + p.data = .{ ~~msg, sizeof packets.Connect + name.count }; + p.free_data = true; + onet.peer_send(peer, 0, p); +} + +send_disconnect :: () { + disconnect := new(packets.Disconnect); + disconnect.player_id = player_manager.player_id; + + p := new(onet.Packet); + p.data = .{ ~~disconnect, sizeof typeof *disconnect }; + p.free_data = true; + onet.peer_send(peer, 0, p); +} + +send_chat_message :: (message: str) { + msg := cast(^packets.Chat_Message) calloc(sizeof packets.Chat_Message + message.count); + msg.type = .Chat_Message; + msg.sender_id = player_manager.player_id; + msg.message_length = ~~ message.count; + memory.copy(~~ ^msg.message_data, message.data, message.count); + + p := new(onet.Packet); + p.flags |= .Reliable; + p.data = .{ ~~msg, sizeof packets.Chat_Message + message.count }; + p.free_data = true; + onet.peer_send(peer, 0, p); +} + +send_movement_update :: (position: Vector3, velocity: Vector3, facing: Vector3, on_ground: bool) { + movement := new(packets.Player_Moved); + movement.player_id = player_manager.player_id; + movement.position = position; + movement.velocity = velocity; + movement.facing = facing; + movement.on_ground = on_ground; + + p := new(onet.Packet); + p.data = .{ ~~movement, sizeof typeof *movement }; + p.free_data = true; + onet.peer_send(peer, 0, p); +} + +send_block_updates :: (updates: [] packets.Block_Updates.Update) { + size := sizeof packets.Block_Updates + updates.count * sizeof packets.Block_Updates.Update; + block_updates := cast(^packets.Block_Updates) calloc(size); + block_updates.type = .Block_Updates; + block_updates.update_count = ~~updates.count; + + block_update := cast(^packets.Block_Updates.Update) ^block_updates.update_data; + for updates.count { + block_update[it].position = updates[it].position; + block_update[it].new_block = updates[it].new_block; + } + + p := new(onet.Packet); + p.data = .{ ~~block_updates, size }; + p.free_data = true; + onet.peer_send(peer, 0, p); +} diff --git a/src/client/world/player.onyx b/src/client/world/player.onyx index 2814107..01fd581 100644 --- a/src/client/world/player.onyx +++ b/src/client/world/player.onyx @@ -92,12 +92,12 @@ player_update :: (use player: ^Player, dt: f32) { } if is_button_just_down(GLFW_MOUSE_BUTTON_LEFT) { - net_send_block_updates(.[.{selected_block, Block_Empty}]); + game_net.send_block_updates(.[.{selected_block, Block_Empty}]); } if is_button_just_down(GLFW_MOUSE_BUTTON_RIGHT) { target := selected_block + dir; - net_send_block_updates(.[.{target, block_make(1,0,0,1)}]); + game_net.send_block_updates(.[.{target, block_make(1,0,0,1)}]); } } diff --git a/src/client/world/player_manager.onyx b/src/client/world/player_manager.onyx new file mode 100644 index 0000000..c0260c2 --- /dev/null +++ b/src/client/world/player_manager.onyx @@ -0,0 +1,47 @@ +use package core + +Remote_Player :: struct { + name: str; + + position: Vector3; + velocity: Vector3; + facing: Vector3; + on_ground: bool; +} + +Player_Manager :: struct { + // Player ID of the local player + player_id: u16; + + other_players: Map(u16, Remote_Player); + + add_player :: (use this: ^Player_Manager, id: u16, name: str) { + other_players[id] = .{ + string.alloc_copy(name), + .{0, 0, 0}, .{0, 0, 0}, .{0, 0, 0}, + false + }; + } + + get_player :: (use this: ^Player_Manager, id: u16) -> ^Remote_Player { + return ^other_players[id]; + } + + move_players :: (use this: ^Player_Manager, dt: f32) { + for ^other_players.entries { + if it.value.on_ground do it.value.velocity.y = 0; + it.value.position += it.value.velocity * dt; + } + } + + draw_players :: (use this: ^Player_Manager) { + shader_use(player_shader); + shader_set_uniform(player_shader, #cstr "color", Color.{1,0,0}); + for^ player_manager.other_players.entries { + if (it.value.position - player.body.pos)->square_mag() >= 70 * 70 do continue; + + update_model_matrix(it.value.position - .{0,0.8,0}, .{0.3, 1, 0.3}); + mesh_draw(Meshes.white_box); + } + } +} \ No newline at end of file -- 2.25.1