mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-09-09 03:59:53 -04:00
Merge d5093c88bba72bfa46dbefa8b85997632b4a1878 into 2dc2a6e79018221d5aab44e09be242d9dab3ddf2
This commit is contained in:
commit
46ced50441
@ -6,6 +6,7 @@ const assets = @import("assets.zig");
|
|||||||
const Block = @import("blocks.zig").Block;
|
const Block = @import("blocks.zig").Block;
|
||||||
const chunk = @import("chunk.zig");
|
const chunk = @import("chunk.zig");
|
||||||
const entity = @import("entity.zig");
|
const entity = @import("entity.zig");
|
||||||
|
const particles = @import("particles.zig");
|
||||||
const items = @import("items.zig");
|
const items = @import("items.zig");
|
||||||
const Inventory = items.Inventory;
|
const Inventory = items.Inventory;
|
||||||
const ItemStack = items.ItemStack;
|
const ItemStack = items.ItemStack;
|
||||||
@ -1018,6 +1019,7 @@ pub const Protocols = struct {
|
|||||||
worldEditPos = 2,
|
worldEditPos = 2,
|
||||||
time = 3,
|
time = 3,
|
||||||
biome = 4,
|
biome = 4,
|
||||||
|
particle = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
const WorldEditPosition = enum(u2) {
|
const WorldEditPosition = enum(u2) {
|
||||||
@ -1090,6 +1092,20 @@ pub const Protocols = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.particle => {
|
||||||
|
if(conn.manager.world) |_| {
|
||||||
|
const particleId = particles.ParticleManager.getIdByTypeIndex(try reader.readInt(u16));
|
||||||
|
const pos = try reader.readVec(Vec3d);
|
||||||
|
const collides = try reader.readInt(u8) == 1;
|
||||||
|
const count = try reader.readInt(u32);
|
||||||
|
|
||||||
|
const emitter: particles.Emitter = .init(particleId, collides);
|
||||||
|
emitter.spawnParticles(count, particles.Emitter.SpawnPoint, .{
|
||||||
|
.mode = .spread,
|
||||||
|
.position = pos,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,6 +1146,19 @@ pub const Protocols = struct {
|
|||||||
conn.send(.fast, id, writer.data.items);
|
conn.send(.fast, id, writer.data.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sendParticle(conn: *Connection, particleId: u16, pos: Vec3d, collides: bool, count: u32) void {
|
||||||
|
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, 32);
|
||||||
|
defer writer.deinit();
|
||||||
|
|
||||||
|
writer.writeEnum(UpdateType, .particle);
|
||||||
|
writer.writeInt(u16, particleId);
|
||||||
|
writer.writeVec(Vec3d, pos);
|
||||||
|
writer.writeInt(u8, if(collides) 1 else 0);
|
||||||
|
writer.writeInt(u32, count);
|
||||||
|
|
||||||
|
conn.send(.fast, id, writer.data.items);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sendTime(conn: *Connection, world: *const main.server.ServerWorld) void {
|
pub fn sendTime(conn: *Connection, world: *const main.server.ServerWorld) void {
|
||||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, 13);
|
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, 13);
|
||||||
defer writer.deinit();
|
defer writer.deinit();
|
||||||
|
@ -35,6 +35,7 @@ pub const ParticleManager = struct {
|
|||||||
|
|
||||||
const ParticleIndex = u16;
|
const ParticleIndex = u16;
|
||||||
var particleTypeHashmap: std.StringHashMapUnmanaged(ParticleIndex) = .{};
|
var particleTypeHashmap: std.StringHashMapUnmanaged(ParticleIndex) = .{};
|
||||||
|
var typeIds: main.List([]const u8) = undefined;
|
||||||
|
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
types = .init(arenaAllocator);
|
types = .init(arenaAllocator);
|
||||||
@ -42,6 +43,7 @@ pub const ParticleManager = struct {
|
|||||||
emissionTextures = .init(arenaAllocator);
|
emissionTextures = .init(arenaAllocator);
|
||||||
textureArray = .init();
|
textureArray = .init();
|
||||||
emissionTextureArray = .init();
|
emissionTextureArray = .init();
|
||||||
|
typeIds = .init(arenaAllocator);
|
||||||
particleTypesSSBO = SSBO.init();
|
particleTypesSSBO = SSBO.init();
|
||||||
ParticleSystem.init();
|
ParticleSystem.init();
|
||||||
}
|
}
|
||||||
@ -52,6 +54,7 @@ pub const ParticleManager = struct {
|
|||||||
emissionTextures.deinit();
|
emissionTextures.deinit();
|
||||||
textureArray.deinit();
|
textureArray.deinit();
|
||||||
emissionTextureArray.deinit();
|
emissionTextureArray.deinit();
|
||||||
|
typeIds.deinit();
|
||||||
particleTypeHashmap.deinit(arenaAllocator.allocator);
|
particleTypeHashmap.deinit(arenaAllocator.allocator);
|
||||||
ParticleSystem.deinit();
|
ParticleSystem.deinit();
|
||||||
particleTypesSSBO.deinit();
|
particleTypesSSBO.deinit();
|
||||||
@ -67,6 +70,7 @@ pub const ParticleManager = struct {
|
|||||||
const particleType = readTextureDataAndParticleType(assetsFolder, textureId);
|
const particleType = readTextureDataAndParticleType(assetsFolder, textureId);
|
||||||
|
|
||||||
particleTypeHashmap.put(arenaAllocator.allocator, id, @intCast(types.items.len)) catch unreachable;
|
particleTypeHashmap.put(arenaAllocator.allocator, id, @intCast(types.items.len)) catch unreachable;
|
||||||
|
typeIds.append(id);
|
||||||
types.append(particleType);
|
types.append(particleType);
|
||||||
|
|
||||||
std.log.debug("Registered particle type: {s}", .{id});
|
std.log.debug("Registered particle type: {s}", .{id});
|
||||||
@ -147,6 +151,16 @@ pub const ParticleManager = struct {
|
|||||||
particleTypesSSBO.bufferData(ParticleType, ParticleManager.types.items);
|
particleTypesSSBO.bufferData(ParticleType, ParticleManager.types.items);
|
||||||
particleTypesSSBO.bind(14);
|
particleTypesSSBO.bind(14);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getTypeIndexById(id: []const u8) ?ParticleIndex {
|
||||||
|
return particleTypeHashmap.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getIdByTypeIndex(index: ParticleIndex) []const u8 {
|
||||||
|
std.debug.assert(index < typeIds.items.len);
|
||||||
|
|
||||||
|
return typeIds.items[index];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ParticleSystem = struct {
|
pub const ParticleSystem = struct {
|
||||||
|
@ -3,6 +3,7 @@ pub const gamemode = @import("gamemode.zig");
|
|||||||
pub const help = @import("help.zig");
|
pub const help = @import("help.zig");
|
||||||
pub const invite = @import("invite.zig");
|
pub const invite = @import("invite.zig");
|
||||||
pub const kill = @import("kill.zig");
|
pub const kill = @import("kill.zig");
|
||||||
|
pub const particle = @import("particle.zig");
|
||||||
pub const time = @import("time.zig");
|
pub const time = @import("time.zig");
|
||||||
pub const tp = @import("tp.zig");
|
pub const tp = @import("tp.zig");
|
||||||
|
|
||||||
|
90
src/server/command/particle.zig
Normal file
90
src/server/command/particle.zig
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const main = @import("main");
|
||||||
|
const particles = main.particles;
|
||||||
|
const User = main.server.User;
|
||||||
|
|
||||||
|
pub const description = "Spawns particles.";
|
||||||
|
pub const usage =
|
||||||
|
\\/particle <id> <x> <y> <z>
|
||||||
|
\\/particle <id> <x> <y> <z> <collides>
|
||||||
|
\\/particle <id> <x> <y> <z> <collides> <count>
|
||||||
|
;
|
||||||
|
|
||||||
|
pub fn execute(args: []const u8, source: *User) void {
|
||||||
|
const particleId, const x, const y, const z, const collides, const particleCount = parseArguments(source, args) catch |err| {
|
||||||
|
switch(err) {
|
||||||
|
error.TooFewArguments => source.sendMessage("#ff0000Too few arguments for command /particle", .{}),
|
||||||
|
error.TooManyArguments => source.sendMessage("#ff0000Too many arguments for command /particle", .{}),
|
||||||
|
error.InvalidParticleId => source.sendMessage("#ff0000Invalid particle id", .{}),
|
||||||
|
error.InvalidBoolean => source.sendMessage("#ff0000Invalid argument. Expected \"true\" or \"false\"", .{}),
|
||||||
|
error.InvalidNumber => return,
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
const users = main.server.getUserListAndIncreaseRefCount(main.stackAllocator);
|
||||||
|
defer main.server.freeUserListAndDecreaseRefCount(main.stackAllocator, users);
|
||||||
|
for(users) |user| {
|
||||||
|
main.network.Protocols.genericUpdate.sendParticle(user.conn, particleId, .{x, y, z}, collides, particleCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const CommandError = error{
|
||||||
|
TooManyArguments,
|
||||||
|
TooFewArguments,
|
||||||
|
InvalidBoolean,
|
||||||
|
InvalidNumber,
|
||||||
|
InvalidParticleId,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn parseArguments(source: *User, args: []const u8) CommandError!struct {u16, f64, f64, f64, bool, u32} {
|
||||||
|
var split = std.mem.splitScalar(u8, args, ' ');
|
||||||
|
const particleId = split.next() orelse return error.TooFewArguments;
|
||||||
|
const indexId = particles.ParticleManager.getTypeIndexById(particleId) orelse return error.InvalidParticleId;
|
||||||
|
|
||||||
|
const x = try parsePosition(split.next() orelse return error.TooFewArguments, source.player.pos[0], source);
|
||||||
|
const y = try parsePosition(split.next() orelse return error.TooFewArguments, source.player.pos[1], source);
|
||||||
|
const z = try parsePosition(split.next() orelse return error.TooFewArguments, source.player.pos[2], source);
|
||||||
|
const collides = try parseBool(split.next() orelse "false");
|
||||||
|
const particleCount = try parseNumber(split.next() orelse "1", source);
|
||||||
|
if(split.next() != null) return error.TooManyArguments;
|
||||||
|
|
||||||
|
return .{indexId, x, y, z, collides, particleCount};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parsePosition(arg: []const u8, playerPos: f64, source: *User) CommandError!f64 {
|
||||||
|
const hasTilde = if(arg.len == 0) false else arg[0] == '~';
|
||||||
|
const numberSlice = if(hasTilde) arg[1..] else arg;
|
||||||
|
const num: f64 = std.fmt.parseFloat(f64, numberSlice) catch ret: {
|
||||||
|
if(arg.len > 1 or arg.len == 0) {
|
||||||
|
source.sendMessage("#ff0000Expected number, found \"{s}\"", .{arg});
|
||||||
|
return error.InvalidNumber;
|
||||||
|
}
|
||||||
|
break :ret 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
return if(hasTilde) playerPos + num else num;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseBool(arg: []const u8) CommandError!bool {
|
||||||
|
if(std.mem.eql(u8, arg, "true")) {
|
||||||
|
return true;
|
||||||
|
} else if(std.mem.eql(u8, arg, "false")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error.InvalidBoolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseNumber(arg: []const u8, source: *User) CommandError!u32 {
|
||||||
|
return std.fmt.parseUnsigned(u32, arg, 0) catch |err| {
|
||||||
|
switch(err) {
|
||||||
|
error.Overflow => return std.math.maxInt(u32),
|
||||||
|
error.InvalidCharacter => {
|
||||||
|
source.sendMessage("#ff0000Expected number, found \"{s}\"", .{arg});
|
||||||
|
return error.InvalidNumber;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user