Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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
36 changes: 34 additions & 2 deletions src/gui/windows/manage_players.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,30 @@ pub var window = GuiWindow{
const padding: f32 = 8;
var userList: []*main.server.User = &.{};

pub var needsUpdate: bool = false;

fn kick(conn: *main.network.Connection) void {
conn.disconnect();
}

fn ipBan(conn: *main.network.Connection) void {
const ip = conn.remoteAddress.ip;
main.server.settings.?.ipBanList.append(ip);
conn.disconnect();
needsUpdate = true;
}

// u32 in a pointer costume
fn unBan(ip_: usize) void {
var bannedIps = &main.server.settings.?.ipBanList;
const ip: u32 = @intCast(ip_);
const removed = bannedIps.swapRemove(std.mem.indexOfScalar(u32, bannedIps.items, ip).?);
std.debug.assert(removed == ip);
needsUpdate = true;
}

pub fn onOpen() void {
const list = VerticalList.init(.{padding, 16 + padding}, 300, 16);
const list = VerticalList.init(.{padding, 16 + padding}, 400, 16);
{
main.server.connectionManager.mutex.lock();
defer main.server.connectionManager.mutex.unlock();
Expand All @@ -46,8 +64,21 @@ pub fn onOpen() void {
row.add(Label.init(.{0, 0}, 200, ip, .left));
row.add(Button.initText(.{0, 0}, 100, "Cancel", .{.callback = @ptrCast(&kick), .arg = @intFromPtr(connection)}));
}
row.add(Button.initText(.{0, 0}, 100, "Ip Ban", .{.callback = @ptrCast(&ipBan), .arg = @intFromPtr(connection)}));
list.add(row);
}
const bannedIps = main.server.settings.?.ipBanList.items;
if(bannedIps.len > 0) {
list.add(Label.init(.{0, 0}, 200, "Banned IPs", .left));
for(bannedIps) |ip| {
const ipText = std.fmt.allocPrint(main.stackAllocator.allocator, "{}.{}.{}.{}", .{ip & 255, ip >> 8 & 255, ip >> 16 & 255, ip >> 24}) catch unreachable;
defer main.stackAllocator.free(ipText);
const row = HorizontalList.init();
row.add(Label.init(.{0, 0}, 200, ipText, .left));
row.add(Button.initText(.{0, 0}, 100, "Unban", .{.callback = @ptrCast(&unBan), .arg = @intCast(ip)}));
list.add(row);
}
}
}
list.finish(.center);
window.rootComponent = list.toComponent();
Expand All @@ -70,7 +101,8 @@ pub fn update() void {
main.server.connectionManager.mutex.lock();
const serverListLen = main.server.connectionManager.connections.items.len;
main.server.connectionManager.mutex.unlock();
if(userList.len != serverListLen) {
if(needsUpdate or userList.len != serverListLen) {
needsUpdate = false;
onClose();
onOpen();
}
Expand Down
3 changes: 3 additions & 0 deletions src/network.zig
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,9 @@ pub const ConnectionManager = struct { // MARK: ConnectionManager
}
if(self.allowNewConnections.load(.monotonic) or source.ip == Address.localHost) {
if(data.len != 0 and data[0] == @intFromEnum(Connection.ChannelId.init)) {
if(std.mem.containsAtLeastScalar(u32, main.server.settings.?.ipBanList.items, 1, source.ip)) {
return;
}
const ip = std.fmt.allocPrint(main.stackAllocator.allocator, "{f}", .{source}) catch unreachable;
defer main.stackAllocator.free(ip);
const user = main.server.User.initAndIncreaseRefCount(main.server.connectionManager, ip) catch |err| {
Expand Down
62 changes: 54 additions & 8 deletions src/server/server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const Blueprint = main.blueprint.Blueprint;
const Mask = main.blueprint.Mask;
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
const CircularBufferQueue = main.utils.CircularBufferQueue;
const ZonElement = main.ZonElement;

pub const world_zig = @import("world.zig");
pub const ServerWorld = world_zig.ServerWorld;
Expand Down Expand Up @@ -287,10 +288,41 @@ pub const User = struct { // MARK: User
}
};

pub const Settings = struct {
ipBanList: main.List(u32),

fn toZon(self: @This()) ZonElement {
const data = ZonElement.initObject(main.stackAllocator);
const arr = ZonElement.initArray(main.stackAllocator);
for(self.ipBanList.items) |ip| {
arr.append(ip);
}
data.put("ipBanList", arr);
return data;
}

fn fromZon(allocator: NeverFailingAllocator, zon: ZonElement) @This() {
const arrayZon = zon.getChild("ipBanList").toSlice();
var self: @This() = .{
.ipBanList = .initCapacity(allocator, arrayZon.len),
};
for(arrayZon) |elem| {
self.ipBanList.append(elem.as(u32, 0));
}
return self;
}

fn deinit(self: *@This()) void {
self.ipBanList.deinit();
self.* = undefined;
}
};

pub const updatesPerSec: u32 = 20;
const updateNanoTime: u32 = 1000000000/20;

pub var world: ?*ServerWorld = null;
pub var settings: ?Settings = null;
var userMutex: std.Thread.Mutex = .{};
var users: main.List(*User) = undefined;
var userDeinitList: main.utils.ConcurrentQueue(*User) = undefined;
Expand All @@ -306,6 +338,7 @@ pub var thread: ?std.Thread = null;
fn init(name: []const u8, singlePlayerPort: ?u16) void { // MARK: init()
main.heap.allocators.createWorldArena();
std.debug.assert(world == null); // There can only be one world.
std.debug.assert(settings == null);
command.init();
users = .init(main.globalAllocator);
userDeinitList = .init(main.globalAllocator, 16);
Expand All @@ -322,6 +355,12 @@ fn init(name: []const u8, singlePlayerPort: ?u16) void { // MARK: init()
std.log.err("Failed to create world: {s}", .{@errorName(err)});
@panic("Can't create world.");
};

const settingsZon = world.?.wio.dir.readToZon(main.stackAllocator, "server.zig.zon") catch .null;
defer settingsZon.deinit(main.stackAllocator);

settings = Settings.fromZon(main.stackAllocator, settingsZon);

world.?.generate() catch |err| {
std.log.err("Failed to generate world: {s}", .{@errorName(err)});
@panic("Can't generate world.");
Expand Down Expand Up @@ -351,10 +390,17 @@ fn deinit() void {
connectionManager.deinit();
connectionManager = undefined;

if(world) |_world| {
_world.deinit();
if(world) |world_| {
const zon = settings.?.toZon();
defer zon.deinit(main.stackAllocator);
settings.?.deinit();
world_.wio.dir.writeZon("server.zig.zon", zon) catch |err| {
std.log.err("Error while saving the server settings: {s}", .{@errorName(err)});
};
world_.deinit();
}
world = null;
settings = null;

main.items.Inventory.Sync.ServerSide.deinit();

Expand Down Expand Up @@ -382,7 +428,7 @@ pub fn freeUserListAndDecreaseRefCount(allocator: main.heap.NeverFailingAllocato
fn getInitialEntityList(allocator: main.heap.NeverFailingAllocator) []const u8 {
// Send the entity updates:
var initialList: []const u8 = undefined;
const list = main.ZonElement.initArray(main.stackAllocator);
const list = ZonElement.initArray(main.stackAllocator);
defer list.deinit(main.stackAllocator);
list.array.append(.null);
const itemDropList = world.?.itemDropManager.getInitialList(main.stackAllocator);
Expand Down Expand Up @@ -490,7 +536,7 @@ pub fn removePlayer(user: *User) void { // MARK: removePlayer()

sendMessage("{s}§#ffff00 left", .{user.name});
// Let the other clients know about that this new one left.
const zonArray = main.ZonElement.initArray(main.stackAllocator);
const zonArray = ZonElement.initArray(main.stackAllocator);
defer zonArray.deinit(main.stackAllocator);
zonArray.array.append(.{.int = user.id});
const data = zonArray.toStringEfficient(main.stackAllocator, &.{});
Expand Down Expand Up @@ -521,9 +567,9 @@ pub fn connectInternal(user: *User) void {
}
// Let the other clients know about this new one.
{
const zonArray = main.ZonElement.initArray(main.stackAllocator);
const zonArray = ZonElement.initArray(main.stackAllocator);
defer zonArray.deinit(main.stackAllocator);
const entityZon = main.ZonElement.initObject(main.stackAllocator);
const entityZon = ZonElement.initObject(main.stackAllocator);
entityZon.put("id", user.id);
entityZon.put("name", user.name);
zonArray.array.append(entityZon);
Expand All @@ -534,10 +580,10 @@ pub fn connectInternal(user: *User) void {
}
}
{ // Let this client know about the others:
const zonArray = main.ZonElement.initArray(main.stackAllocator);
const zonArray = ZonElement.initArray(main.stackAllocator);
defer zonArray.deinit(main.stackAllocator);
for(userList) |other| {
const entityZon = main.ZonElement.initObject(main.stackAllocator);
const entityZon = ZonElement.initObject(main.stackAllocator);
entityZon.put("id", other.id);
entityZon.put("name", other.name);
zonArray.array.append(entityZon);
Expand Down