Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/network/protocols.zig
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ pub const genericUpdate = struct { // MARK: genericUpdate
biome = 4,
particles = 5,
clear = 6,
setRotation = 7,
};

const WorldEditPosition = enum(u2) {
Expand All @@ -626,6 +627,13 @@ pub const genericUpdate = struct { // MARK: genericUpdate
.teleport => {
game.Player.setPosBlocking(try reader.readVec(Vec3d));
},
.setRotation => {
var rot: Vec3f = try reader.readVec(Vec3f);
const bound = std.math.pi/2.0 - 0.001;
rot[0] = std.math.clamp(rot[0], -bound, bound);
game.camera.rotation[0] = rot[0];
game.camera.rotation[2] = rot[2];
},
.worldEditPos => {
const typ = try reader.readEnum(WorldEditPosition);
const pos: ?Vec3i = switch (typ) {
Expand Down Expand Up @@ -704,7 +712,7 @@ pub const genericUpdate = struct { // MARK: genericUpdate

fn serverReceive(conn: *Connection, reader: *utils.BinaryReader) !void {
switch (try reader.readEnum(UpdateType)) {
.gamemode, .teleport, .time, .biome, .particles, .clear => return error.InvalidSide,
.gamemode, .teleport, .setRotation, .time, .biome, .particles, .clear => return error.InvalidSide,
.worldEditPos => {
const typ = try reader.readEnum(WorldEditPosition);
const pos: ?Vec3i = switch (typ) {
Expand Down Expand Up @@ -737,6 +745,16 @@ pub const genericUpdate = struct { // MARK: genericUpdate
conn.send(.secure, id, writer.data.items);
}

pub fn sendTPRotation(conn: *Connection, rot: Vec3f) void {
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, 20);
defer writer.deinit();

writer.writeEnum(UpdateType, .setRotation);
writer.writeVec(Vec3f, rot);

conn.send(.secure, id, writer.data.items);
}

pub fn sendWorldEditPos(conn: *Connection, posType: WorldEditPosition, maybePos: ?Vec3i) void {
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, 25);
defer writer.deinit();
Expand Down
34 changes: 34 additions & 0 deletions src/server/command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,27 @@ pub const Coordinate = union(enum) {
}
};

pub const Rotation = union(enum) {
relative: f32, // Relative rotations are indicated by leading `~`.
absolute: f32,

pub fn parse(_: NeverFailingAllocator, name: []const u8, arg: []const u8, errorMessage: *ListManaged(u8)) error{ParseError}!Rotation {
const isRelative = arg[0] == '~';
const numberSlice = if (isRelative) arg[1..] else arg;
if (isRelative and numberSlice.len == 0) return .{.relative = 0};
if (isRelative) {
return .{.relative = std.fmt.parseFloat(f32, numberSlice) catch {
errorMessage.print("Expected number for <{s}>, found \"{s}\"", .{name, numberSlice});
return error.ParseError;
}};
}
return .{.absolute = std.fmt.parseFloat(f32, numberSlice) catch {
errorMessage.print("Expected number or \"~\" for <{s}>, found \"{s}\"", .{name, arg});
return error.ParseError;
}};
}
};

pub fn resolveCoordinates(x: Coordinate, y: Coordinate, z: Coordinate, source: Source) error{InvalidArg}!main.vec.Vec3d {
if (source != .user and (x == .relative or y == .relative or z == .relative)) {
source.sendMessage("Command was run without a user; unable to interpret relative coordinates.", .{});
Expand All @@ -121,6 +142,19 @@ pub fn resolveCoordinates(x: Coordinate, y: Coordinate, z: Coordinate, source: S
};
}

pub fn resolveRotation(yaw: Rotation, pitch: Rotation, source: Source) error{InvalidArg}!main.vec.Vec3f {
if (source != .user and (yaw == .relative or pitch == .relative)) {
source.sendMessage("Command was run without a user; unable to interpret relative rotation.", .{});
return error.InvalidArg;
}
const bound = std.math.pi/2.0 - 0.001;
return .{
std.math.clamp(if (yaw == .relative) source.user.player().rot[0] + yaw.relative*std.math.pi/180 else yaw.absolute*std.math.pi/180, -bound, bound),
0,
if (pitch == .relative) source.user.player().rot[2] + @mod(pitch.relative, 360)*std.math.pi/180 else @mod(pitch.absolute, 360)*std.math.pi/180,
};
}

pub const Target = struct {
user: *User,

Expand Down
15 changes: 14 additions & 1 deletion src/server/command/tp.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ pub const Args = union(enum) {
sourcePlayerIndex: command.PlayerIndex,
destinationPlayerIndex: command.PlayerIndex,
},
@"/tp <sourcePlayerIndex> <x> <y> <z> <yaw> <pitch>": struct {
sourcePlayerIndex: ?command.PlayerIndex,
x: command.Coordinate,
y: command.Coordinate,
z: command.Coordinate,
yaw: command.Rotation,
pitch: command.Rotation,
},
};

pub fn execute(args: Args, source: Source) void {
Expand Down Expand Up @@ -99,10 +107,15 @@ pub fn execute(args: Args, source: Source) void {
.@"/tp <sourcePlayerIndex> <x> <y> <z>" => |pos| {
break :blk command.resolveCoordinates(pos.x, pos.y, pos.z, source) catch return;
},
.@"/tp <sourcePlayerIndex> <x> <y> <z> <yaw> <pitch>" => |pos| {
main.sync.server.executeCommand(.{.setRotation = .{.target = target.user.id, .rotation = command.resolveRotation(pos.yaw, pos.pitch, source) catch return}}, source.user);
break :blk command.resolveCoordinates(pos.x, pos.y, pos.z, source) catch return;
},
inline .@"/tp <destinationPlayerIndex>", .@"/tp <sourcePlayerIndex> <destinationPlayerIndex>" => |index| {
const dest = command.Target.fromPlayerIndex(index.destinationPlayerIndex, source) catch return;
break :blk dest.user.player().pos;
},
};
main.network.protocols.genericUpdate.sendTPCoordinates(target.user.conn, pos);

if (!std.meta.eql(target.user.player().pos, pos)) main.network.protocols.genericUpdate.sendTPCoordinates(target.user.conn, pos);
}
73 changes: 72 additions & 1 deletion src/sync.zig
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ pub const Command = struct { // MARK: Command
updateBlock = 9,
addHealth = 10,
chatCommand = 12,
setRotation = 18,
};
pub const Payload = union(PayloadType) {
open: Open,
Expand All @@ -261,6 +262,7 @@ pub const Command = struct { // MARK: Command
updateBlock: UpdateBlock,
addHealth: AddHealth,
chatCommand: ChatCommand,
setRotation: SetRotation,
};

const BaseOperationType = enum(u8) {
Expand All @@ -273,6 +275,7 @@ pub const Command = struct { // MARK: Command
useDurability = 4,
addHealth = 5,
addEnergy = 6,
setRotation = 9,
};

pub const BaseOperation = union(BaseOperationType) {
Expand Down Expand Up @@ -322,6 +325,11 @@ pub const Command = struct { // MARK: Command
energy: f32,
previous: f32,
},
setRotation: struct {
target: ?*main.server.User,
rotation: Vec3f,
previous: Vec3f,
},
};

const SyncOperationType = enum(u8) {
Expand Down Expand Up @@ -618,14 +626,17 @@ pub const Command = struct { // MARK: Command
.addEnergy => |info| {
main.game.Player.super.energy = info.previous;
},
.setRotation => |info| {
main.game.camera.rotation = info.previous;
},
}
}
}

fn finalize(self: Command, allocator: NeverFailingAllocator, side: Side, reader: *BinaryReader) !void {
for (self.baseOperations.items) |step| {
switch (step) {
.move, .swap, .create, .moveToBag, .takeFromBag, .addHealth, .addEnergy => {},
.move, .swap, .create, .moveToBag, .takeFromBag, .addHealth, .addEnergy, .setRotation => {},
.delete => |info| {
info.item.deinit();
},
Expand Down Expand Up @@ -814,6 +825,23 @@ pub const Command = struct { // MARK: Command
main.game.Player.super.energy = std.math.clamp(main.game.Player.super.energy + info.energy, 0, main.game.Player.super.maxEnergy);
}
},
.setRotation => |*info| {
if (side == .server) {
info.previous = info.target.?.player().rot;
std.log.debug("SetRotation executed on server; target=TRUNCATED, rotation={}", .{info.rotation});

info.target.?.player().rot = info.rotation;
self.baseOperations.append(allocator, .{.setRotation = .{
.target = info.target.?,
.rotation = info.rotation,
.previous = info.previous,
}});
} else {
std.log.debug("SetRotation executed on client; target=TRUNCATED, rotation={}", .{info.rotation});
info.previous = main.game.camera.rotation;
main.game.camera.rotation = info.rotation;
}
},
}
self.baseOperations.append(allocator, op);
}
Expand Down Expand Up @@ -1730,6 +1758,49 @@ pub const Command = struct { // MARK: Command
}
};

const SetRotation = struct { // MARK: SetRotation
target: main.entity.Entity,
rotation: Vec3f,

fn run(self: SetRotation, ctx: Context) error{serverFailure}!void {
std.log.debug("SetRotation ran; target={}, rotation={}", .{self.target, self.rotation});
var target: ?*main.server.User = null;

if (ctx.side == .server) {
const userList = main.server.getUserList(main.stackAllocator);
defer main.stackAllocator.free(userList);
for (userList) |user| {
if (user.id == self.target) {
target = user;
break;
}
}

if (target == null) return error.serverFailure;
}

ctx.execute(.{.setRotation = .{
.target = target,
.rotation = self.rotation,
.previous = if (ctx.side == .server) target.?.player().rot else main.game.camera.rotation,
}});
}

fn serialize(self: SetRotation, writer: *BinaryWriter) void {
writer.writeEnum(main.entity.Entity, self.target);
writer.writeVec(Vec3f, self.rotation);
}

fn deserialize(reader: *BinaryReader, _: Side, user: ?*main.server.User) !SetRotation {
const result: SetRotation = .{
.target = try reader.readEnum(main.entity.Entity),
.rotation = try reader.readVec(Vec3f),
};
if (user.?.id != result.target) return error.Invalid;
return result;
}
};

const ChatCommand = struct { // MARK: ChatCommand
message: []const u8,

Expand Down