#load_all "./."
#load_all "./gfx"
+#load_all "./menu"
+#load_all "./net"
#load_all "./utils"
#load_all "./world"
+++ /dev/null
-
-use package core
-use package glfw3
-use package opengles
-
-#local {
- ip_addr: [..] u8;
- port: [..] u8;
- name: [..] u8;
-
- title_font: Font;
-}
-
-Connect_Menu :: struct {
- init :: (_: rawptr) {
- array.clear(^port);
- port_buffer: [8] u8;
- string.concat(^port, conv.format(port_buffer, "{}", (package runtime.vars).Game_Port));
-
- title_font = font_lookup(.{"./assets/fonts/calibri.ttf", 64});
- }
-
- join :: (_: rawptr) {
- net_connect(ip_addr, ~~ conv.str_to_i64(port));
-
- pop_game_state();
- push_game_state(Connecting_Menu, null);
- }
-
- draw :: (_: rawptr) {
- if is_key_just_down(GLFW_KEY_ESCAPE) {
- glfwSetWindowShouldClose(window, true);
- }
-
- glDisable(GL_DEPTH_TEST);
- glClearColor(0.1, 0.1, 0.1, 1);
- glClear(GL_COLOR_BUFFER_BIT);
-
- ww, wh := camera.window_width, camera.window_height;
-
- font_draw_centered(title_font, 0, (wh - 70) / 3, ww, "Untitled Shooter Game");
-
- tx := (ww - 200) / 2;
- ty := (wh - 160) / 2;
- ui.textbox_list_start();
- ui.draw_textbox(.{tx, ty+0, 200, 40}, ^ip_addr, "IP Address");
- ui.draw_textbox(.{tx, ty+40, 200, 40}, ^port, "Port");
- ui.draw_textbox(.{tx, ty+80, 200, 40}, ^name, "Name");
- ui.textbox_list_end();
-
- if ui.draw_button(.{tx, ty+120, 200, 40}, "Join") {
- join(_);
- }
- }
-}
-
-
-
-Connecting_Menu :: struct {
- #persist font: Font;
- #persist connection_timeout: f32;
-
- init :: (_: rawptr) {
- font = font_lookup(.{"./assets/fonts/calibri.ttf", 32});
- net_set_on_connect_callback(.{ _, on_connect });
-
- connection_timeout = 10.0; // 10 second timeout
- }
-
- on_connect :: (_: rawptr) {
- net_send_connect(name);
- }
-
- leave :: (_: rawptr) {
- delete(^ip_addr);
- delete(^port);
- delete(^name);
- }
-
- update :: (_: rawptr, dt: f32) {
- net_pulse();
-
- connection_timeout -= dt;
- if connection_timeout < 0 {
- pop_game_state();
- push_game_state(Connect_Menu, null);
- }
- }
-
- draw :: (_: rawptr) {
- if is_key_just_down(GLFW_KEY_ESCAPE) {
- net_disconnect();
- glfwSetWindowShouldClose(window, true);
- }
-
- glDisable(GL_DEPTH_TEST);
- glClearColor(0.1, 0.1, 0.1, 1);
- glClear(GL_COLOR_BUFFER_BIT);
-
- ww, wh := camera.window_width, camera.window_height;
-
- font_draw_centered(title_font, 0, (wh - 70) / 3, ww, "Untitled Shooter Game");
-
- tx := (ww - 200) / 2;
- ty := (wh - 16) / 2;
- font_draw_centered(font, tx, ty, 200, "Connecting...");
- }
-}
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;
}
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 {
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;
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
#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);
}
}
#local runtime :: package runtime
#package {
- ui :: package ui
+ ui :: package ui
+ game_net :: package game_net
}
State :: struct {
shaders_init();
fonts_init();
immediate_init();
- net_register_handles();
+ game_net.register_handles();
__initialize(^camera);
camera_set_fov(^camera, 75);
--- /dev/null
+
+use package core
+use package glfw3
+use package opengles
+
+#local {
+ ip_addr: [..] u8;
+ port: [..] u8;
+ name: [..] u8;
+
+ title_font: Font;
+}
+
+Connect_Menu :: struct {
+ init :: (_: rawptr) {
+ array.clear(^port);
+ port_buffer: [8] u8;
+ 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) {
+ game_net.connect(ip_addr, ~~ conv.str_to_i64(port));
+
+ pop_game_state();
+ push_game_state(Connecting_Menu, null);
+ }
+
+ draw :: (_: rawptr) {
+ if is_key_just_down(GLFW_KEY_ESCAPE) {
+ glfwSetWindowShouldClose(window, true);
+ }
+
+ glDisable(GL_DEPTH_TEST);
+ glClearColor(0.1, 0.1, 0.1, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ ww, wh := camera.window_width, camera.window_height;
+
+ font_draw_centered(title_font, 0, (wh - 70) / 3, ww, "Untitled Shooter Game");
+
+ tx := (ww - 200) / 2;
+ ty := (wh - 160) / 2;
+ ui.textbox_list_start();
+ ui.draw_textbox(.{tx, ty+0, 200, 40}, ^ip_addr, "IP Address");
+ ui.draw_textbox(.{tx, ty+40, 200, 40}, ^port, "Port");
+ ui.draw_textbox(.{tx, ty+80, 200, 40}, ^name, "Name");
+ ui.textbox_list_end();
+
+ if ui.draw_button(.{tx, ty+120, 200, 40}, "Join") {
+ join(_);
+ }
+ }
+}
+
+
+
+Connecting_Menu :: struct {
+ #persist font: Font;
+ #persist connection_timeout: f32;
+
+ init :: (_: rawptr) {
+ font = font_lookup(.{"./assets/fonts/calibri.ttf", 32});
+ game_net.set_on_connect_callback(.{ _, on_connect });
+
+ connection_timeout = 10.0; // 10 second timeout
+ }
+
+ on_connect :: (_: rawptr) {
+ game_net.send_connect(name);
+ }
+
+ leave :: (_: rawptr) {
+ delete(^ip_addr);
+ delete(^port);
+ delete(^name);
+ }
+
+ update :: (_: rawptr, dt: f32) {
+ game_net.pulse();
+
+ connection_timeout -= dt;
+ if connection_timeout < 0 {
+ pop_game_state();
+ push_game_state(Connect_Menu, null);
+ }
+ }
+
+ draw :: (_: rawptr) {
+ if is_key_just_down(GLFW_KEY_ESCAPE) {
+ game_net.disconnect();
+ glfwSetWindowShouldClose(window, true);
+ }
+
+ glDisable(GL_DEPTH_TEST);
+ glClearColor(0.1, 0.1, 0.1, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ ww, wh := camera.window_width, camera.window_height;
+
+ font_draw_centered(title_font, 0, (wh - 70) / 3, ww, "Untitled Shooter Game");
+
+ tx := (ww - 200) / 2;
+ ty := (wh - 16) / 2;
+ font_draw_centered(font, tx, ty, 200, "Connecting...");
+ }
+}
+++ /dev/null
-
-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 };
-}
-
-
--- /dev/null
+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);
+ }
+ }
+}
--- /dev/null
+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
--- /dev/null
+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);
+}
}
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)}]);
}
}
--- /dev/null
+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