Compare commits
2 Commits
99061337dd
...
01144b2bd4
| Author | SHA1 | Date | |
|---|---|---|---|
| 01144b2bd4 | |||
| 5dad7572b7 |
16
.vscode/launch.json
vendored
16
.vscode/launch.json
vendored
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Launch",
|
|
||||||
"type": "lldb",
|
|
||||||
"request": "launch",
|
|
||||||
"program": "${workspaceRoot}/<your program>",
|
|
||||||
"args": [],
|
|
||||||
"cwd": "${workspaceRoot}"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -4,24 +4,32 @@
|
|||||||
// see: https://zed.dev/docs/debugger
|
// see: https://zed.dev/docs/debugger
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"label": "Debug Zig Client",
|
||||||
"adapter": "CodeLLDB",
|
"adapter": "CodeLLDB",
|
||||||
"label": "zig build run",
|
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"build": {
|
"program": "$ZED_WORKTREE_ROOT/zig-out/bin/client",
|
||||||
"label": "zig build",
|
"cwd": "$ZED_WORKTREE_ROOT/",
|
||||||
"command": "zig",
|
"build": "zig build",
|
||||||
"args": ["build"],
|
|
||||||
"env": {},
|
|
||||||
"cwd": null,
|
|
||||||
"use_new_terminal": false,
|
|
||||||
"allow_concurrent_runs": false,
|
|
||||||
"reveal": "always",
|
|
||||||
"reveal_target": "dock",
|
|
||||||
"hide": "never",
|
|
||||||
//"tags": [],
|
|
||||||
"shell": "system",
|
|
||||||
"show_summary": false,
|
|
||||||
"show_command": false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// "adapter": "CodeLLDB",
|
||||||
|
// "label": "zig build run",
|
||||||
|
// "request": "launch",
|
||||||
|
// "build": {
|
||||||
|
// "label": "zig build",
|
||||||
|
// "command": "zig",
|
||||||
|
// "args": ["build"],
|
||||||
|
// "env": {},
|
||||||
|
// "cwd": null,
|
||||||
|
// "use_new_terminal": false,
|
||||||
|
// "allow_concurrent_runs": false,
|
||||||
|
// "reveal": "always",
|
||||||
|
// "reveal_target": "dock",
|
||||||
|
// "hide": "never",
|
||||||
|
// //"tags": [],
|
||||||
|
// "shell": "system",
|
||||||
|
// "show_summary": false,
|
||||||
|
// "show_command": false,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
]
|
]
|
||||||
|
|||||||
@ -2,55 +2,55 @@
|
|||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
[
|
[
|
||||||
{
|
// {
|
||||||
"label": "Example task",
|
// "label": "Example task",
|
||||||
"command": "for i in {1..5}; do echo \"Hello $i/5\"; sleep 1; done",
|
// "command": "for i in {1..5}; do echo \"Hello $i/5\"; sleep 1; done",
|
||||||
//"args": [],
|
// //"args": [],
|
||||||
// Env overrides for the command, will be appended to the terminal's environment from the settings.
|
// // Env overrides for the command, will be appended to the terminal's environment from the settings.
|
||||||
"env": { "foo": "bar" },
|
// "env": { "foo": "bar" },
|
||||||
// Current working directory to spawn the command into, defaults to current project root.
|
// // Current working directory to spawn the command into, defaults to current project root.
|
||||||
//"cwd": "/path/to/working/directory",
|
// //"cwd": "/path/to/working/directory",
|
||||||
// Whether to use a new terminal tab or reuse the existing one to spawn the process, defaults to `false`.
|
// // Whether to use a new terminal tab or reuse the existing one to spawn the process, defaults to `false`.
|
||||||
"use_new_terminal": false,
|
// "use_new_terminal": false,
|
||||||
// Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish, defaults to `false`.
|
// // Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish, defaults to `false`.
|
||||||
"allow_concurrent_runs": false,
|
// "allow_concurrent_runs": false,
|
||||||
// What to do with the terminal pane and tab, after the command was started:
|
// // What to do with the terminal pane and tab, after the command was started:
|
||||||
// * `always` — always show the task's pane, and focus the corresponding tab in it (default)
|
// // * `always` — always show the task's pane, and focus the corresponding tab in it (default)
|
||||||
// * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
|
// // * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
|
||||||
// * `never` — do not alter focus, but still add/reuse the task's tab in its pane
|
// // * `never` — do not alter focus, but still add/reuse the task's tab in its pane
|
||||||
"reveal": "always",
|
// "reveal": "always",
|
||||||
// Where to place the task's terminal item after starting the task:
|
// // Where to place the task's terminal item after starting the task:
|
||||||
// * `dock` — in the terminal dock, "regular" terminal items' place (default)
|
// // * `dock` — in the terminal dock, "regular" terminal items' place (default)
|
||||||
// * `center` — in the central pane group, "main" editor area
|
// // * `center` — in the central pane group, "main" editor area
|
||||||
"reveal_target": "dock",
|
// "reveal_target": "dock",
|
||||||
// What to do with the terminal pane and tab, after the command had finished:
|
// // What to do with the terminal pane and tab, after the command had finished:
|
||||||
// * `never` — Do nothing when the command finishes (default)
|
// // * `never` — Do nothing when the command finishes (default)
|
||||||
// * `always` — always hide the terminal tab, hide the pane also if it was the last tab in it
|
// // * `always` — always hide the terminal tab, hide the pane also if it was the last tab in it
|
||||||
// * `on_success` — hide the terminal tab on task success only, otherwise behaves similar to `always`
|
// // * `on_success` — hide the terminal tab on task success only, otherwise behaves similar to `always`
|
||||||
"hide": "never",
|
// "hide": "never",
|
||||||
// Which shell to use when running a task inside the terminal.
|
// // Which shell to use when running a task inside the terminal.
|
||||||
// May take 3 values:
|
// // May take 3 values:
|
||||||
// 1. (default) Use the system's default terminal configuration in /etc/passwd
|
// // 1. (default) Use the system's default terminal configuration in /etc/passwd
|
||||||
// "shell": "system"
|
// // "shell": "system"
|
||||||
// 2. A program:
|
// // 2. A program:
|
||||||
// "shell": {
|
// // "shell": {
|
||||||
// "program": "sh"
|
// // "program": "sh"
|
||||||
// }
|
// // }
|
||||||
// 3. A program with arguments:
|
// // 3. A program with arguments:
|
||||||
// "shell": {
|
// // "shell": {
|
||||||
// "with_arguments": {
|
// // "with_arguments": {
|
||||||
// "program": "/bin/bash",
|
// // "program": "/bin/bash",
|
||||||
// "args": ["--login"]
|
// // "args": ["--login"]
|
||||||
// }
|
// // }
|
||||||
// }
|
// // }
|
||||||
"shell": "system",
|
// "shell": "system",
|
||||||
// Whether to show the task line in the output of the spawned task, defaults to `true`.
|
// // Whether to show the task line in the output of the spawned task, defaults to `true`.
|
||||||
"show_summary": true,
|
// "show_summary": true,
|
||||||
// Whether to show the command line in the output of the spawned task, defaults to `true`.
|
// // Whether to show the command line in the output of the spawned task, defaults to `true`.
|
||||||
"show_command": true,
|
// "show_command": true,
|
||||||
// Represents the tags for inline runnable indicators, or spawning multiple tasks at once.
|
// // Represents the tags for inline runnable indicators, or spawning multiple tasks at once.
|
||||||
// "tags": []
|
// // "tags": []
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
"label": "zig build",
|
"label": "zig build",
|
||||||
"command": "zig build",
|
"command": "zig build",
|
||||||
|
|||||||
208
build.zig
208
build.zig
@ -1,149 +1,149 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
// Although this function looks imperative, it does not perform the build
|
|
||||||
// directly and instead it mutates the build graph (`b`) that will be then
|
|
||||||
// executed by an external runner. The functions in `std.Build` implement a DSL
|
|
||||||
// for defining build steps and express dependencies between them, allowing the
|
|
||||||
// build runner to parallelize the build automatically (and the cache system to
|
|
||||||
// know when a step doesn't need to be re-run).
|
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
// Standard target options allow the person running `zig build` to choose
|
|
||||||
// what target to build for. Here we do not override the defaults, which
|
|
||||||
// means any target is allowed, and the default is native. Other options
|
|
||||||
// for restricting supported target set are available.
|
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
// Standard optimization options allow the person running `zig build` to select
|
|
||||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
|
||||||
// set a preferred release mode, allowing the user to decide how to optimize.
|
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
// It's also possible to define more custom flags to toggle optional features
|
|
||||||
// of this build script using `b.option()`. All defined flags (including
|
|
||||||
// target and optimize options) will be listed when running `zig build --help`
|
|
||||||
// in this directory.
|
|
||||||
|
|
||||||
// This creates a module, which represents a collection of source files alongside
|
const raylib_dep = b.dependency("raylib_zig", .{
|
||||||
// some compilation options, such as optimization mode and linked system libraries.
|
.target = target,
|
||||||
// Zig modules are the preferred way of making Zig code available to consumers.
|
.optimize = optimize,
|
||||||
// addModule defines a module that we intend to make available for importing
|
});
|
||||||
// to our consumers. We must give it a name because a Zig package can expose
|
|
||||||
// multiple modules and consumers will need to be able to specify which
|
const raylib = raylib_dep.module("raylib"); // main raylib module
|
||||||
// module they want to access.
|
const raygui = raylib_dep.module("raygui"); // raygui module
|
||||||
const mod = b.addModule("zzz", .{
|
const raylib_artifact = raylib_dep.artifact("raylib"); // raylib C library
|
||||||
// The root source file is the "entry point" of this module. Users of
|
|
||||||
// this module will only be able to access public declarations contained
|
// const sdl3 = b.dependency("sdl3", .{
|
||||||
// in this file, which means that if you have declarations that you
|
// .target = target,
|
||||||
// intend to expose to consumers that were defined in other files part
|
// .optimize = .Debug,
|
||||||
// of this module, you will have to make sure to re-export them from
|
|
||||||
// the root file.
|
// // Lib options.
|
||||||
.root_source_file = b.path("src/root.zig"),
|
// // .callbacks = false,
|
||||||
// Later on we'll use this module as the root module of a test executable
|
// // .ext_image = false,
|
||||||
// which requires us to specify a target.
|
// // .ext_net = false,
|
||||||
|
// // .ext_ttf = false,
|
||||||
|
// // .log_message_stack_size = 1024,
|
||||||
|
// // .main = false,
|
||||||
|
// // .renderer_debug_text_stack_size = 1024,
|
||||||
|
|
||||||
|
// // Options passed directly to https://github.com/castholm/SDL (SDL3 C Bindings):
|
||||||
|
// // .c_sdl_preferred_linkage = .static,
|
||||||
|
// // .c_sdl_strip = false,
|
||||||
|
// // .c_sdl_sanitize_c = .off,
|
||||||
|
// // .c_sdl_lto = .none,
|
||||||
|
// // .c_sdl_emscripten_pthreads = false,
|
||||||
|
// // .c_sdl_install_build_config_h = false,
|
||||||
|
|
||||||
|
// // Options if `ext_image` is enabled:
|
||||||
|
// // .image_enable_bmp = true,
|
||||||
|
// // .image_enable_gif = true,
|
||||||
|
// // .image_enable_jpg = true,
|
||||||
|
// // .image_enable_lbm = true,
|
||||||
|
// // .image_enable_pcx = true,
|
||||||
|
// // .image_enable_png = true,
|
||||||
|
// // .image_enable_pnm = true,
|
||||||
|
// // .image_enable_qoi = true,
|
||||||
|
// // .image_enable_svg = true,
|
||||||
|
// // .image_enable_tga = true,
|
||||||
|
// // .image_enable_xcf = true,
|
||||||
|
// // .image_enable_xpm = true,
|
||||||
|
// // .image_enable_xv = true,
|
||||||
|
// });
|
||||||
|
|
||||||
|
const shared = b.addModule("shared", .{
|
||||||
|
.root_source_file = b.path("src/shared/shared.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Here we define an executable. An executable needs to have a root module
|
const client = b.addExecutable(.{
|
||||||
// which needs to expose a `main` function. While we could add a main function
|
.name = "client",
|
||||||
// to the module defined above, it's sometimes preferable to split business
|
|
||||||
// logic and the CLI into two separate modules.
|
|
||||||
//
|
|
||||||
// If your goal is to create a Zig library for others to use, consider if
|
|
||||||
// it might benefit from also exposing a CLI tool. A parser library for a
|
|
||||||
// data serialization format could also bundle a CLI syntax checker, for example.
|
|
||||||
//
|
|
||||||
// If instead your goal is to create an executable, consider if users might
|
|
||||||
// be interested in also being able to embed the core functionality of your
|
|
||||||
// program in their own executable in order to avoid the overhead involved in
|
|
||||||
// subprocessing your CLI tool.
|
|
||||||
//
|
|
||||||
// If neither case applies to you, feel free to delete the declaration you
|
|
||||||
// don't need and to put everything under a single module.
|
|
||||||
const exe = b.addExecutable(.{
|
|
||||||
.name = "zzz",
|
|
||||||
.root_module = b.createModule(.{
|
.root_module = b.createModule(.{
|
||||||
// b.createModule defines a new module just like b.addModule but,
|
.root_source_file = b.path("src/client/main.zig"),
|
||||||
// unlike b.addModule, it does not expose the module to consumers of
|
|
||||||
// this package, which is why in this case we don't have to give it a name.
|
|
||||||
.root_source_file = b.path("src/main.zig"),
|
|
||||||
// Target and optimization levels must be explicitly wired in when
|
|
||||||
// defining an executable or library (in the root module), and you
|
|
||||||
// can also hardcode a specific target for an executable or library
|
|
||||||
// definition if desireable (e.g. firmware for embedded devices).
|
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
// List of modules available for import in source files part of the
|
|
||||||
// root module.
|
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
// Here "zzz" is the name you will use in your source code to
|
.{ .name = "shared", .module = shared },
|
||||||
// import this module (e.g. `@import("zzz")`). The name is
|
},
|
||||||
// repeated because you are allowed to rename your imports, which
|
}),
|
||||||
// can be extremely useful in case of collisions (which can happen
|
});
|
||||||
// importing modules from different packages).
|
|
||||||
.{ .name = "zzz", .module = mod },
|
const server = b.addExecutable(.{
|
||||||
|
.name = "server",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/server/main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.imports = &.{
|
||||||
|
.{ .name = "shared", .module = shared },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const zmath = b.dependency("zmath", .{});
|
const zmath = b.dependency("zmath", .{});
|
||||||
exe.root_module.addImport("zmath", zmath.module("root"));
|
client.root_module.addImport("zmath", zmath.module("root"));
|
||||||
|
server.root_module.addImport("zmath", zmath.module("root"));
|
||||||
|
shared.addImport("zmath", zmath.module("root"));
|
||||||
|
|
||||||
// This declares intent for the executable to be installed into the
|
const znet_dep = b.dependency("znet", .{
|
||||||
// install prefix when running `zig build` (i.e. when executing the default
|
.target = target,
|
||||||
// step). By default the install prefix is `zig-out/` but can be overridden
|
.optimize = optimize,
|
||||||
// by passing `--prefix` or `-p`.
|
});
|
||||||
b.installArtifact(exe);
|
const znet_mod = znet_dep.module("znet");
|
||||||
|
const znet_artifact = znet_dep.artifact("znet");
|
||||||
|
|
||||||
|
client.root_module.addImport("znet", znet_mod);
|
||||||
|
client.linkLibrary(znet_artifact);
|
||||||
|
|
||||||
|
client.linkLibrary(raylib_artifact);
|
||||||
|
client.root_module.addImport("raylib", raylib);
|
||||||
|
client.root_module.addImport("raygui", raygui);
|
||||||
|
|
||||||
|
server.root_module.addImport("znet", znet_mod);
|
||||||
|
server.linkLibrary(znet_artifact);
|
||||||
|
|
||||||
|
b.installArtifact(client);
|
||||||
|
b.installArtifact(server);
|
||||||
|
|
||||||
// This creates a top level step. Top level steps have a name and can be
|
|
||||||
// invoked by name when running `zig build` (e.g. `zig build run`).
|
|
||||||
// This will evaluate the `run` step rather than the default step.
|
|
||||||
// For a top level step to actually do something, it must depend on other
|
|
||||||
// steps (e.g. a Run step, as we will see in a moment).
|
|
||||||
const run_step = b.step("run", "Run the app");
|
const run_step = b.step("run", "Run the app");
|
||||||
|
|
||||||
// This creates a RunArtifact step in the build graph. A RunArtifact step
|
const run_cmd_client = b.addRunArtifact(client);
|
||||||
// invokes an executable compiled by Zig. Steps will only be executed by the
|
const run_cmd_server = b.addRunArtifact(server);
|
||||||
// runner if invoked directly by the user (in the case of top level steps)
|
run_step.dependOn(&run_cmd_client.step);
|
||||||
// or if another step depends on it, so it's up to you to define when and
|
run_step.dependOn(&run_cmd_server.step);
|
||||||
// how this Run step will be executed. In our case we want to run it when
|
|
||||||
// the user runs `zig build run`, so we create a dependency link.
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
|
||||||
run_step.dependOn(&run_cmd.step);
|
|
||||||
|
|
||||||
// By making the run step depend on the default step, it will be run from the
|
run_cmd_client.step.dependOn(b.getInstallStep());
|
||||||
// installation directory rather than directly from within the cache directory.
|
run_cmd_server.step.dependOn(b.getInstallStep());
|
||||||
run_cmd.step.dependOn(b.getInstallStep());
|
|
||||||
|
|
||||||
// This allows the user to pass arguments to the application in the build
|
|
||||||
// command itself, like this: `zig build run -- arg1 arg2 etc`
|
|
||||||
if (b.args) |args| {
|
if (b.args) |args| {
|
||||||
run_cmd.addArgs(args);
|
run_cmd_client.addArgs(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates an executable that will run `test` blocks from the provided module.
|
// Creates an executable that will run `test` blocks from the provided module.
|
||||||
// Here `mod` needs to define a target, which is why earlier we made sure to
|
// Here `mod` needs to define a target, which is why earlier we made sure to
|
||||||
// set the releative field.
|
// set the releative field.
|
||||||
const mod_tests = b.addTest(.{
|
// const mod_tests = b.addTest(.{
|
||||||
.root_module = mod,
|
// .root_module = mod,
|
||||||
});
|
// });
|
||||||
|
|
||||||
// A run step that will run the test executable.
|
// A run step that will run the test executable.
|
||||||
const run_mod_tests = b.addRunArtifact(mod_tests);
|
// const run_mod_tests = b.addRunArtifact(mod_tests);
|
||||||
|
|
||||||
// Creates an executable that will run `test` blocks from the executable's
|
// Creates an executable that will run `test` blocks from the executable's
|
||||||
// root module. Note that test executables only test one module at a time,
|
// root module. Note that test executables only test one module at a time,
|
||||||
// hence why we have to create two separate ones.
|
// hence why we have to create two separate ones.
|
||||||
const exe_tests = b.addTest(.{
|
// const exe_tests = b.addTest(.{
|
||||||
.root_module = exe.root_module,
|
// .root_module = exe.root_module,
|
||||||
});
|
// });
|
||||||
|
|
||||||
// A run step that will run the second test executable.
|
// A run step that will run the second test executable.
|
||||||
const run_exe_tests = b.addRunArtifact(exe_tests);
|
// const run_exe_tests = b.addRunArtifact(exe_tests);
|
||||||
|
|
||||||
// A top level step for running all tests. dependOn can be called multiple
|
// A top level step for running all tests. dependOn can be called multiple
|
||||||
// times and since the two run steps do not depend on one another, this will
|
// times and since the two run steps do not depend on one another, this will
|
||||||
// make the two of them run in parallel.
|
// make the two of them run in parallel.
|
||||||
const test_step = b.step("test", "Run tests");
|
// const test_step = b.step("test", "Run tests");
|
||||||
test_step.dependOn(&run_mod_tests.step);
|
// test_step.dependOn(&run_mod_tests.step);
|
||||||
test_step.dependOn(&run_exe_tests.step);
|
// test_step.dependOn(&run_exe_tests.step);
|
||||||
|
|
||||||
// Just like flags, top level steps are also listed in the `--help` menu.
|
// Just like flags, top level steps are also listed in the `--help` menu.
|
||||||
//
|
//
|
||||||
|
|||||||
@ -36,6 +36,18 @@
|
|||||||
.url = "git+https://github.com/zig-gamedev/zmath.git#3a5955b2b72cd081563fbb084eff05bffd1e3fbb",
|
.url = "git+https://github.com/zig-gamedev/zmath.git#3a5955b2b72cd081563fbb084eff05bffd1e3fbb",
|
||||||
.hash = "zmath-0.11.0-dev-wjwivdMsAwD-xaLj76YHUq3t9JDH-X16xuMTmnDzqbu2",
|
.hash = "zmath-0.11.0-dev-wjwivdMsAwD-xaLj76YHUq3t9JDH-X16xuMTmnDzqbu2",
|
||||||
},
|
},
|
||||||
|
.sdl3 = .{
|
||||||
|
.url = "git+https://github.com/Gota7/zig-sdl3?ref=master#79b0d1f1ef10a424037025f6af44fe06bf7e062c",
|
||||||
|
.hash = "sdl3-0.1.5-NmT1Q3ARJgDmFWtbbK3KBb7vufbQD0EjD4Me4Fbdq0p3",
|
||||||
|
},
|
||||||
|
.raylib_zig = .{
|
||||||
|
.url = "git+https://github.com/raylib-zig/raylib-zig?ref=devel#a4d18b2d1cf8fdddec68b5b084535fca0475f466",
|
||||||
|
.hash = "raylib_zig-5.6.0-dev-KE8REL5MBQAf3p497t52Xw9P7ojndIkVOWPXnLiLLw2P",
|
||||||
|
},
|
||||||
|
.znet = .{
|
||||||
|
.url = "git+https://github.com/connellr023/znet#cb11fb0c4a2b668128c436fbbccd111223c74898",
|
||||||
|
.hash = "znet-0.0.0-PGDNtD9RAAChe8Ky4dhWhS2XH77-xyf1X8HcDBwpM3kA",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
.paths = .{
|
.paths = .{
|
||||||
"build.zig",
|
"build.zig",
|
||||||
|
|||||||
26
src/client/client.zig
Normal file
26
src/client/client.zig
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const ConnectState = union(enum) {
|
||||||
|
disconnected,
|
||||||
|
connecting,
|
||||||
|
connected: std.net.Stream,
|
||||||
|
err: anyerror,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Client = struct {
|
||||||
|
state: ConnectState = .disconnected,
|
||||||
|
|
||||||
|
pub fn startConnect(self: *Client, addr: std.net.Address) void {
|
||||||
|
if (self.state == .connecting or self.state == .connected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
self.state = .connecting;
|
||||||
|
|
||||||
|
const stream = std.net.tcpConnectToAddress(addr) catch |err| {
|
||||||
|
self.state = .{ .err = err };
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.state = .{ .connected = stream };
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,58 +1,131 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const zm = @import("zmath");
|
const zm = @import("zmath");
|
||||||
|
const znet = @import("znet");
|
||||||
|
const rl = @import("raylib");
|
||||||
|
|
||||||
const shared = @import("shared");
|
const shared = @import("shared");
|
||||||
|
|
||||||
|
const client = @import("client.zig");
|
||||||
|
|
||||||
|
const screen_width = 640;
|
||||||
|
const screen_height = 480;
|
||||||
|
|
||||||
|
var running: bool = true;
|
||||||
|
|
||||||
|
var dbg_allocator: std.heap.DebugAllocator(.{}) = undefined;
|
||||||
|
const allocator = dbg_allocator.allocator();
|
||||||
|
|
||||||
var stdout: *std.io.Writer = undefined;
|
var stdout: *std.io.Writer = undefined;
|
||||||
|
|
||||||
|
// var connection: ?std.net.Stream = undefined;
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
std.log.info("Helllo Client!", .{});
|
std.log.info("Hello Client!", .{});
|
||||||
var dbg_allocator = std.heap.DebugAllocator(.{}).init;
|
|
||||||
|
try init();
|
||||||
|
try znet.init();
|
||||||
|
defer znet.deinit();
|
||||||
|
rl.initWindow(1280, 720, "raylib-zig [core] example - basic window");
|
||||||
|
defer rl.closeWindow();
|
||||||
|
|
||||||
|
const host = try znet.Host.init(.{
|
||||||
|
.addr = null,
|
||||||
|
.peer_limit = 1,
|
||||||
|
.channel_limit = .max,
|
||||||
|
.incoming_bandwidth = .unlimited,
|
||||||
|
.outgoing_bandwidth = .unlimited,
|
||||||
|
});
|
||||||
|
defer host.deinit();
|
||||||
|
|
||||||
|
const peer = try host.connect(.{
|
||||||
|
.addr = try .init(.{
|
||||||
|
.ip = .{ .ipv4 = "127.0.0.1" },
|
||||||
|
.port = .{ .uint = 5000 },
|
||||||
|
}),
|
||||||
|
.channel_limit = .max,
|
||||||
|
.data = 0,
|
||||||
|
});
|
||||||
|
|
||||||
defer _ = dbg_allocator.deinit();
|
defer _ = dbg_allocator.deinit();
|
||||||
const allocator = dbg_allocator.allocator();
|
|
||||||
|
|
||||||
var stdout_buffer: [1024]u8 = undefined;
|
// connect() catch |err| switch (err) {
|
||||||
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
|
// error.ConnectionRefused => {
|
||||||
stdout = &stdout_writer.interface;
|
// std.log.err("server refused connection", .{});
|
||||||
|
// },
|
||||||
|
// else => {
|
||||||
|
// std.log.err("unexpected connect error: {}", .{err});
|
||||||
|
// return err;
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
std.log.info("{s}", .{@typeName(shared.chunk.Chunk)});
|
// try stdout.flush();
|
||||||
|
|
||||||
try stdout.flush();
|
|
||||||
|
|
||||||
const address = try std.net.Address.parseIp4("127.0.0.1", shared.protocol.SERVER_PORT);
|
|
||||||
|
|
||||||
var connection = try std.net.tcpConnectToAddress(address);
|
|
||||||
|
|
||||||
std.log.info("Connected to server", .{});
|
|
||||||
|
|
||||||
var the_chunk = try shared.chunk.initChunk(allocator);
|
var the_chunk = try shared.chunk.initChunk(allocator);
|
||||||
defer shared.chunk.deinitChunk(&the_chunk, allocator);
|
defer shared.chunk.deinitChunk(&the_chunk, allocator);
|
||||||
|
|
||||||
shared.chunk.spawn(&the_chunk, shared.entity.Player, allocator, .{
|
|
||||||
.pos = zm.f32x4(1, 1, 0, 0),
|
|
||||||
.hp = 10,
|
|
||||||
});
|
|
||||||
|
|
||||||
shared.chunk.spawn(&the_chunk, shared.entity.Monster, allocator, .{
|
|
||||||
.pos = zm.f32x4(1, 1, 0, 0),
|
|
||||||
.hp = 20,
|
|
||||||
});
|
|
||||||
|
|
||||||
shared.chunk.spawn(&the_chunk, shared.entity.Projectile, allocator, .{
|
|
||||||
.pos = zm.f32x4(0, 0, 0, 0),
|
|
||||||
.vel = zm.f32x4(0.2, 0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
shared.chunk.updateChunk(&the_chunk);
|
shared.chunk.updateChunk(&the_chunk);
|
||||||
|
|
||||||
var send_buf: [1024]u8 = undefined;
|
// var send_buf: [1024]u8 = undefined;
|
||||||
var writer = connection.writer(&send_buf);
|
// var writer = if (connection) |*conn| conn.writer(&send_buf) else return;
|
||||||
|
|
||||||
try shared.protocol.sendHello(&writer.interface, .{ .msg = "Hello from client" });
|
// try shared.protocol.sendHello(&writer.interface, .{ .msg = "Hello from client" });
|
||||||
|
|
||||||
var recv_buf: [1024]u8 = undefined;
|
// var recv_buf: [1024]u8 = undefined;
|
||||||
var reader = connection.reader(&recv_buf);
|
// var reader = if (connection) |*conn| conn.reader(&recv_buf) else return;
|
||||||
const line = try shared.protocol.recvLine(reader.interface());
|
// const line = try reader.interface().takeDelimiterExclusive('\n');
|
||||||
std.log.info("{s}", .{line});
|
// std.log.info("{s}", .{line});
|
||||||
|
|
||||||
|
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
|
||||||
|
while (try host.service(0)) |event| switch (event) {
|
||||||
|
.connect => |data| {
|
||||||
|
_ = data;
|
||||||
|
// std.log.info("{}", .{data.peer});
|
||||||
|
},
|
||||||
|
.disconnect => |data| {
|
||||||
|
// _ = data;
|
||||||
|
std.log.info("{}", .{data.peer});
|
||||||
|
},
|
||||||
|
.receive => |data| {
|
||||||
|
std.log.info("{s}", .{data.packet.dataSlice()});
|
||||||
|
defer data.packet.deinit();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (peer.state() == .connected) {
|
||||||
|
const packet = try znet.Packet.init("Hello, Server!", 0, .reliable);
|
||||||
|
try peer.send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// TODO: Update your variables here
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
rl.beginDrawing();
|
||||||
|
defer rl.endDrawing();
|
||||||
|
|
||||||
|
rl.clearBackground(.sky_blue);
|
||||||
|
|
||||||
|
rl.drawText("Congrats! You created your first window!", 190, 200, 20, .light_gray);
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init() !void {
|
||||||
|
dbg_allocator = std.heap.DebugAllocator(.{}).init;
|
||||||
|
var stdout_buffer: [1024]u8 = undefined;
|
||||||
|
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
|
||||||
|
stdout = &stdout_writer.interface;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect() !void {
|
||||||
|
// const address = try std.net.Address.parseIp4("127.0.0.1", shared.protocol.SERVER_PORT);
|
||||||
|
|
||||||
|
// connection = try std.net.tcpConnectToAddress(address);
|
||||||
|
|
||||||
|
// std.log.info("Connected to server", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
//fn handle_connection(connection: std.net.Server.Connection) !void {}
|
//fn handle_connection(connection: std.net.Server.Connection) !void {}
|
||||||
|
|||||||
30
src/server/chunk.zig
Normal file
30
src/server/chunk.zig
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const shared = @import("shared");
|
||||||
|
const server = @import("server.zig");
|
||||||
|
|
||||||
|
pub fn spawn(chunk: *shared.chunk.Chunk(), comptime T: type, allocator: std.mem.Allocator, value: T, w: *std.Io.Writer) !void {
|
||||||
|
const id = server.next_entity_id;
|
||||||
|
server.next_entity_id += 1;
|
||||||
|
|
||||||
|
var entity = value;
|
||||||
|
entity.id = id;
|
||||||
|
|
||||||
|
inline for (@typeInfo(shared.chunk.Chunk()).@"struct".fields) |field| {
|
||||||
|
if (field.type == shared.chunk.Storage(T)) {
|
||||||
|
try @field(chunk, field.name).items.append(allocator, entity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// serialize entity
|
||||||
|
var buffer: [64]u8 = undefined;
|
||||||
|
var fbs = std.io.fixedBufferStream(&buffer);
|
||||||
|
try T.encode(entity, fbs.writer());
|
||||||
|
|
||||||
|
try shared.protocol.write_message(
|
||||||
|
w,
|
||||||
|
.spawn_entity,
|
||||||
|
fbs.getWritten(),
|
||||||
|
);
|
||||||
|
try w.flush();
|
||||||
|
}
|
||||||
@ -1,11 +1,16 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const zm = @import("zmath");
|
const zm = @import("zmath");
|
||||||
|
const znet = @import("znet");
|
||||||
|
|
||||||
const shared = @import("shared");
|
const shared = @import("shared");
|
||||||
|
|
||||||
|
const chunk = @import("chunk.zig");
|
||||||
|
const server = @import("server.zig");
|
||||||
|
|
||||||
var stdout: *std.io.Writer = undefined;
|
var stdout: *std.io.Writer = undefined;
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
std.log.info("Helllo Server!", .{});
|
std.log.info("Hello Server!", .{});
|
||||||
var dbg_allocator = std.heap.DebugAllocator(.{}).init;
|
var dbg_allocator = std.heap.DebugAllocator(.{}).init;
|
||||||
defer _ = dbg_allocator.deinit();
|
defer _ = dbg_allocator.deinit();
|
||||||
const allocator = dbg_allocator.allocator();
|
const allocator = dbg_allocator.allocator();
|
||||||
@ -14,50 +19,76 @@ pub fn main() !void {
|
|||||||
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
|
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
|
||||||
stdout = &stdout_writer.interface;
|
stdout = &stdout_writer.interface;
|
||||||
|
|
||||||
std.log.info("{s}", .{@typeName(shared.chunk.Chunk)});
|
|
||||||
|
|
||||||
try stdout.flush();
|
try stdout.flush();
|
||||||
|
|
||||||
const address = try std.net.Address.parseIp4("127.0.0.1", shared.protocol.SERVER_PORT);
|
try znet.init();
|
||||||
var server = try address.listen(.{});
|
defer znet.deinit();
|
||||||
|
|
||||||
defer server.deinit();
|
const host = try znet.Host.init(.{
|
||||||
|
.addr = try .init(.{
|
||||||
|
.ip = .any,
|
||||||
|
.port = .{ .uint = 5000 },
|
||||||
|
}),
|
||||||
|
.peer_limit = 32,
|
||||||
|
.channel_limit = .max,
|
||||||
|
.incoming_bandwidth = .unlimited,
|
||||||
|
.outgoing_bandwidth = .unlimited,
|
||||||
|
});
|
||||||
|
|
||||||
|
// const address = try std.net.Address.parseIp4("127.0.0.1", shared.protocol.SERVER_PORT);
|
||||||
|
// var tcp_server = try address.listen(.{});
|
||||||
|
|
||||||
|
// defer tcp_server.deinit();
|
||||||
|
|
||||||
var the_chunk = try shared.chunk.initChunk(allocator);
|
var the_chunk = try shared.chunk.initChunk(allocator);
|
||||||
defer shared.chunk.deinitChunk(&the_chunk, allocator);
|
defer shared.chunk.deinitChunk(&the_chunk, allocator);
|
||||||
|
|
||||||
shared.chunk.spawn(&the_chunk, shared.entity.Player, allocator, .{
|
|
||||||
.pos = zm.f32x4(1, 1, 0, 0),
|
|
||||||
.hp = 10,
|
|
||||||
});
|
|
||||||
|
|
||||||
shared.chunk.spawn(&the_chunk, shared.entity.Monster, allocator, .{
|
|
||||||
.pos = zm.f32x4(1, 1, 0, 0),
|
|
||||||
.hp = 20,
|
|
||||||
});
|
|
||||||
|
|
||||||
shared.chunk.spawn(&the_chunk, shared.entity.Projectile, allocator, .{
|
|
||||||
.pos = zm.f32x4(0, 0, 0, 0),
|
|
||||||
.vel = zm.f32x4(0.2, 0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
shared.chunk.updateChunk(&the_chunk);
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const connection = try server.accept();
|
while (try host.service(500)) |event| switch (event) {
|
||||||
defer connection.stream.close();
|
.connect => |data| {
|
||||||
|
_ = data;
|
||||||
|
// std.log.info("{}", .{data.peer});
|
||||||
|
},
|
||||||
|
.disconnect => |data| {
|
||||||
|
_ = data;
|
||||||
|
// std.log.info("{}", .{data.peer});
|
||||||
|
},
|
||||||
|
.receive => |data| {
|
||||||
|
std.log.info("{s}", .{data.packet.dataSlice()});
|
||||||
|
defer data.packet.deinit();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
std.log.info("Client connected", .{});
|
// const connection = try tcp_server.accept();
|
||||||
|
// defer connection.stream.close();
|
||||||
|
|
||||||
var recv_buffer: [4096]u8 = undefined;
|
// var recv_buffer: [4096]u8 = undefined;
|
||||||
var send_buffer: [4096]u8 = undefined;
|
// var reader = connection.stream.reader(&recv_buffer);
|
||||||
var reader = connection.stream.reader(&recv_buffer);
|
|
||||||
var writer = connection.stream.writer(&send_buffer);
|
|
||||||
|
|
||||||
const line = try shared.protocol.recvLine(reader.interface());
|
// const line = try reader.interface().takeDelimiterExclusive('\n');
|
||||||
std.log.info("Received: {s}", .{line});
|
// std.log.info("Received: {s}", .{line});
|
||||||
|
|
||||||
try shared.protocol.sendHello(&writer.interface, .{ .msg = "Hello from server!" });
|
// var send_buffer: [4096]u8 = undefined;
|
||||||
|
// var writer = connection.stream.writer(&send_buffer);
|
||||||
|
// const w = &writer.interface;
|
||||||
|
// try shared.protocol.sendHello(w, .{ .msg = "Hello from server!" });
|
||||||
|
|
||||||
|
// try chunk.spawn(&the_chunk, shared.entity.Player, allocator, .{
|
||||||
|
// .pos = zm.f32x4(1, 1, 0, 0),
|
||||||
|
// .hp = 10,
|
||||||
|
// }, w);
|
||||||
|
|
||||||
|
// try chunk.spawn(&the_chunk, shared.entity.Monster, allocator, .{
|
||||||
|
// .pos = zm.f32x4(1, 1, 0, 0),
|
||||||
|
// .hp = 20,
|
||||||
|
// }, w);
|
||||||
|
|
||||||
|
// try chunk.spawn(&the_chunk, shared.entity.Projectile, allocator, .{
|
||||||
|
// .pos = zm.f32x4(0, 0, 0, 0),
|
||||||
|
// .vel = zm.f32x4(0.2, 0, 0, 0),
|
||||||
|
// }, w);
|
||||||
|
|
||||||
|
shared.chunk.updateChunk(&the_chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3
src/server/server.zig
Normal file
3
src/server/server.zig
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const shared = @import("shared");
|
||||||
|
|
||||||
|
pub var next_entity_id: shared.entity.entity_id = 1;
|
||||||
@ -2,7 +2,7 @@ const std = @import("std");
|
|||||||
const entity = @import("entity.zig");
|
const entity = @import("entity.zig");
|
||||||
const misc = @import("misc.zig");
|
const misc = @import("misc.zig");
|
||||||
|
|
||||||
fn Storage(comptime T: type) type {
|
pub fn Storage(comptime T: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
items: std.ArrayList(T),
|
items: std.ArrayList(T),
|
||||||
|
|
||||||
@ -26,10 +26,10 @@ fn Storage(comptime T: type) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initChunk(allocator: std.mem.Allocator) !Chunk {
|
pub fn initChunk(allocator: std.mem.Allocator) !Chunk() {
|
||||||
var chunk: Chunk = undefined;
|
var chunk: Chunk() = undefined;
|
||||||
|
|
||||||
switch (@typeInfo(Chunk)) {
|
switch (@typeInfo(Chunk())) {
|
||||||
.@"struct" => |s| {
|
.@"struct" => |s| {
|
||||||
inline for (s.fields) |field| {
|
inline for (s.fields) |field| {
|
||||||
const StorageT = field.type;
|
const StorageT = field.type;
|
||||||
@ -42,8 +42,8 @@ pub fn initChunk(allocator: std.mem.Allocator) !Chunk {
|
|||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinitChunk(chunk: *Chunk, allocator: std.mem.Allocator) void {
|
pub fn deinitChunk(chunk: *Chunk(), allocator: std.mem.Allocator) void {
|
||||||
switch (@typeInfo(Chunk)) {
|
switch (@typeInfo(Chunk())) {
|
||||||
.@"struct" => |s| {
|
.@"struct" => |s| {
|
||||||
inline for (s.fields) |field| {
|
inline for (s.fields) |field| {
|
||||||
@field(chunk, field.name).deinit(allocator);
|
@field(chunk, field.name).deinit(allocator);
|
||||||
@ -53,12 +53,12 @@ pub fn deinitChunk(chunk: *Chunk, allocator: std.mem.Allocator) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _Chunk(comptime Types: anytype) type {
|
pub fn Chunk() type {
|
||||||
const FieldCount = Types.len;
|
const FieldCount = entity.EntityKinds.len;
|
||||||
|
|
||||||
var fields: [FieldCount]std.builtin.Type.StructField = undefined;
|
var fields: [FieldCount]std.builtin.Type.StructField = undefined;
|
||||||
|
|
||||||
inline for (Types, 0..) |T, i| {
|
inline for (entity.EntityKinds, 0..) |T, i| {
|
||||||
fields[i] = .{
|
fields[i] = .{
|
||||||
.name = misc.short_type_name(T),
|
.name = misc.short_type_name(T),
|
||||||
.type = Storage(T),
|
.type = Storage(T),
|
||||||
@ -78,10 +78,8 @@ fn _Chunk(comptime Types: anytype) type {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Chunk = _Chunk(entity.EntityKinds);
|
pub fn updateChunk(chunk: *Chunk()) void {
|
||||||
|
const info = @typeInfo(Chunk());
|
||||||
pub fn updateChunk(chunk: *Chunk) void {
|
|
||||||
const info = @typeInfo(Chunk);
|
|
||||||
|
|
||||||
switch (info) {
|
switch (info) {
|
||||||
.@"struct" => |s| {
|
.@"struct" => |s| {
|
||||||
@ -92,8 +90,3 @@ pub fn updateChunk(chunk: *Chunk) void {
|
|||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn(chunk: anytype, comptime T: type, allocator: std.mem.Allocator, value: T) void {
|
|
||||||
std.log.info("hello!? {s}", .{@typeName(T)});
|
|
||||||
@field(chunk, misc.short_type_name(T)).items.append(allocator, value) catch unreachable;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const zm = @import("zmath");
|
const zm = @import("zmath");
|
||||||
|
const protocol = @import("protocol.zig");
|
||||||
|
|
||||||
|
pub const entity_id = u64;
|
||||||
|
pub const INVALID_ENTITY_ID: entity_id = 0;
|
||||||
|
|
||||||
pub const EntityKinds = .{
|
pub const EntityKinds = .{
|
||||||
Player,
|
Player,
|
||||||
@ -8,24 +12,47 @@ pub const EntityKinds = .{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Player = struct {
|
pub const Player = struct {
|
||||||
|
id: entity_id = INVALID_ENTITY_ID,
|
||||||
pos: zm.Vec,
|
pos: zm.Vec,
|
||||||
hp: i32,
|
hp: i32,
|
||||||
|
|
||||||
pub fn update(self: *Player) void {
|
pub fn encode(self: Projectile, w: *std.Io.Writer) !void {
|
||||||
std.log.info("pos=({})", .{self.pos});
|
try w.writeInt(u64, self.id, .little);
|
||||||
|
try protocol.writeVec4(w, self.pos);
|
||||||
|
try protocol.writeVec4(w, self.vel);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(r: *std.Io.Reader) !Projectile {
|
||||||
|
return .{
|
||||||
|
.id = try r.readInt(u64, .little),
|
||||||
|
.pos = try protocol.readVec4(r),
|
||||||
|
.vel = try protocol.readVec4(r),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Monster = struct {
|
pub const Monster = struct {
|
||||||
|
id: entity_id = INVALID_ENTITY_ID,
|
||||||
pos: zm.Vec,
|
pos: zm.Vec,
|
||||||
hp: i32,
|
hp: i32,
|
||||||
|
|
||||||
pub fn update(self: *Monster) void {
|
pub fn encode(self: Projectile, w: *std.Io.Writer) !void {
|
||||||
std.log.info("pos=({})", .{self.pos});
|
try w.writeInt(u64, self.id, .little);
|
||||||
|
try protocol.writeVec4(w, self.pos);
|
||||||
|
try protocol.writeVec4(w, self.vel);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(r: *std.Io.Reader) !Projectile {
|
||||||
|
return .{
|
||||||
|
.id = try r.readInt(u64, .little),
|
||||||
|
.pos = try protocol.readVec4(r),
|
||||||
|
.vel = try protocol.readVec4(r),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Projectile = struct {
|
pub const Projectile = struct {
|
||||||
|
id: entity_id = INVALID_ENTITY_ID,
|
||||||
pos: zm.Vec,
|
pos: zm.Vec,
|
||||||
vel: zm.Vec,
|
vel: zm.Vec,
|
||||||
|
|
||||||
@ -33,4 +60,18 @@ pub const Projectile = struct {
|
|||||||
self.pos = self.pos + self.vel;
|
self.pos = self.pos + self.vel;
|
||||||
std.log.info("pos=({})", .{self.pos});
|
std.log.info("pos=({})", .{self.pos});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encode(self: Projectile, w: *std.Io.Writer) !void {
|
||||||
|
try w.writeInt(u64, self.id, .little);
|
||||||
|
try protocol.writeVec4(w, self.pos);
|
||||||
|
try protocol.writeVec4(w, self.vel);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(r: *std.Io.Reader) !Projectile {
|
||||||
|
return .{
|
||||||
|
.id = try r.readInt(u64, .little),
|
||||||
|
.pos = try protocol.readVec4(r),
|
||||||
|
.vel = try protocol.readVec4(r),
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,27 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub fn short_type_name(comptime T: type) [:0]const u8 {
|
pub fn short_type_name(comptime T: type) [:0]const u8 {
|
||||||
const full = @typeName(T);
|
const fullTypeName = @typeName(T);
|
||||||
const base = full[std.mem.lastIndexOf(u8, full, ".").? + 1 ..];
|
const last_index = std.mem.lastIndexOf(u8, fullTypeName, ".");
|
||||||
return base ++ "\x00";
|
if (last_index) |idx| {
|
||||||
|
return fullTypeName[idx + 1 .. :0];
|
||||||
|
}
|
||||||
|
return fullTypeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dumpStructType(comptime T: type) void {
|
||||||
|
const info = @typeInfo(T);
|
||||||
|
|
||||||
|
switch (info) {
|
||||||
|
.@"struct" => |s| {
|
||||||
|
std.log.info("struct {{", .{});
|
||||||
|
inline for (s.fields) |field| {
|
||||||
|
std.log.info(" {s}: {s}", .{ field.name, @typeName(field.type) });
|
||||||
|
}
|
||||||
|
std.log.info("}}", .{});
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
std.log.info("{s} is not a struct", .{@typeName(T)});
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,70 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const entity = @import("entity.zig");
|
||||||
|
const zm = @import("zmath");
|
||||||
|
|
||||||
pub const SERVER_PORT: u16 = 1337;
|
pub const SERVER_PORT: u16 = 1337;
|
||||||
|
|
||||||
|
pub const MessageType = enum(u8) {
|
||||||
|
spawn_entity = 1,
|
||||||
|
// later: despawn_entity, update_entity, snapshot, etc.
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SpawnEntity = struct {
|
||||||
|
id: entity.entity_id,
|
||||||
|
kind: EntityKind,
|
||||||
|
payload: []const u8, // serialized entity data
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn write_message(writer: *std.Io.Writer, msg_type: MessageType, payload: []const u8) !void {
|
||||||
|
try writer.writeByte(@intFromEnum(msg_type));
|
||||||
|
try writer.writeInt(u32, @intCast(payload.len), .little);
|
||||||
|
try writer.writeAll(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_message(reader: *std.Io.Reader, allocator: std.mem.Allocator) !struct {
|
||||||
|
msg_type: MessageType,
|
||||||
|
payload: []u8,
|
||||||
|
} {
|
||||||
|
const msg_type = try reader.readByte();
|
||||||
|
const size = try reader.readInt(u32, .little);
|
||||||
|
|
||||||
|
const payload = try allocator.alloc(u8, size);
|
||||||
|
errdefer allocator.free(payload);
|
||||||
|
|
||||||
|
try reader.readNoEof(payload);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.msg_type = @enumFromInt(msg_type),
|
||||||
|
.payload = payload,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const EntityKind = enum(u8) {
|
||||||
|
Player,
|
||||||
|
Monster,
|
||||||
|
Projectile,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Hello = struct {
|
pub const Hello = struct {
|
||||||
msg: []const u8,
|
msg: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn sendHello(writer: *std.io.Writer, hello: Hello) !void {
|
pub fn sendHello(writer: *std.io.Writer, hello: Hello) !void {
|
||||||
try writer.print("{s}\n", .{hello.msg});
|
try writer.print("{s}\n", .{hello.msg});
|
||||||
|
try writer.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recvLine(reader: *std.io.Reader) ![]u8 {
|
fn writeVec4(w: *std.Io.Writer, v: zm.Vec4) !void {
|
||||||
return try reader.takeDelimiterExclusive('\n');
|
const a = zm.vecToArray(v);
|
||||||
|
inline for (a) |f| {
|
||||||
|
try w.writeFloat(f32, f, .little);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readVec4(r: *std.Io.Reader) !zm.Vec4 {
|
||||||
|
var a: [4]f32 = undefined;
|
||||||
|
inline for (&a) |*f| {
|
||||||
|
f.* = try r.readFloat(f32, .little);
|
||||||
|
}
|
||||||
|
return zm.loadArr4(a);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user