Skip to content

Commit

Permalink
Add the Command system with a simple help command.
Browse files Browse the repository at this point in the history
Progress towards #327
  • Loading branch information
IntegratedQuantum committed May 28, 2024
1 parent 36be82b commit e084709
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 11 deletions.
11 changes: 1 addition & 10 deletions src/network.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1140,16 +1140,7 @@ pub const Protocols = struct {
pub const asynchronous = false;
fn receive(conn: *Connection, data: []const u8) !void {
if(conn.user) |user| {
if(data[0] == '/') {
// TODO:
// CommandExecutor.execute(data, user);
} else {
const newMessage = std.fmt.allocPrint(main.stackAllocator.allocator, "[{s}#ffffff]{s}", .{user.name, data}) catch unreachable;
defer main.stackAllocator.free(newMessage);
main.server.mutex.lock();
defer main.server.mutex.unlock();
main.server.sendMessage(newMessage);
}
main.server.messageFrom(data, user);
} else {
main.gui.windowlist.chat.addMessage(data);
}
Expand Down
42 changes: 42 additions & 0 deletions src/server/command/_command.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const std = @import("std");

const main = @import("root");
const User = main.server.User;

pub const Command = struct {
exec: *const fn(args: []const u8, source: *User) void,
name: []const u8,
description: []const u8,
usage: []const u8,
};

pub var commands: std.StringHashMap(Command) = undefined;

pub fn init() void {
commands = std.StringHashMap(Command).init(main.globalAllocator.allocator);
const commandList = @import("_list.zig");
inline for(@typeInfo(commandList).Struct.decls) |decl| {
commands.put(decl.name, .{
.name = decl.name,
.description = @field(commandList, decl.name).description,
.usage = @field(commandList, decl.name).usage,
.exec = &@field(commandList, decl.name).execute,
}) catch unreachable;
}
}

pub fn deinit() void {
commands.deinit();
}

pub fn execute(msg: []const u8, source: *User) void {
const end = std.mem.indexOfScalar(u8, msg, ' ') orelse msg.len;
const command = msg[0..end];
if(commands.get(command)) |cmd| {
cmd.exec(msg[@min(end + 1, msg.len)..], source);
} else {
const result = std.fmt.allocPrint(main.stackAllocator.allocator, "#ff0000Unrecognized Command \"{s}\"", .{command}) catch unreachable;
defer main.stackAllocator.free(result);
source.sendMessage(result);
}
}
3 changes: 3 additions & 0 deletions src/server/command/_list.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@


pub const help = @import("help.zig");
42 changes: 42 additions & 0 deletions src/server/command/help.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const std = @import("std");

const main = @import("root");
const User = main.server.User;

const command = @import("_command.zig");

pub const description = "Shows info about all the commands.";
pub const usage = "/help\n/help <command>";

pub fn execute(args: []const u8, source: *User) void {
var msg = main.List(u8).init(main.stackAllocator);
defer msg.deinit();
msg.appendSlice("#ffff00");
if(args.len == 0) {
var iterator = command.commands.valueIterator();
while(iterator.next()) |cmd| {
msg.appendSlice(cmd.name);
msg.appendSlice(": ");
msg.appendSlice(cmd.description);
msg.append('\n');
}
} else {
var split = std.mem.splitScalar(u8, args, ' ');
while(split.next()) |arg| {
if(command.commands.get(arg)) |cmd| {
msg.appendSlice(cmd.name);
msg.appendSlice(": ");
msg.appendSlice(cmd.description);
msg.append('\n');
msg.appendSlice(cmd.usage);
msg.append('\n');
} else {
msg.appendSlice("#ff0000Unrecognized Command \"");
msg.appendSlice(arg);
msg.appendSlice("\"#ffff00\n");
}
}
}
if(msg.items[msg.items.len - 1] == '\n') _ = msg.pop();
source.sendMessage(msg.items);
}
23 changes: 22 additions & 1 deletion src/server/server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub const terrain = @import("terrain/terrain.zig");
pub const Entity = @import("Entity.zig");
pub const storage = @import("storage.zig");

const command = @import("command/_command.zig");


pub const User = struct {
conn: *Connection = undefined,
Expand Down Expand Up @@ -99,6 +101,10 @@ pub const User = struct {
self.timeDifference.addDataPoint(time);
self.interpolation.updatePosition(&position, &velocity, time);
}

pub fn sendMessage(user: *User, msg: []const u8) void {
main.network.Protocols.chat.send(user.conn, msg);
}
};

pub const updatesPerSec: u32 = 20;
Expand All @@ -119,6 +125,7 @@ pub var thread: ?std.Thread = null;

fn init(name: []const u8) void {
std.debug.assert(world == null); // There can only be one world.
command.init();
users = main.List(*User).init(main.globalAllocator);
userDeinitList = main.List(*User).init(main.globalAllocator);
lastTime = std.time.nanoTimestamp();
Expand Down Expand Up @@ -158,6 +165,7 @@ fn deinit() void {
_world.deinit();
}
world = null;
command.deinit();
}

fn update() void {
Expand Down Expand Up @@ -298,10 +306,23 @@ pub fn connect(user: *User) void {
users.append(user);
}

pub fn messageFrom(msg: []const u8, source: *User) void {
if(msg[0] == '/') { // Command.
std.log.info("User \"{s}\" executed command \"{s}\"", .{source.name, msg}); // TODO use color \033[0;32m
command.execute(msg[1..], source);
} else {
const newMessage = std.fmt.allocPrint(main.stackAllocator.allocator, "[{s}#ffffff]{s}", .{source.name, msg}) catch unreachable;
defer main.stackAllocator.free(newMessage);
main.server.mutex.lock();
defer main.server.mutex.unlock();
main.server.sendMessage(newMessage);
}
}

pub fn sendMessage(msg: []const u8) void {
main.utils.assertLocked(&mutex);
std.log.info("Chat: {s}", .{msg}); // TODO use color \033[0;32m
for(users.items) |user| {
main.network.Protocols.chat.send(user.conn, msg);
user.sendMessage(msg);
}
}

0 comments on commit e084709

Please sign in to comment.