mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 19:28:49 -04:00
Reduce latency of itemdrops by sending item drop updates instantly instead of waiting for the next server tick.
progress towards #868
This commit is contained in:
parent
2202cd01da
commit
850956b0af
@ -62,13 +62,10 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
|
||||
size: u32 = 0,
|
||||
|
||||
lastUpdates: ZonElement,
|
||||
|
||||
pub fn init(self: *ItemDropManager, allocator: NeverFailingAllocator, world: ?*ServerWorld, gravity: f64) void {
|
||||
self.* = ItemDropManager {
|
||||
.allocator = allocator,
|
||||
.list = std.MultiArrayList(ItemDrop){},
|
||||
.lastUpdates = ZonElement.initArray(allocator),
|
||||
.isEmpty = .initFull(),
|
||||
.changeQueue = .init(allocator, 16),
|
||||
.world = world,
|
||||
@ -87,7 +84,6 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
}
|
||||
}
|
||||
self.list.deinit(self.allocator.allocator);
|
||||
self.lastUpdates.deinit(self.allocator);
|
||||
}
|
||||
|
||||
pub fn loadFrom(self: *ItemDropManager, zon: ZonElement) void {
|
||||
@ -136,18 +132,18 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
}
|
||||
|
||||
pub fn getInitialList(self: *ItemDropManager, allocator: NeverFailingAllocator) ZonElement {
|
||||
self.processChanges(); // Make sure all the items from the queue are included.
|
||||
var list = ZonElement.initArray(allocator);
|
||||
var ii: u32 = 0;
|
||||
while(ii < self.size) : (ii += 1) {
|
||||
const i = self.indices[ii];
|
||||
list.array.append(self.storeSingle(self.lastUpdates.array.allocator, i));
|
||||
list.array.append(self.storeSingle(allocator, i));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
fn storeSingle(self: *ItemDropManager, allocator: NeverFailingAllocator, i: u16) ZonElement {
|
||||
fn storeDrop(allocator: NeverFailingAllocator, itemDrop: ItemDrop, i: u16) ZonElement {
|
||||
const obj = ZonElement.initObject(allocator);
|
||||
const itemDrop = self.list.get(i);
|
||||
obj.put("i", i);
|
||||
obj.put("pos", itemDrop.pos);
|
||||
obj.put("vel", itemDrop.vel);
|
||||
@ -156,6 +152,10 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
return obj;
|
||||
}
|
||||
|
||||
fn storeSingle(self: *ItemDropManager, allocator: NeverFailingAllocator, i: u16) ZonElement {
|
||||
return storeDrop(allocator, self.list.get(i), i);
|
||||
}
|
||||
|
||||
pub fn store(self: *ItemDropManager, allocator: NeverFailingAllocator) ZonElement {
|
||||
const zonArray = ZonElement.initArray(allocator);
|
||||
for(self.indices[0..self.size]) |i| {
|
||||
@ -187,10 +187,7 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
pickupCooldown[i] -= 1;
|
||||
despawnTime[i] -= 1;
|
||||
if(despawnTime[i] < 0) {
|
||||
self.emptyMutex.lock();
|
||||
self.isEmpty.set(i);
|
||||
self.emptyMutex.unlock();
|
||||
self.internalRemove(i);
|
||||
self.directRemove(i);
|
||||
} else {
|
||||
ii += 1;
|
||||
}
|
||||
@ -212,8 +209,7 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
return;
|
||||
});
|
||||
self.isEmpty.unset(i);
|
||||
self.emptyMutex.unlock();
|
||||
self.changeQueue.enqueue(.{.add = .{i, .{
|
||||
const drop = ItemDrop {
|
||||
.pos = pos,
|
||||
.vel = vel,
|
||||
.rot = rot,
|
||||
@ -221,15 +217,32 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
.despawnTime = despawnTime,
|
||||
.pickupCooldown = pickupCooldown,
|
||||
.reverseIndex = undefined,
|
||||
}}});
|
||||
};
|
||||
if(self.world != null) {
|
||||
const list = ZonElement.initArray(main.stackAllocator);
|
||||
defer list.deinit(main.stackAllocator);
|
||||
list.array.append(.null);
|
||||
list.array.append(storeDrop(main.stackAllocator, drop, i));
|
||||
const updateData = list.toStringEfficient(main.stackAllocator, &.{});
|
||||
defer main.stackAllocator.free(updateData);
|
||||
|
||||
const userList = main.server.getUserListAndIncreaseRefCount(main.stackAllocator);
|
||||
defer main.server.freeUserListAndDecreaseRefCount(main.stackAllocator, userList);
|
||||
for(userList) |user| {
|
||||
main.network.Protocols.entity.send(user.conn, updateData);
|
||||
}
|
||||
}
|
||||
|
||||
self.emptyMutex.unlock();
|
||||
self.changeQueue.enqueue(.{.add = .{i, drop}});
|
||||
|
||||
}
|
||||
|
||||
fn addWithIndex(self: *ItemDropManager, i: u16, pos: Vec3d, vel: Vec3d, rot: Vec3f, itemStack: ItemStack, despawnTime: i32, pickupCooldown: i32) void {
|
||||
self.emptyMutex.lock();
|
||||
std.debug.assert(self.isEmpty.isSet(i));
|
||||
self.isEmpty.unset(i);
|
||||
self.emptyMutex.unlock();
|
||||
self.changeQueue.enqueue(.{.add = .{i, .{
|
||||
const drop = ItemDrop {
|
||||
.pos = pos,
|
||||
.vel = vel,
|
||||
.rot = rot,
|
||||
@ -237,7 +250,24 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
.despawnTime = despawnTime,
|
||||
.pickupCooldown = pickupCooldown,
|
||||
.reverseIndex = undefined,
|
||||
}}});
|
||||
};
|
||||
if(self.world != null) {
|
||||
const list = ZonElement.initArray(main.stackAllocator);
|
||||
defer list.deinit(main.stackAllocator);
|
||||
list.array.append(.null);
|
||||
list.array.append(storeDrop(main.stackAllocator, drop, i));
|
||||
const updateData = list.toStringEfficient(main.stackAllocator, &.{});
|
||||
defer main.stackAllocator.free(updateData);
|
||||
|
||||
const userList = main.server.getUserListAndIncreaseRefCount(main.stackAllocator);
|
||||
defer main.server.freeUserListAndDecreaseRefCount(main.stackAllocator, userList);
|
||||
for(userList) |user| {
|
||||
main.network.Protocols.entity.send(user.conn, updateData);
|
||||
}
|
||||
}
|
||||
|
||||
self.emptyMutex.unlock();
|
||||
self.changeQueue.enqueue(.{.add = .{i, drop}});
|
||||
}
|
||||
|
||||
fn processChanges(self: *ItemDropManager) void {
|
||||
@ -260,9 +290,6 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
}
|
||||
drop.reverseIndex = @intCast(self.size);
|
||||
self.list.set(i, drop);
|
||||
if(self.world != null) {
|
||||
self.lastUpdates.array.append(self.storeSingle(self.lastUpdates.array.allocator, i));
|
||||
}
|
||||
self.indices[self.size] = i;
|
||||
self.size += 1;
|
||||
}
|
||||
@ -273,9 +300,28 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
self.list.items(.itemStack)[i].clear();
|
||||
self.indices[ii] = self.indices[self.size];
|
||||
self.list.items(.reverseIndex)[self.indices[self.size]] = ii;
|
||||
if(self.world != null) {
|
||||
self.lastUpdates.array.append(.{.int = i});
|
||||
}
|
||||
|
||||
fn directRemove(self: *ItemDropManager, i: u16) void {
|
||||
std.debug.assert(self.world != null);
|
||||
self.emptyMutex.lock();
|
||||
self.isEmpty.set(i);
|
||||
|
||||
const list = ZonElement.initArray(main.stackAllocator);
|
||||
defer list.deinit(main.stackAllocator);
|
||||
list.array.append(.null);
|
||||
list.array.append(.{.int = i});
|
||||
const updateData = list.toStringEfficient(main.stackAllocator, &.{});
|
||||
defer main.stackAllocator.free(updateData);
|
||||
|
||||
const userList = main.server.getUserListAndIncreaseRefCount(main.stackAllocator);
|
||||
defer main.server.freeUserListAndDecreaseRefCount(main.stackAllocator, userList);
|
||||
for(userList) |user| {
|
||||
main.network.Protocols.entity.send(user.conn, updateData);
|
||||
}
|
||||
|
||||
self.emptyMutex.unlock();
|
||||
self.internalRemove(i);
|
||||
}
|
||||
|
||||
fn updateEnt(self: *ItemDropManager, chunk: *ServerChunk, pos: *Vec3d, vel: *Vec3d, deltaTime: f64) void {
|
||||
@ -374,10 +420,7 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
||||
const itemStack = &self.list.items(.itemStack)[i];
|
||||
main.items.Inventory.Sync.ServerSide.tryCollectingToPlayerInventory(user, itemStack);
|
||||
if(itemStack.amount == 0) {
|
||||
self.emptyMutex.lock();
|
||||
self.isEmpty.set(i);
|
||||
self.emptyMutex.unlock();
|
||||
self.internalRemove(i);
|
||||
self.directRemove(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -296,44 +296,18 @@ pub fn freeUserListAndDecreaseRefCount(allocator: utils.NeverFailingAllocator, l
|
||||
allocator.free(list);
|
||||
}
|
||||
|
||||
fn sendEntityUpdates(comptime getInitialList: bool, allocator: utils.NeverFailingAllocator) if(getInitialList) []const u8 else void {
|
||||
fn getInitialEntityList(allocator: utils.NeverFailingAllocator) []const u8 {
|
||||
// Send the entity updates:
|
||||
const updateList = main.ZonElement.initArray(main.stackAllocator);
|
||||
defer updateList.deinit(main.stackAllocator);
|
||||
defer updateList.array.clearAndFree(); // The children are freed in other locations.
|
||||
if(world.?.itemDropManager.lastUpdates.array.items.len != 0) {
|
||||
updateList.array.append(.null);
|
||||
updateList.array.appendSlice(world.?.itemDropManager.lastUpdates.array.items);
|
||||
}
|
||||
if(!getInitialList and updateList.array.items.len == 0) {
|
||||
return;
|
||||
}
|
||||
const updateData = updateList.toStringEfficient(main.stackAllocator, &.{});
|
||||
defer main.stackAllocator.free(updateData);
|
||||
if(world.?.itemDropManager.lastUpdates.array.items.len != 0) {
|
||||
const alloc = world.?.itemDropManager.lastUpdates.array.allocator;
|
||||
world.?.itemDropManager.lastUpdates.deinit(alloc);
|
||||
world.?.itemDropManager.lastUpdates = main.ZonElement.initArray(alloc);
|
||||
}
|
||||
var initialList: []const u8 = undefined;
|
||||
if(getInitialList) {
|
||||
const list = main.ZonElement.initArray(main.stackAllocator);
|
||||
defer list.deinit(main.stackAllocator);
|
||||
list.array.append(.null);
|
||||
const itemDropList = world.?.itemDropManager.getInitialList(main.stackAllocator);
|
||||
list.array.appendSlice(itemDropList.array.items);
|
||||
itemDropList.array.items.len = 0;
|
||||
itemDropList.deinit(main.stackAllocator);
|
||||
initialList = list.toStringEfficient(allocator, &.{});
|
||||
}
|
||||
const userList = getUserListAndIncreaseRefCount(main.stackAllocator);
|
||||
defer freeUserListAndDecreaseRefCount(main.stackAllocator, userList);
|
||||
for(userList) |user| {
|
||||
main.network.Protocols.entity.send(user.conn, updateData);
|
||||
}
|
||||
if(getInitialList) {
|
||||
return initialList;
|
||||
}
|
||||
const list = main.ZonElement.initArray(main.stackAllocator);
|
||||
defer list.deinit(main.stackAllocator);
|
||||
list.array.append(.null);
|
||||
const itemDropList = world.?.itemDropManager.getInitialList(main.stackAllocator);
|
||||
list.array.appendSlice(itemDropList.array.items);
|
||||
itemDropList.array.items.len = 0;
|
||||
itemDropList.deinit(main.stackAllocator);
|
||||
initialList = list.toStringEfficient(allocator, &.{});
|
||||
return initialList;
|
||||
}
|
||||
|
||||
fn update() void { // MARK: update()
|
||||
@ -349,9 +323,6 @@ fn update() void { // MARK: update()
|
||||
user.update();
|
||||
}
|
||||
|
||||
sendEntityUpdates(false, main.stackAllocator);
|
||||
|
||||
|
||||
// Send the entity data:
|
||||
const data = main.stackAllocator.alloc(u8, (4 + 24 + 12 + 24)*userList.len);
|
||||
defer main.stackAllocator.free(data);
|
||||
@ -482,7 +453,7 @@ pub fn connectInternal(user: *User) void {
|
||||
defer main.stackAllocator.free(data);
|
||||
if(user.connected.load(.unordered)) main.network.Protocols.entity.send(user.conn, data);
|
||||
}
|
||||
const initialList = sendEntityUpdates(true, main.stackAllocator);
|
||||
const initialList = getInitialEntityList(main.stackAllocator);
|
||||
main.network.Protocols.entity.send(user.conn, initialList);
|
||||
main.stackAllocator.free(initialList);
|
||||
const message = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}§#ffff00 joined", .{user.name}) catch unreachable;
|
||||
|
Loading…
x
Reference in New Issue
Block a user