Skip to content

Commit

Permalink
fix: Moving zone rework to feature branch, reverted code in this branch
Browse files Browse the repository at this point in the history
  • Loading branch information
Pazaz committed Mar 23, 2024
1 parent f8fb8f0 commit 01b398a
Show file tree
Hide file tree
Showing 8 changed files with 621 additions and 515 deletions.
298 changes: 247 additions & 51 deletions src/lostcity/engine/World.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { PlayerTimerType } from '#lostcity/entity/EntityTimer.js';
import { Position } from '#lostcity/entity/Position.js';

Check warning on line 56 in src/lostcity/engine/World.ts

View workflow job for this annotation

GitHub Actions / build

'Position' is defined but never used
import ZoneManager from './zone/ZoneManager.js';

Check warning on line 57 in src/lostcity/engine/World.ts

View workflow job for this annotation

GitHub Actions / build

'ZoneManager' is defined but never used
import { getLatestModified, getModified } from '#lostcity/util/PackFile.js';
import { ZoneEvent } from './zone/Zone.js';

class World {
id = Environment.WORLD_ID as number;
Expand All @@ -82,6 +83,9 @@ class World {

npcs: (Npc | null)[] = new Array<Npc>(8192);

trackedZones: number[] = [];
zoneBuffers: Map<number, Packet> = new Map();
futureUpdates: Map<number, number[]> = new Map();
queue: {
script: ScriptState;
delay: number;
Expand Down Expand Up @@ -695,31 +699,72 @@ class World {
// - loc/obj despawn/respawn
// - compute shared buffer
let zoneProcessing = Date.now();
const activeZones: Set<number> = new Set();
for (let i = 0; i < this.players.length; i++) {
const player = this.players[i];
if (!player) {
continue;
}
const future = this.futureUpdates.get(this.currentTick);
if (future) {
// despawn dynamic
for (let i = 0; i < future.length; i++) {
const zoneIndex = future[i];
const zone = this.getZoneIndex(zoneIndex);

for (let i = 0; i < zone.locs.length; i++) {
const loc = zone.locs[i];
if (!loc || loc.despawn === -1) {
continue;
}

const centerX = Position.zone(player.x);
const centerZ = Position.zone(player.z);
if (loc.despawn === this.currentTick) {
this.removeLoc(loc, -1);
i--;
}
}

for (let x = centerX - 3; x <= centerX + 3; x++) {
for (let z = centerZ - 3; z <= centerZ + 3; z++) {
activeZones.add(ZoneManager.zoneIndex(x << 3, z << 3, player.level));
for (let i = 0; i < zone.objs.length; i++) {
const obj = zone.objs[i];
if (!obj || obj.despawn === -1) {
continue;
}

if (obj.despawn === this.currentTick) {
this.removeObj(obj, null);
i--;
}
}
}
}

for (const zoneIndex of activeZones) {
const zone = this.getZoneIndex(zoneIndex);
if (!zone) {
continue;
// respawn static
for (let i = 0; i < future.length; i++) {
const zoneIndex = future[i];
const zone = this.getZoneIndex(zoneIndex);

for (let i = 0; i < zone.staticLocs.length; i++) {
const loc = zone.staticLocs[i];
if (!loc || loc.respawn === -1) {
continue;
}

if (loc.respawn === this.currentTick) {
loc.respawn = -1;
this.addLoc(loc, -1);
}
}

for (let i = 0; i < zone.staticObjs.length; i++) {
const obj = zone.staticObjs[i];
if (!obj || obj.respawn === -1) {
continue;
}

if (obj.respawn === this.currentTick) {
obj.respawn = -1;
this.addObj(obj, null, -1);
}
}
}

zone.cycle();
this.futureUpdates.delete(this.currentTick);
}

this.computeSharedEvents();
zoneProcessing = Date.now() - zoneProcessing;

// client output
Expand Down Expand Up @@ -945,7 +990,70 @@ class World {
}

getZoneIndex(zoneIndex: number) {
return this.gameMap.zoneManager.zones.get(zoneIndex);
return this.gameMap.zoneManager.zones.get(zoneIndex)!;
}

computeSharedEvents() {
this.trackedZones = [];
this.zoneBuffers = new Map();

for (let i = 0; i < this.players.length; i++) {
const player = this.players[i];
if (!player) {
continue;
}

// TODO: optimize this
const zones = Object.keys(player.loadedZones);
for (let j = 0; j < zones.length; j++) {
const zoneIndex = parseInt(zones[j]);
if (!this.trackedZones.includes(zoneIndex)) {
this.trackedZones.push(zoneIndex);
}
}
}

for (let i = 0; i < this.trackedZones.length; i++) {
const zoneIndex = this.trackedZones[i];
const zone = this.getZoneIndex(zoneIndex);

const updates = zone.updates;
if (!updates.length) {
continue;
}

zone.updates = updates.filter((event: ZoneEvent): boolean => {
// filter transient updates
if ((event.type === ServerProt.LOC_MERGE || event.type === ServerProt.LOC_ANIM || event.type === ServerProt.MAP_ANIM || event.type === ServerProt.MAP_PROJANIM) && event.tick < this.currentTick) {
return false;
}

return true;
});
}
}

getSharedEvents(zoneIndex: number): Packet | undefined {
return this.zoneBuffers.get(zoneIndex);
}

getUpdates(zoneIndex: number) {
return this.gameMap.zoneManager.zones.get(zoneIndex)!.updates;
}

getReceiverUpdates(zoneIndex: number, receiverId: number) {

Check warning on line 1044 in src/lostcity/engine/World.ts

View workflow job for this annotation

GitHub Actions / build

'receiverId' is defined but never used
const updates = this.getUpdates(zoneIndex);
return updates.filter((event: ZoneEvent): boolean => {
if (event.type !== ServerProt.OBJ_ADD && event.type !== ServerProt.OBJ_DEL && event.type !== ServerProt.OBJ_COUNT && event.type !== ServerProt.OBJ_REVEAL) {
return false;
}

// if (event.type === ServerProt.OBJ_DEL && receiverId !== -1 && event.receiverId !== receiverId) {
// return false;
// }

return true;
});
}

getZonePlayers(x: number, z: number, level: number) {
Expand All @@ -956,48 +1064,57 @@ class World {
return this.getZone(x, z, level).npcs;
}

// todo: rewrite, this is for legacy code compatibility
getZoneLocs(x: number, z: number, level: number): Loc[] {
const zone = this.getZone(x, z, level);
const locs = [];
for (let dx = 0; dx < 8; dx++) {
for (let dz = 0; dz < 8; dz++) {
for (let layer = 0; layer < 4; layer++) {
const loc = zone.getLoc(x + dx, z + dz, layer);
if (loc) {
locs.push(loc);
}
}
}
}
return locs;
}

addNpc(npc: Npc) {
this.npcs[npc.nid] = npc;
npc.x = npc.startX;
npc.z = npc.startZ;

const zone = this.getZone(npc.x, npc.z, npc.level);
zone.enter(npc);

switch (npc.blockWalk) {
case BlockWalk.NPC:
this.collisionManager.changeNpcCollision(npc.width, npc.x, npc.z, npc.level, true);
break;
case BlockWalk.ALL:
this.collisionManager.changeNpcCollision(npc.width, npc.x, npc.z, npc.level, true);
this.collisionManager.changePlayerCollision(npc.width, npc.x, npc.z, npc.level, true);
break;
}

npc.resetEntity(true);
npc.playAnimation(-1, 0);
}

removeNpc(npc: Npc) {
const zone = this.getZone(npc.x, npc.z, npc.level);
zone.leave(npc);
}

getLoc(x: number, z: number, level: number, locId: number): Loc | null {
const zone = this.getZone(x, z, level);
switch (npc.blockWalk) {
case BlockWalk.NPC:
this.collisionManager.changeNpcCollision(npc.width, npc.x, npc.z, npc.level, false);
break;
case BlockWalk.ALL:
this.collisionManager.changeNpcCollision(npc.width, npc.x, npc.z, npc.level, false);
this.collisionManager.changePlayerCollision(npc.width, npc.x, npc.z, npc.level, false);
break;
}

for (let layer = 0; layer < 4; layer++) {
const loc = zone.getLoc(x, z, layer);
if (loc && loc.type === locId) {
return loc;
}
if (!npc.static) {
this.npcs[npc.nid] = null;
} else {
const type = NpcType.get(npc.type);
npc.despawn = this.currentTick;
npc.respawn = this.currentTick + type.respawnrate;
}
}

return null;
getLoc(x: number, z: number, level: number, locId: number) {
return this.getZone(x, z, level).getLoc(x, z, locId);
}

getZoneLocs(x: number, z: number, level: number) {
return [...this.getZone(x, z, level).staticLocs.filter(l => l.respawn < this.currentTick), ...this.getZone(x, z, level).locs];
}

getObj(x: number, z: number, level: number, objId: number) {
Expand All @@ -1006,27 +1123,106 @@ class World {

addLoc(loc: Loc, duration: number) {
const zone = this.getZone(loc.x, loc.z, loc.level);
zone.addLoc(loc.x, loc.z, loc.type, loc.shape, loc.angle, duration);
}
zone.addLoc(loc, duration);

changeLoc(loc: Loc, duration: number) {
const zone = this.getZone(loc.x, loc.z, loc.level);
zone.changeLoc(loc.x, loc.z, loc.type, loc.shape, loc.angle, duration);
const type = LocType.get(loc.type);
if (type.blockwalk) {
this.collisionManager.changeLocCollision(loc.shape, loc.angle, type.blockrange, type.length, type.width, type.active, loc.x, loc.z, loc.level, true);
}

loc.despawn = this.currentTick + duration;
loc.respawn = -1;
if (duration !== -1) {
const endTick = this.currentTick + duration;
let future = this.futureUpdates.get(endTick);
if (!future) {
future = [];
}

if (!future.includes(zone.index)) {
future.push(zone.index);
}

this.futureUpdates.set(endTick, future);
}
}

removeLoc(loc: Loc, duration: number) {
const zone = this.getZone(loc.x, loc.z, loc.level);
zone.removeLoc(loc.x, loc.z, loc.shape, duration);
zone.removeLoc(loc, duration);

const type = LocType.get(loc.type);
if (type.blockwalk) {
this.collisionManager.changeLocCollision(loc.shape, loc.angle, type.blockrange, type.length, type.width, type.active, loc.x, loc.z, loc.level, false);
}

loc.despawn = -1;
loc.respawn = this.currentTick + duration;
if (duration !== -1) {
const endTick = this.currentTick + duration;
let future = this.futureUpdates.get(endTick);
if (!future) {
future = [];
}

if (!future.includes(zone.index)) {
future.push(zone.index);
}

this.futureUpdates.set(endTick, future);
}
}

addObj(obj: Obj, receiver: Player | null, duration: number) {
const zone = this.getZone(obj.x, obj.z, obj.level);
const existing = this.getObj(obj.x, obj.z, obj.level, obj.id);
if (existing && existing.id == obj.id) {
const type = ObjType.get(obj.type);
const nextCount = obj.count + existing.count;
if (type.stackable && nextCount <= Inventory.STACK_LIMIT) {
// if an obj of the same type exists and is stackable, then we merge them.
obj.count = nextCount;
zone.removeObj(existing, receiver);
}
}
zone.addObj(obj, receiver, duration);

obj.despawn = this.currentTick + duration;
obj.respawn = -1;
if (duration !== -1) {
const endTick = this.currentTick + duration;
let future = this.futureUpdates.get(endTick);
if (!future) {
future = [];
}

if (!future.includes(zone.index)) {
future.push(zone.index);
}

this.futureUpdates.set(endTick, future);
}
}

removeObj(obj: Obj, receiver: Player | null) {
// TODO
// stackable objs when they overflow are created into another slot on the floor
// currently when you pickup from a tile with multiple stackable objs
// you will pickup one of them and the other one disappears
const zone = this.getZone(obj.x, obj.z, obj.level);
zone.removeObj(obj, receiver);
zone.removeObj(obj, receiver, -1);
obj.despawn = this.currentTick;
obj.respawn = this.currentTick + ObjType.get(obj.type).respawnrate;
if (zone.staticObjs.includes(obj)) {
let future = this.futureUpdates.get(obj.respawn);
if (!future) {
future = [];
}
if (!future.includes(zone.index)) {
future.push(zone.index);
}
this.futureUpdates.set(obj.respawn, future);
}
}

// ----
Expand Down
11 changes: 10 additions & 1 deletion src/lostcity/engine/collision/CollisionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,16 @@ export default class CollisionManager {
continue;
}

zoneManager.getZone(absoluteX, absoluteZ, adjustedLevel).addStaticLoc(absoluteX, absoluteZ, id, shape, angle);
const type = LocType.get(id);
const width = type.width;
const length = type.length;

const loc = new Loc(adjustedLevel, absoluteX, absoluteZ, width, length, id, shape, angle);
zoneManager.getZone(absoluteX, absoluteZ, adjustedLevel).addStaticLoc(loc);

if (type.blockwalk) {
this.changeLocCollision(shape, angle, type.blockrange, length, width, type.active, absoluteX, absoluteZ, adjustedLevel, true);
}
}
}

Expand Down
Loading

0 comments on commit 01b398a

Please sign in to comment.