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,
|
size: u32 = 0,
|
||||||
|
|
||||||
lastUpdates: ZonElement,
|
|
||||||
|
|
||||||
pub fn init(self: *ItemDropManager, allocator: NeverFailingAllocator, world: ?*ServerWorld, gravity: f64) void {
|
pub fn init(self: *ItemDropManager, allocator: NeverFailingAllocator, world: ?*ServerWorld, gravity: f64) void {
|
||||||
self.* = ItemDropManager {
|
self.* = ItemDropManager {
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.list = std.MultiArrayList(ItemDrop){},
|
.list = std.MultiArrayList(ItemDrop){},
|
||||||
.lastUpdates = ZonElement.initArray(allocator),
|
|
||||||
.isEmpty = .initFull(),
|
.isEmpty = .initFull(),
|
||||||
.changeQueue = .init(allocator, 16),
|
.changeQueue = .init(allocator, 16),
|
||||||
.world = world,
|
.world = world,
|
||||||
@ -87,7 +84,6 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.list.deinit(self.allocator.allocator);
|
self.list.deinit(self.allocator.allocator);
|
||||||
self.lastUpdates.deinit(self.allocator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn loadFrom(self: *ItemDropManager, zon: ZonElement) void {
|
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 {
|
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 list = ZonElement.initArray(allocator);
|
||||||
var ii: u32 = 0;
|
var ii: u32 = 0;
|
||||||
while(ii < self.size) : (ii += 1) {
|
while(ii < self.size) : (ii += 1) {
|
||||||
const i = self.indices[ii];
|
const i = self.indices[ii];
|
||||||
list.array.append(self.storeSingle(self.lastUpdates.array.allocator, i));
|
list.array.append(self.storeSingle(allocator, i));
|
||||||
}
|
}
|
||||||
return list;
|
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 obj = ZonElement.initObject(allocator);
|
||||||
const itemDrop = self.list.get(i);
|
|
||||||
obj.put("i", i);
|
obj.put("i", i);
|
||||||
obj.put("pos", itemDrop.pos);
|
obj.put("pos", itemDrop.pos);
|
||||||
obj.put("vel", itemDrop.vel);
|
obj.put("vel", itemDrop.vel);
|
||||||
@ -156,6 +152,10 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
|||||||
return obj;
|
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 {
|
pub fn store(self: *ItemDropManager, allocator: NeverFailingAllocator) ZonElement {
|
||||||
const zonArray = ZonElement.initArray(allocator);
|
const zonArray = ZonElement.initArray(allocator);
|
||||||
for(self.indices[0..self.size]) |i| {
|
for(self.indices[0..self.size]) |i| {
|
||||||
@ -187,10 +187,7 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
|||||||
pickupCooldown[i] -= 1;
|
pickupCooldown[i] -= 1;
|
||||||
despawnTime[i] -= 1;
|
despawnTime[i] -= 1;
|
||||||
if(despawnTime[i] < 0) {
|
if(despawnTime[i] < 0) {
|
||||||
self.emptyMutex.lock();
|
self.directRemove(i);
|
||||||
self.isEmpty.set(i);
|
|
||||||
self.emptyMutex.unlock();
|
|
||||||
self.internalRemove(i);
|
|
||||||
} else {
|
} else {
|
||||||
ii += 1;
|
ii += 1;
|
||||||
}
|
}
|
||||||
@ -212,8 +209,7 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
|||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
self.isEmpty.unset(i);
|
self.isEmpty.unset(i);
|
||||||
self.emptyMutex.unlock();
|
const drop = ItemDrop {
|
||||||
self.changeQueue.enqueue(.{.add = .{i, .{
|
|
||||||
.pos = pos,
|
.pos = pos,
|
||||||
.vel = vel,
|
.vel = vel,
|
||||||
.rot = rot,
|
.rot = rot,
|
||||||
@ -221,15 +217,32 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
|||||||
.despawnTime = despawnTime,
|
.despawnTime = despawnTime,
|
||||||
.pickupCooldown = pickupCooldown,
|
.pickupCooldown = pickupCooldown,
|
||||||
.reverseIndex = undefined,
|
.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 {
|
fn addWithIndex(self: *ItemDropManager, i: u16, pos: Vec3d, vel: Vec3d, rot: Vec3f, itemStack: ItemStack, despawnTime: i32, pickupCooldown: i32) void {
|
||||||
self.emptyMutex.lock();
|
self.emptyMutex.lock();
|
||||||
std.debug.assert(self.isEmpty.isSet(i));
|
std.debug.assert(self.isEmpty.isSet(i));
|
||||||
self.isEmpty.unset(i);
|
self.isEmpty.unset(i);
|
||||||
self.emptyMutex.unlock();
|
const drop = ItemDrop {
|
||||||
self.changeQueue.enqueue(.{.add = .{i, .{
|
|
||||||
.pos = pos,
|
.pos = pos,
|
||||||
.vel = vel,
|
.vel = vel,
|
||||||
.rot = rot,
|
.rot = rot,
|
||||||
@ -237,7 +250,24 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
|||||||
.despawnTime = despawnTime,
|
.despawnTime = despawnTime,
|
||||||
.pickupCooldown = pickupCooldown,
|
.pickupCooldown = pickupCooldown,
|
||||||
.reverseIndex = undefined,
|
.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 {
|
fn processChanges(self: *ItemDropManager) void {
|
||||||
@ -260,9 +290,6 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
|||||||
}
|
}
|
||||||
drop.reverseIndex = @intCast(self.size);
|
drop.reverseIndex = @intCast(self.size);
|
||||||
self.list.set(i, drop);
|
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.indices[self.size] = i;
|
||||||
self.size += 1;
|
self.size += 1;
|
||||||
}
|
}
|
||||||
@ -273,9 +300,28 @@ pub const ItemDropManager = struct { // MARK: ItemDropManager
|
|||||||
self.list.items(.itemStack)[i].clear();
|
self.list.items(.itemStack)[i].clear();
|
||||||
self.indices[ii] = self.indices[self.size];
|
self.indices[ii] = self.indices[self.size];
|
||||||
self.list.items(.reverseIndex)[self.indices[self.size]] = ii;
|
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 {
|
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];
|
const itemStack = &self.list.items(.itemStack)[i];
|
||||||
main.items.Inventory.Sync.ServerSide.tryCollectingToPlayerInventory(user, itemStack);
|
main.items.Inventory.Sync.ServerSide.tryCollectingToPlayerInventory(user, itemStack);
|
||||||
if(itemStack.amount == 0) {
|
if(itemStack.amount == 0) {
|
||||||
self.emptyMutex.lock();
|
self.directRemove(i);
|
||||||
self.isEmpty.set(i);
|
|
||||||
self.emptyMutex.unlock();
|
|
||||||
self.internalRemove(i);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,44 +296,18 @@ pub fn freeUserListAndDecreaseRefCount(allocator: utils.NeverFailingAllocator, l
|
|||||||
allocator.free(list);
|
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:
|
// 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;
|
var initialList: []const u8 = undefined;
|
||||||
if(getInitialList) {
|
const list = main.ZonElement.initArray(main.stackAllocator);
|
||||||
const list = main.ZonElement.initArray(main.stackAllocator);
|
defer list.deinit(main.stackAllocator);
|
||||||
defer list.deinit(main.stackAllocator);
|
list.array.append(.null);
|
||||||
list.array.append(.null);
|
const itemDropList = world.?.itemDropManager.getInitialList(main.stackAllocator);
|
||||||
const itemDropList = world.?.itemDropManager.getInitialList(main.stackAllocator);
|
list.array.appendSlice(itemDropList.array.items);
|
||||||
list.array.appendSlice(itemDropList.array.items);
|
itemDropList.array.items.len = 0;
|
||||||
itemDropList.array.items.len = 0;
|
itemDropList.deinit(main.stackAllocator);
|
||||||
itemDropList.deinit(main.stackAllocator);
|
initialList = list.toStringEfficient(allocator, &.{});
|
||||||
initialList = list.toStringEfficient(allocator, &.{});
|
return initialList;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update() void { // MARK: update()
|
fn update() void { // MARK: update()
|
||||||
@ -349,9 +323,6 @@ fn update() void { // MARK: update()
|
|||||||
user.update();
|
user.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
sendEntityUpdates(false, main.stackAllocator);
|
|
||||||
|
|
||||||
|
|
||||||
// Send the entity data:
|
// Send the entity data:
|
||||||
const data = main.stackAllocator.alloc(u8, (4 + 24 + 12 + 24)*userList.len);
|
const data = main.stackAllocator.alloc(u8, (4 + 24 + 12 + 24)*userList.len);
|
||||||
defer main.stackAllocator.free(data);
|
defer main.stackAllocator.free(data);
|
||||||
@ -482,7 +453,7 @@ pub fn connectInternal(user: *User) void {
|
|||||||
defer main.stackAllocator.free(data);
|
defer main.stackAllocator.free(data);
|
||||||
if(user.connected.load(.unordered)) main.network.Protocols.entity.send(user.conn, 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.network.Protocols.entity.send(user.conn, initialList);
|
||||||
main.stackAllocator.free(initialList);
|
main.stackAllocator.free(initialList);
|
||||||
const message = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}§#ffff00 joined", .{user.name}) catch unreachable;
|
const message = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}§#ffff00 joined", .{user.name}) catch unreachable;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user