forked from PixelGuys/Cubyz
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path_command.zig
More file actions
119 lines (106 loc) · 3.89 KB
/
_command.zig
File metadata and controls
119 lines (106 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
const std = @import("std");
const main = @import("main");
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,
permissionPath: []const u8,
};
pub var commands: std.StringHashMap(Command) = undefined;
pub fn init() void {
commands = .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,
.permissionPath = "/command/" ++ decl.name,
}) catch unreachable;
std.log.debug("Registered command: '/{s}'", .{decl.name});
}
}
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| {
if (!source.hasPermission(cmd.permissionPath)) {
source.sendMessage("#ff0000No permission to use Command \"{s}\"", .{command});
return;
}
source.sendMessage("#00ff00Executing Command /{s}", .{msg});
cmd.exec(msg[@min(end + 1, msg.len)..], source);
} else {
source.sendMessage("#ff0000Unrecognized Command \"{s}\"", .{command});
}
}
fn parseAxis(arg: []const u8, playerPos: f64, source: *User) !f64 {
const hasTilde = if (arg.len == 0) false else arg[0] == '~';
const numberSlice = if (hasTilde) arg[1..] else arg;
if (hasTilde and numberSlice.len == 0) return playerPos;
const num = std.fmt.parseFloat(f64, numberSlice) catch {
if (hasTilde) {
source.sendMessage("#ff0000Expected number, found \"{s}\"", .{numberSlice});
} else {
source.sendMessage("#ff0000Expected number or \"~\", found \"{s}\"", .{arg});
}
return error.InvalidNumber;
};
return std.math.clamp(if (hasTilde) playerPos + num else num, -1e9, 1e9); // TODO: Remove clamp after #310 is implemented
}
pub fn parseCoordinates(split: *std.mem.SplitIterator(u8, .scalar), source: *User) !main.vec.Vec3d {
return blk: {
var output: main.vec.Vec3d = undefined;
inline for (0..3) |i| {
output[i] = try parseAxis(split.next() orelse {
source.sendMessage("#ff0000Too few arguments for position", .{});
return error.TooFewArguments;
}, source.player().pos[i], source);
}
break :blk output;
};
}
fn parsePlayerIndexAndIncreaseRefCount(playerIndex: []const u8, source: *User) !*User {
if (!std.ascii.startsWithIgnoreCase(playerIndex, "@")) {
source.sendMessage("#ff0000Player index specifiers always start with @, found \"{s}\"", .{playerIndex});
return error.InvalidArg;
}
const index = std.fmt.parseInt(usize, playerIndex[1..], 10) catch {
source.sendMessage("#ff0000Player index must be an integer, found \"{s}\"", .{playerIndex[1..]});
return error.InvalidArg;
};
return main.server.getUserByIndexAndIncreaseRefCount(index) orelse {
source.sendMessage("#ff0000Player with index {d} not found or not online", .{index});
return error.InvalidArg;
};
}
pub const Target = struct {
user: *User,
increasedRefCount: bool,
pub fn init(split: *std.mem.SplitIterator(u8, .scalar), source: *User) !Target {
var increasedRefCount = false;
const user: *User = blk: {
const userIndex = split.peek() orelse {
source.sendMessage("#ff0000Too few arguments for command", .{});
return error.TooFewArguments;
};
if (userIndex.len > 0 and userIndex[0] == '@') {
const user = parsePlayerIndexAndIncreaseRefCount(userIndex, source) catch return error.InvalidArgs;
increasedRefCount = true;
_ = split.next();
break :blk user;
}
break :blk source;
};
return .{.user = user, .increasedRefCount = increasedRefCount};
}
pub fn deinit(self: Target) void {
if (self.increasedRefCount) self.user.decreaseRefCount();
}
};