From 33f1ea94d19572edc71b791223499621413fcb16 Mon Sep 17 00:00:00 2001 From: Player Name Date: Tue, 28 Jul 2026 20:07:12 +0200 Subject: [PATCH] Hopefully last review comments for greg --- .../special/PowerstabSpecialHandler.java | 4 +- .../skill/construction/HouseManager.java | 28 ++--- .../global/skill/construction/Room.java | 2 +- .../gather/woodcutting/WoodcuttingListener.kt | 6 +- .../magic/ancient/AncientTeleportPlugin.java | 2 +- .../draynor/dialogue/DraynorBankGuard.java | 4 +- Server/src/main/core/game/bots/ScriptAPI.kt | 8 +- .../core/game/interaction/MovementPulse.java | 2 +- .../node/entity/combat/MultihitTargets.kt | 11 +- .../core/game/node/entity/player/Player.java | 2 +- .../system/command/sets/SpawnCommandSet.kt | 8 +- .../core/game/system/config/ConfigParser.kt | 4 +- .../system/config/ObjectOverrideParser.kt | 4 +- .../src/main/core/game/world/map/Region.java | 110 ++++++++++-------- .../main/core/game/world/map/RegionChunk.java | 74 ++++++------ .../main/core/game/world/map/RegionManager.kt | 13 +-- .../game/world/map/build/DynamicRegion.java | 34 +++--- .../game/world/map/build/MapscapeParser.java | 20 ++-- .../world/map/zone/impl/ModeratorZone.java | 5 - .../game/world/update/ChunkDirtyListener.kt | 17 ++- .../game/world/update/ChunkUpdateTracker.kt | 19 --- .../game/world/update/MapChunkRenderer.kt | 12 +- .../core/game/world/update/NPCRenderer.kt | 5 +- .../game/world/update/flag/PlayerFlags.java | 3 +- .../randoms/SnowStormHolidayRandomNPC.kt | 2 +- .../net/packet/out/BuildDynamicScene.java | 11 +- .../core/net/packet/out/ClearRegionChunk.java | 2 +- .../blastfurnace/BlastFurnaceAreaTests.kt | 2 +- 28 files changed, 206 insertions(+), 208 deletions(-) delete mode 100644 Server/src/main/core/game/world/update/ChunkUpdateTracker.kt diff --git a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java index 74f18dca1..ca7efb145 100644 --- a/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java +++ b/Server/src/main/content/global/handlers/item/equipment/special/PowerstabSpecialHandler.java @@ -16,7 +16,7 @@ import core.tools.RandomFunction; import org.rs09.consts.Sounds; import static core.api.ContentAPIKt.playGlobalAudio; -import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargets; +import static core.game.node.entity.combat.MultihitTargetsKt.findMultihitTargetsForD2h; /** * Handles the Powerstab special attack. @@ -73,7 +73,7 @@ public final class PowerstabSpecialHandler extends MeleeSwingHandler implements if (!multi) { return super.swing(entity, victim, state); } - List list = findMultihitTargets(entity.getLocation(), entity, CombatStyle.MELEE); + List list = findMultihitTargetsForD2h(entity.getLocation(), entity, CombatStyle.MELEE); BattleState[] targets = new BattleState[list.size()]; int count = 0; for (Entity e : list) { diff --git a/Server/src/main/content/global/skill/construction/HouseManager.java b/Server/src/main/content/global/skill/construction/HouseManager.java index 555ad027a..773d252b5 100644 --- a/Server/src/main/content/global/skill/construction/HouseManager.java +++ b/Server/src/main/content/global/skill/construction/HouseManager.java @@ -26,14 +26,12 @@ import static core.api.ContentAPIKt.*; import static core.api.regionspec.RegionSpecificationKt.fillWith; import static core.api.regionspec.RegionSpecificationKt.using; - /** * Manages the player's house. * @author Emperor * */ public final class HouseManager { - /** * The current region. */ @@ -98,7 +96,6 @@ public final class HouseManager { */ } - public void parse(JSONObject data){ location = HouseLocation.values()[Integer.parseInt( data.get("location").toString())]; style = HousingStyle.values()[Integer.parseInt( data.get("style").toString())]; @@ -261,7 +258,7 @@ public final class HouseManager { */ public void expelGuests(Player player) { if (isLoaded()) { - for (int z = 0; z < 4; z++) { + for (int z = 0; z < Region.PLANES; z++) { ArrayList players = new ArrayList<>(houseRegion.assemblePlayerList(z)); if (dungeonRegion != null) { players.addAll(dungeonRegion.assemblePlayerList(z)); @@ -292,7 +289,7 @@ public final class HouseManager { if (h.getDecorationIndex() > -1) { Decoration d = h.getHotspot().getDecorations()[h.getDecorationIndex()]; if (d == Decoration.PORTAL) { - return houseRegion.getBaseLocation().transform(x * 8 + h.getChunkX(), y * 8 + h.getChunkY() + 2, 0); + return houseRegion.getBaseLocation().transform(x*RegionChunk.SIZE + h.getChunkX(), y*RegionChunk.SIZE + h.getChunkY() + 2, 0); } } } @@ -308,9 +305,9 @@ public final class HouseManager { */ public void redecorate(HousingStyle style) { this.style = style; - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int z = 0; z < Region.PLANES; z++) { + for (int x = 0; x < RegionChunk.SIZE; x++) { + for (int y = 0; y < RegionChunk.SIZE; y++) { Room room = rooms[z][x][y]; if (room != null) { room.decorate(style); @@ -325,9 +322,9 @@ public final class HouseManager { */ @Deprecated public void clearRooms() { - for (int z = 0; z < 4; z++) { - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int z = 0; z < Region.PLANES; z++) { + for (int x = 0; x < RegionChunk.SIZE; x++) { + for (int y = 0; y < RegionChunk.SIZE; y++) { rooms[z][x][y] = null; } } @@ -368,7 +365,7 @@ public final class HouseManager { } private DynamicRegion getPreparedRegion() { - ZoneBorders borders = DynamicRegion.reserveArea(8,8); + ZoneBorders borders = DynamicRegion.reserveArea(Region.CHUNKS_SIZE,Region.CHUNKS_SIZE); DynamicRegion region = new DynamicRegion(-1, borders.getSouthWestX() >> 6, borders.getSouthWestY() >> 6); region.setBorders(borders); region.setBuild(true); @@ -604,8 +601,8 @@ public final class HouseManager { int startY = 99; int endX = 0; int endY = 0; - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < Region.CHUNKS_SIZE; x++) { + for (int y = 0; y < Region.CHUNKS_SIZE; y++) { if (rooms[0][x][y] != null) { if (x < startX) startX = x; if (y < startY) startY = y; @@ -699,9 +696,6 @@ public final class HouseManager { * Checks if the house region was constructed and active. * @return {@code True} if an active region for the house exists. */ - //public boolean isLoaded() { - // return (houseRegion != null) || (dungeonRegion != null); - //} public boolean isLoaded() { return (houseRegion != null && houseRegion.isActive()) || (dungeonRegion != null && dungeonRegion.isActive()); } diff --git a/Server/src/main/content/global/skill/construction/Room.java b/Server/src/main/content/global/skill/construction/Room.java index 508fa6370..1dbbaecb7 100644 --- a/Server/src/main/content/global/skill/construction/Room.java +++ b/Server/src/main/content/global/skill/construction/Room.java @@ -149,7 +149,7 @@ public final class Room { } } } - if (rotation != Direction.NORTH && chunk.getRotation() == 0) { + if (rotation != Direction.NORTH && chunk.getRotation() == 0) { //TODO: it is absolutely insane that this is using Direction.NORTH and such rather than RegionChunk.NORTH_ROTATION and such. chunk.rotate(rotation); } if (!house.isBuildingMode()) { diff --git a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt index 301fc6799..e9c3edcad 100644 --- a/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt +++ b/Server/src/main/content/global/skill/gather/woodcutting/WoodcuttingListener.kt @@ -214,11 +214,11 @@ class WoodcuttingListener : InteractionListener { player.animate(SkillingTool.getHatchet(player).animation) val playersAroundMe: List = RegionManager.getLocalPlayers(player.location, 2) .stream() - .filter { p -> p.name != player.name } + .filter { p -> p != player } .toList() val soundIndex = RandomFunction.random(0, woodcuttingSounds.size) - for (player in playersAroundMe) { - playAudio(player, woodcuttingSounds[soundIndex]) + for (p in playersAroundMe) { + playAudio(p, woodcuttingSounds[soundIndex]) } } } diff --git a/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java b/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java index 0d7b1cfa1..a9c95ab5e 100644 --- a/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java +++ b/Server/src/main/content/global/skill/magic/ancient/AncientTeleportPlugin.java @@ -68,7 +68,7 @@ public final class AncientTeleportPlugin extends MagicSpell { return false; } homeTeleport((Player) entity, Location.create(3087, 3495, 0)); - entity.dispatch(new SpellCastEvent(SpellBook.ANCIENT, getSpellId(), target)); + entity.dispatch(new SpellCastEvent(SpellBook.ANCIENT, getSpellId(), target)); } else if (entity.getTeleporter().send(location.transform(0, RandomFunction.random(3), 0), TeleportType.ANCIENT)) { if (!super.meetsRequirements(entity, true, true)) { entity.getTeleporter().getCurrentTeleport().stop(); diff --git a/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java b/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java index 501f0f0dd..611737fd1 100644 --- a/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java +++ b/Server/src/main/content/region/misthalin/draynor/dialogue/DraynorBankGuard.java @@ -17,8 +17,6 @@ import static core.api.ContentAPIKt.getAttribute; */ @Initializable public final class DraynorBankGuard extends DialoguePlugin { - private final static String HAS_SEEN_RECORDING = "draynor-recording"; - /** * Represents the coins item needed to re-watch the recording. */ @@ -58,7 +56,7 @@ public final class DraynorBankGuard extends DialoguePlugin { public boolean handle(int interfaceId, int buttonId) { switch (stage) { case 0: - if (!getAttribute(player, HAS_SEEN_RECORDING, false)) { + if (!getAttribute(player, DBRCutscene.HAS_SEEN_RECORDING, false)) { interpreter.sendOptions("Select an option", "Can I deposit my stuff here?", "That wall doesn't look very good.", "Sorry, I don't want anything."); stage = 1; } else { diff --git a/Server/src/main/core/game/bots/ScriptAPI.kt b/Server/src/main/core/game/bots/ScriptAPI.kt index b2e94e8a7..9b96aec77 100644 --- a/Server/src/main/core/game/bots/ScriptAPI.kt +++ b/Server/src/main/core/game/bots/ScriptAPI.kt @@ -134,7 +134,7 @@ class ScriptAPI(private val bot: Player) { */ fun getNearestNodeFromList(acceptedNames: List, isObject: Boolean): Node? { val region = RegionManager.forId(bot.location.regionId) - val list = if (isObject) region.assembleObjectList(bot.location.z) else region.assembleEntityList(bot.location.z) + val list = if (isObject) region.assembleObjectList(bot.location.z) else region.assembleNodeList(bot.location.z) return processEvaluationList(list, acceptedName = acceptedNames) } @@ -147,7 +147,7 @@ class ScriptAPI(private val bot: Player) { */ fun getNearestNode(id: Int, isObject: Boolean): Node? { val region = RegionManager.forId(bot.location.regionId) - val list = if (isObject) region.assembleObjectList(bot.location.z) else region.assembleEntityList(bot.location.z) + val list = if (isObject) region.assembleObjectList(bot.location.z) else region.assembleNodeList(bot.location.z) return processEvaluationList(list, acceptedId = id) } @@ -159,7 +159,7 @@ class ScriptAPI(private val bot: Player) { */ fun getNearestNode(entityName: String): Node? { val region = RegionManager.forId(bot.location.regionId) - val list = region.assembleEntityList(bot.location.z) + val list = region.assembleNodeList(bot.location.z) return processEvaluationList(list, acceptedName = listOf(entityName)) } @@ -172,7 +172,7 @@ class ScriptAPI(private val bot: Player) { */ fun getNearestNode(name: String, isObject: Boolean): Node? { val region = RegionManager.forId(bot.location.regionId) - val list = region.assembleEntityList(bot.location.z) + val list = region.assembleNodeList(bot.location.z) return processEvaluationList(list, acceptedName = listOf(name)) } diff --git a/Server/src/main/core/game/interaction/MovementPulse.java b/Server/src/main/core/game/interaction/MovementPulse.java index 372ed3b12..de51f1d13 100644 --- a/Server/src/main/core/game/interaction/MovementPulse.java +++ b/Server/src/main/core/game/interaction/MovementPulse.java @@ -240,7 +240,7 @@ public abstract class MovementPulse extends Pulse { private boolean tryInteract() { Location ml = mover.getLocation(); // Allow being within 1 square of moving entities to interact with them. - int radius = destination instanceof Entity && ((Entity)destination).getWalkingQueue().hasPath() ? 1 : 0; + int radius = destination instanceof Entity && ((Entity) destination).getWalkingQueue().hasPath() ? 1 : 0; if (interactLocation == null) return false; boolean atInteractLocation = Math.max(Math.abs(ml.getX() - interactLocation.getX()), Math.abs(ml.getY() - interactLocation.getY())) <= radius; diff --git a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt index 1150743a4..26f1c9168 100644 --- a/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt +++ b/Server/src/main/core/game/node/entity/combat/MultihitTargets.kt @@ -20,7 +20,12 @@ private fun isAttackable(victim: Entity, attacker: Entity, combatStyle: CombatSt fun findMultihitTargets(center: Location, attacker: Entity, combatStyle: CombatStyle?): List { val targets = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } - return targets.take(9) + return targets.take(9) //https://runescape.wiki/w/Vesta%27s_spear "the opponent and up to 9 additional targets in a 3x3 area around the player"; https://oldschool.runescape.wiki/w/Ice_Barrage "up to nine targets" +} + +fun findMultihitTargetsForD2h(center: Location, attacker: Entity, combatStyle: CombatStyle?): List { + val targets = getLocalEntities(center, 1).filter { it != attacker && isAttackable(it, attacker, combatStyle, false) } + return targets.filter { it.location.withinDistance(center, 1) } .take(14) //runescape.wiki/w/Dragon_2h_sword?oldid=859949 "up to 14 enemies in the squares around the player (Only directly in front of and to the sides, it does not attack those diagonal of the player)" } fun findMultihitTargetsForChinchompa(center: Location, attacker: Entity, victim: Entity): List { @@ -50,5 +55,5 @@ fun findMultihitTargetsForChinchompa(center: Location, attacker: Entity, victim: } targets = targetCandidates.filter { it is NPC || isOwnerOf(it, npcs) } } - return targets.take(9) -} \ No newline at end of file + return targets.take(9) //https://runescape.wiki/w/Chinchompa "up to 9 enemies" +} diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index 301ad724f..19233647d 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -856,7 +856,7 @@ public class Player extends Entity { getZoneMonitor().getZones().clear(); playerFlags.setLastSceneGraph(null); playerFlags.setUpdateSceneGraph(false); - playerFlags.setLastViewport(new RegionChunk[13][13]); + playerFlags.setLastViewport(new RegionChunk[MapChunkRenderer.BUILD_AREA_SIZE][MapChunkRenderer.BUILD_AREA_SIZE]); renderInfo.getLocalNPCs().clear(); renderInfo.getLocalPlayers().clear(); renderInfo.setLastLocation(null); diff --git a/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt b/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt index f197553bb..7649bb414 100644 --- a/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/SpawnCommandSet.kt @@ -151,7 +151,7 @@ class SpawnCommandSet : CommandSet(Privilege.ADMIN){ if (args.size != 1) reject(player, "::removeobject doesn't support arguments") val obj = getObject(player.location) if (obj == null) { - sendMessage(player, "All ten objects on the tile were null.") + sendMessage(player, "All four objects on the tile were null.") return@define } sendMessage(player, "The first object found on the tile was ${obj.id}; it will now be removed.") @@ -161,12 +161,10 @@ class SpawnCommandSet : CommandSet(Privilege.ADMIN){ define("objects", Privilege.STANDARD, "::objects", "Prints a list of all ten sceneries at your current coordinates") { player, args -> if (args.size != 1) reject(player, "::objects doesn't support arguments") val chunk = getRegionChunk(player.location) - val region = RegionManager.forId(player.location.regionId) fun dump(label: String, objects: List) { sendMessage(player, "--- $label ---") val nulls = ArrayList(10) - for (i in 0 until objects.size) { - val o = objects[i] + for ((i, o) in objects.withIndex()) { if (o == null) { nulls.add(i) } else { @@ -174,7 +172,7 @@ class SpawnCommandSet : CommandSet(Privilege.ADMIN){ val r = if (o.isRenderable) "R" else "" val a = if (o.isActive) "A" else "" var props = c + r + a - if (props.length > 0) { + if (props.isNotEmpty()) { props = " *$props" } sendMessage(player, " $i: $o$props") diff --git a/Server/src/main/core/game/system/config/ConfigParser.kt b/Server/src/main/core/game/system/config/ConfigParser.kt index 00c8e72e7..fd88dfdfa 100644 --- a/Server/src/main/core/game/system/config/ConfigParser.kt +++ b/Server/src/main/core/game/system/config/ConfigParser.kt @@ -34,8 +34,8 @@ class ConfigParser : Commands { fun reloadConfigs(callback: () -> Unit) { GlobalScope.launch { RegionManager.apply { r -> - r.addScenery.clear() - r.removeScenery.clear() + r.addSceneries.clear() + r.removeSceneries.clear() } Repository.npcs.toTypedArray().forEach { npc -> diff --git a/Server/src/main/core/game/system/config/ObjectOverrideParser.kt b/Server/src/main/core/game/system/config/ObjectOverrideParser.kt index 68705d7ca..c75840039 100644 --- a/Server/src/main/core/game/system/config/ObjectOverrideParser.kt +++ b/Server/src/main/core/game/system/config/ObjectOverrideParser.kt @@ -45,8 +45,8 @@ class ObjectOverrideParser { val obj = Scenery(id, loc, type, rotation) val region = RegionManager.forId(loc.regionId) when (mode) { - "remove" -> region.removeScenery.add(obj) //type and rotation are currently ignored, but this can be changed in Region.java if needed - "add" -> region.addScenery.add(obj) + "remove" -> region.removeSceneries.add(obj) //type and rotation are currently ignored, but this can be changed in Region.java if needed + "add" -> region.addSceneries.add(obj) else -> log(this::class.java, Log.ERR, "Ignored unknown ObjectOverride mode $mode!") } count++ diff --git a/Server/src/main/core/game/world/map/Region.java b/Server/src/main/core/game/world/map/Region.java index 6524772aa..0a0ca85e4 100644 --- a/Server/src/main/core/game/world/map/Region.java +++ b/Server/src/main/core/game/world/map/Region.java @@ -32,6 +32,21 @@ import static core.api.ContentAPIKt.log; * @author Emperor */ public class Region { + /** + * The number of tiles per region. + */ + public static final int SIZE = 64; + + /** + * The number of chunks per region. + */ + public static final int CHUNKS_SIZE = 8; + + /** + * The number of z levels per x,y coordinate. + */ + public static final int PLANES = 4; + /** * The region x-coordinate. */ @@ -45,7 +60,7 @@ public class Region { /** * The chunks in this region. */ - protected RegionChunk[][][] chunks = new RegionChunk[8][8][4]; + protected RegionChunk[][][] chunks = new RegionChunk[CHUNKS_SIZE][CHUNKS_SIZE][PLANES]; /** * The activity pulse. @@ -105,8 +120,8 @@ public class Region { /** * Any scenery overrides for this region */ - private ArrayList addScenery = new ArrayList<>(); - private ArrayList removeScenery = new ArrayList<>(); + private final ArrayList addSceneries = new ArrayList<>(); + private final ArrayList removeSceneries = new ArrayList<>(); /** * Constructs a new {@code Region} {@code Object}. @@ -117,10 +132,10 @@ public class Region { this.x = x; this.y = y; Location swCorner = getBaseLocation(); - for (x = 0; x < 8; x++) { - for (y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { - Location loc = swCorner.transform(x*8, y*8, z); + for (x = 0; x < CHUNKS_SIZE; x++) { + for (y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { + Location loc = swCorner.transform(x*RegionChunk.SIZE, y*RegionChunk.SIZE, z); chunks[x][y][z] = new RegionChunk(loc, 0); } } @@ -157,9 +172,9 @@ public class Region { */ public void add(RegionZone zone) { regionZones.add(zone); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { for (NPC npc : chunks[x][y][z].getNpcs()) { npc.getZoneMonitor().updateLocation(npc.getLocation()); } @@ -175,9 +190,9 @@ public class Region { public void remove(RegionZone zone) { regionZones.remove(zone); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { for (NPC npc : chunks[x][y][z].getNpcs()) { npc.getZoneMonitor().updateLocation(npc.getLocation()); } @@ -213,9 +228,9 @@ public class Region { if (isViewed()) { return false; } - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { if (!chunks[x][y][z].getPlayers().isEmpty()) { return false; } @@ -240,9 +255,9 @@ public class Region { if (!active) { active = true; load(this); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { for (NPC npc : chunks[x][y][z].getNpcs()) { if (npc.isActive()) { Repository.addRenderableNPC(npc); @@ -300,11 +315,11 @@ public class Region { return; } - byte[][][] mapscapeData = new byte[4][64][64]; - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { - r.chunks[x][y][z].getFlags().setLandscape(new boolean[8][8]); + byte[][][] mapscapeData = new byte[PLANES][SIZE][SIZE]; + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { + r.chunks[x][y][z].getFlags().setLandscape(new boolean[RegionChunk.SIZE][RegionChunk.SIZE]); } } } @@ -328,14 +343,14 @@ public class Region { } } MapscapeParser.clipMapscape(r, r.chunks, mapscapeData); - for (Scenery object : r.removeScenery) { + for (Scenery object : r.removeSceneries) { // Get the actual object, not the instance that's kept in the removeScenery array Scenery realObject = RegionManager.getObject(object.getLocation()); //can be extended to take into account type and rotation if needed if (realObject != null) { SceneryBuilder.remove(realObject); } } - for (Scenery object : r.addScenery) { + for (Scenery object : r.addSceneries) { SceneryBuilder.add(object); } } catch (Throwable e) { @@ -353,20 +368,20 @@ public class Region { r.flagActive(); return false; } - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { if (!force && !chunks[x][y][z].getPlayers().isEmpty()) { - log(CommunicationInfo.class, Log.ERR, "Players still in region!"); + log(CommunicationInfo.class, Log.ERR, "Players still in region! (region id " + getId() + "; " + chunks[x][y][z].getPlayers().size() + " players on a chunk)"); r.flagActive(); return false; } } } } - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { if (!(r instanceof DynamicRegion)) { for (NPC npc : chunks[x][y][z].getNpcs()) { npc.onRegionInactivity(); @@ -552,12 +567,12 @@ public class Region { public List assembleObjectList(int z) { ArrayList list = new ArrayList<>(); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { RegionChunk chunk = chunks[x][y][z]; - for (int offsetX = 0; offsetX < 8; offsetX++) { - for (int offsetY = 0; offsetY < 8; offsetY++) { - for (int i = 0; i < 4; i++) { + for (int offsetX = 0; offsetX < RegionChunk.SIZE; offsetX++) { + for (int offsetY = 0; offsetY < RegionChunk.SIZE; offsetY++) { + for (int i = 0; i < RegionChunk.ARRAY_SIZE; i++) { Scenery object = chunk.getObjects()[offsetX][offsetY][i]; if (object != null) { list.add(object); @@ -572,8 +587,8 @@ public class Region { public List assembleNpcList(int z) { ArrayList list = new ArrayList<>(); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { RegionChunk chunk = chunks[x][y][z]; list.addAll(chunk.getNpcs()); } @@ -583,8 +598,8 @@ public class Region { public List assemblePlayerList(int z) { ArrayList list = new ArrayList<>(); - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { RegionChunk chunk = chunks[x][y][z]; list.addAll(chunk.getPlayers()); } @@ -592,7 +607,7 @@ public class Region { return list; } - public List assembleEntityList(int z) { + public List assembleNodeList(int z) { ArrayList list = new ArrayList<>(assembleObjectList(z)); list.addAll(assemblePlayerList(z)); list.addAll(assembleNpcList(z)); @@ -601,7 +616,6 @@ public class Region { /** * Getter for region aggro tolerances. - * @return */ public HashMap getTolerances() { return tolerances; @@ -610,10 +624,10 @@ public class Region { /** * Getters for addScenery and removeScenery. */ - public ArrayList getAddScenery() { - return addScenery; + public ArrayList getAddSceneries() { + return addSceneries; } - public ArrayList getRemoveScenery() { - return removeScenery; + public ArrayList getRemoveSceneries() { + return removeSceneries; } } diff --git a/Server/src/main/core/game/world/map/RegionChunk.java b/Server/src/main/core/game/world/map/RegionChunk.java index 216d1556a..17f4e7f08 100644 --- a/Server/src/main/core/game/world/map/RegionChunk.java +++ b/Server/src/main/core/game/world/map/RegionChunk.java @@ -19,6 +19,7 @@ import core.game.world.map.build.DynamicRegion; import core.game.world.map.build.LandscapeParser; import core.game.world.update.flag.UpdateFlag; import core.net.packet.IoBuffer; +import org.rs09.consts.Items; import java.util.ArrayList; import java.util.List; @@ -188,22 +189,21 @@ public class RegionChunk { * Adds the scenery to the static and dynamic object lists. You never want this unless you are the landscape-parsing * code. * @param object The object to add. - * @return The slot it was added into. */ - public int addStatDyn(Scenery object, int chunkOffsetX, int chunkOffsetY) { + public void addStatDyn(Scenery object, int chunkOffsetX, int chunkOffsetY) { for (int i = 0; i < ARRAY_SIZE; i++) { Scenery current = statObjects[chunkOffsetX][chunkOffsetY][i]; if (current == null) { statObjects[chunkOffsetX][chunkOffsetY][i] = object; objects[chunkOffsetX][chunkOffsetY][i] = object.transform(object.getId()); //deep copy so that active/renderable flags don't synchronize across multiple copies of e.g. a POH - return i; + return; } if (current.getId() == object.getId()) { // It's possible that we already have this object. One instance of this was found at 1906, 5082, 0, // where our cache has more than one copy of the same [Scenery 15349, [1906, 5082, 0], type=22, rot=1] // object. Since authentically, the engine can only support one of the same type of object per tile, // if the ID matches we can be confident that this is a duplicate. - return i; + return; } } throw new IllegalStateException("RC addStatDyn insufficient array length for storing object " + object); @@ -249,8 +249,7 @@ public class RegionChunk { */ public void addPlayer(Player player) { players.add(player); - Region region = getCurrentBase().getRegion(); - region.flagActive(); + currentBase.getRegion().flagActive(); } /** @@ -282,8 +281,7 @@ public class RegionChunk { */ public void removePlayer(Player player) { players.remove(player); - Region region = getCurrentBase().getRegion(); - region.checkInactive(); + currentBase.getRegion().checkInactive(); } /** @@ -318,8 +316,8 @@ public class RegionChunk { */ public List assembleObjectList() { ArrayList list = new ArrayList<>(ARRAY_SIZE); - for (int offsetX = 0; offsetX < 8; offsetX++) { - for (int offsetY = 0; offsetY < 8; offsetY++) { + for (int offsetX = 0; offsetX < SIZE; offsetX++) { + for (int offsetY = 0; offsetY < SIZE; offsetY++) { for (int i = 0; i < ARRAY_SIZE; i++) { Scenery object = objects[offsetX][offsetY][i]; if (object != null) { @@ -331,12 +329,6 @@ public class RegionChunk { return list; } - public List getEntities() { - List entities = new ArrayList<>(assembleObjectList()); - entities.addAll(npcs); - return entities; - } - /** * Gets the players. * @return The players. @@ -424,7 +416,7 @@ public class RegionChunk { } public ArrayList drawItems(List items, Player player) { - ArrayList totalItems = items != null ? new ArrayList(items) : new ArrayList(); + ArrayList totalItems = items != null ? new ArrayList<>(items) : new ArrayList(); if (player.getAttribute("chunkdraw", false)) { Location l = currentBase; @@ -436,7 +428,7 @@ public class RegionChunk { else if (x == 0 || x == SIZE - 1) add = true; if (add) - totalItems.add(new GroundItem(new Item(13444), l.transform(x, y, 0), player)); + totalItems.add(new GroundItem(new Item(Items.ABYSSAL_WHIP_13444), l.transform(x, y, 0), player)); } } } @@ -461,7 +453,7 @@ public class RegionChunk { add = true; if (add) - totalItems.add(new GroundItem(new Item(13444), l.transform(x,y,0), player)); + totalItems.add(new GroundItem(new Item(Items.ABYSSAL_WHIP_13444), l.transform(x,y,0), player)); } } @@ -502,7 +494,7 @@ public class RegionChunk { */ public List getItems() { if (items == null) { - items = new ArrayList(); + items = new ArrayList<>(); } return items; } @@ -555,7 +547,7 @@ public class RegionChunk { * Gets the objects index for the given object id and/or scenery type. * @param x The x-coordinate on the region chunk. * @param y The y-coordinate on the region chunk. - * @param objectId The object id. + * @param objectId The object id. -1 if any. * @param type The scenery type. */ public int getIndex(int x, int y, int objectId, int type) { @@ -569,7 +561,6 @@ public class RegionChunk { return i; } else { if (o.getId() == objectId) { - // TODO: what if there are multiple instances of the same object? Hopefully this is only a theoretical possibility in this game return i; } } @@ -654,8 +645,8 @@ public class RegionChunk { * @param from The region plane to get the new clipping flags from. */ public void rebuildClippingFlags(RegionChunk from) { - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { // Import the landscape flags from the template chunk to the new chunk flags.getLandscape()[x][y] = from.getFlags().getLandscape()[x][y]; projectileFlags.getLandscape()[x][y] = from.getProjectileFlags().getLandscape()[x][y]; @@ -670,6 +661,15 @@ public class RegionChunk { } } + /** + * Rotation consts. Greg loves these :) + */ + private static int NORTH_ROTATION = 0; + private static int EAST_ROTATION = 1; + private static int SOUTH_ROTATION = 2; + private static int WEST_ROTATION = 2; + private static int NUMBER_OF_CARDINAL_ROTATIONS = 4; + /** * Rotates the chunk. * @param direction The direction. @@ -692,22 +692,22 @@ public class RegionChunk { } } clear(); - switch(direction) { - case NORTH: rotation = 0; break; - case EAST: rotation = 1; break; - case SOUTH: rotation = 2; break; - case WEST: rotation = 3; break; - default: rotation = (direction.toInteger() + (direction.toInteger() % 2 == 0 ? 2 : 0)) % 4; + switch (direction) { + case NORTH: rotation = NORTH_ROTATION; break; + case EAST: rotation = EAST_ROTATION; break; + case SOUTH: rotation = SOUTH_ROTATION; break; + case WEST: rotation = WEST_ROTATION; break; + default: rotation = (direction.toInteger() + (direction.toInteger() % 2 == 0 ? 2 : 0)) % NUMBER_OF_CARDINAL_ROTATIONS; log(this.getClass(), Log.ERR, "Attempted to rotate a chunk in a non-cardinal direction - using fallback rotation code. This should be investigated!"); break; }; - for (int i = 0; i < ARRAY_SIZE; i++) { - for (int x = 0; x < SIZE; x++) { - for (int y = 0; y < SIZE; y++) { + for (int x = 0; x < SIZE; x++) { + for (int y = 0; y < SIZE; y++) { + for (int i = 0; i < ARRAY_SIZE; i++) { Scenery object = copy[x][y][i]; if (object != null) { int[] pos = getRotatedPosition(x, y, object.getDefinition().getSizeX(), object.getDefinition().getSizeY(), object.getRotation(), rotation); - Scenery obj = object.transform(object.getId(), (object.getRotation() + rotation) % 4, object.getLocation().transform(pos[0] - x, pos[1] - y, 0)); + Scenery obj = object.transform(object.getId(), (object.getRotation() + rotation) % NUMBER_OF_CARDINAL_ROTATIONS, object.getLocation().transform(pos[0] - x, pos[1] - y, 0)); if (object instanceof Constructed) { obj = obj.asConstructed(); } @@ -740,12 +740,12 @@ public class RegionChunk { return new int[] { x, y }; } if (chunkRotation == 1) { - return new int[] { y, 7 - x - (sizeX - 1) }; + return new int[] { y, (SIZE-1) - x - (sizeX - 1) }; } if (chunkRotation == 2) { - return new int[] { 7 - x - (sizeX - 1), 7 - y - (sizeY - 1) }; + return new int[] { (SIZE-1) - x - (sizeX - 1), 7 - y - (sizeY - 1) }; } - return new int[] { 7 - y - (sizeY - 1), x }; + return new int[] { (SIZE-1) - y - (sizeY - 1), x }; } public ChunkFlags getFlags() { diff --git a/Server/src/main/core/game/world/map/RegionManager.kt b/Server/src/main/core/game/world/map/RegionManager.kt index d123088dd..aca27af9f 100644 --- a/Server/src/main/core/game/world/map/RegionManager.kt +++ b/Server/src/main/core/game/world/map/RegionManager.kt @@ -25,7 +25,7 @@ object RegionManager { @JvmStatic val CLIPPING_FLAGS = HashMap>() @JvmStatic val PROJECTILE_FLAGS = HashMap>() - val LOCK = ReentrantLock() + private val LOCK = ReentrantLock() /** * Gets the region for the given region id. @@ -378,12 +378,10 @@ object RegionManager { } } is NPC -> { - if (src != null) { - src.chunk.remove(entity) - } + src?.chunk?.remove(entity) dst.chunk.add(entity) } - else -> throw IllegalStateException("Tried to move an Entity that was neither Player nor NPC") + else -> log(this::class.java, Log.ERR, "Tried to move an Entity that was neither Player nor NPC, but $entity of class ${entity.javaClass}! It tried to move from $src to $dst.") } } entity.zoneMonitor.updateLocation(entity.walkingQueue.footPrint) @@ -393,7 +391,6 @@ object RegionManager { * Gets local entities. You never call the below function directly (it's inlined); instead, you use one of the typed helpers defined directly below this function. * @param location the location. * @param distance the distance. - * @param maximum the maximum number of entities to return. * @return the list. */ private inline fun getLocalEntitiesOfType(location: Location, distance: Int): List { @@ -402,10 +399,10 @@ object RegionManager { for (cy in (location.absChunkY - 8)..(location.absChunkY + 8)) { val chunk = Location(cx shl 3, cy shl 3, location.z).chunk if (T::class.java.isAssignableFrom(Player::class.java)) { - entities.addAll(chunk.players as Collection) + entities.addAll(chunk.players.filterIsInstance()) } if (T::class.java.isAssignableFrom(NPC::class.java)) { - entities.addAll(chunk.npcs as Collection) + entities.addAll(chunk.npcs.filterIsInstance()) } } } diff --git a/Server/src/main/core/game/world/map/build/DynamicRegion.java b/Server/src/main/core/game/world/map/build/DynamicRegion.java index c1a7ac7de..96671133a 100644 --- a/Server/src/main/core/game/world/map/build/DynamicRegion.java +++ b/Server/src/main/core/game/world/map/build/DynamicRegion.java @@ -15,7 +15,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; - /** * Represents a dynamically constructed region. * @@ -69,9 +68,9 @@ public final class DynamicRegion extends Region { super(x, y); this.regionId = regionId; // Reset any stale flags at this region's chunk coordinates - for (int chunkX = 0; chunkX < 8; chunkX++) { - for (int chunkY = 0; chunkY < 8; chunkY++) { - for (int cz = 0; cz < 4; cz++) { + for (int chunkX = 0; chunkX < CHUNKS_SIZE; chunkX++) { + for (int chunkY = 0; chunkY < CHUNKS_SIZE; chunkY++) { + for (int cz = 0; cz < Region.PLANES; cz++) { RegionChunk chunk = chunks[chunkX][chunkY][cz]; for (int chunkOffsetX = 0; chunkOffsetX < 8; chunkOffsetX++) { for (int chunkOffsetY = 0; chunkOffsetY < 8; chunkOffsetY++) { @@ -98,7 +97,7 @@ public final class DynamicRegion extends Region { public static DynamicRegion create(int regionId) { int x = (regionId >> 8) << 6; int y = (regionId & 0xFF) << 6; - return create(new ZoneBorders(x, y, x + 64, y + 64))[0]; + return create(new ZoneBorders(x, y, x + SIZE, y + SIZE))[0]; } /** @@ -112,7 +111,7 @@ public final class DynamicRegion extends Region { int y = (regionOne & 0xFF) << 6; int x1 = (regionTwo >> 8) << 6; int y1 = (regionTwo & 0xFF) << 6; - return create(new ZoneBorders(x, y, x1 + 64, y1 + 64))[0]; + return create(new ZoneBorders(x, y, x1 + SIZE, y1 + SIZE))[0]; } /** @@ -123,7 +122,6 @@ public final class DynamicRegion extends Region { public static DynamicRegion[] create(ZoneBorders copy) { int baseX = copy.getSouthWestX() >> 6; int baseY = copy.getSouthWestY() >> 6; - ZoneBorders border = findZoneBorders((copy.getNorthEastX() - copy.getSouthWestX()) >> 3, (copy.getNorthEastY() - copy.getSouthWestY()) >> 3); RESERVED_AREAS.add(border); Location l = Location.create(border.getSouthWestX(), border.getSouthWestY(), 0); @@ -139,7 +137,7 @@ public final class DynamicRegion extends Region { } } for (Region r : regions) { - for (int z = 0; z < 4; z++) { + for (int z = 0; z < PLANES; z++) { for (Player player : r.assemblePlayerList(z)) { if (player != null) { player.updateSceneGraph(false); @@ -174,11 +172,11 @@ public final class DynamicRegion extends Region { int count = 0; int width = (sizeX >> 3) << 6; int height = (sizeY >> 3) << 6; - if (width < 64) { - width = 64; + if (width < SIZE) { + width = SIZE; } - if (height < 64) { - height = 64; + if (height < SIZE) { + height = SIZE; } while (true) { int endX = x + width; @@ -195,10 +193,10 @@ public final class DynamicRegion extends Region { return new ZoneBorders(x, y, endX, endY); } if (++count % 15 == 0) { - y += 64; + y += SIZE; x = 0; } else { - x += 64; + x += SIZE; } } } @@ -219,7 +217,7 @@ public final class DynamicRegion extends Region { for (int offsetY = 0; offsetY < 8; offsetY++) { int x = regionX + (offsetX << 3); int y = regionY + (offsetY << 3); - for (int plane = 0; plane < 4; plane++) { + for (int plane = 0; plane < PLANES; plane++) { RegionChunk c = base.getChunks()[offsetX][offsetY][plane]; if (c == null) { c = new RegionChunk(Location.create(0, 0, 0), 0); @@ -319,9 +317,9 @@ public final class DynamicRegion extends Region { if (!super.flagInactive(force)) { return false; } - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { - for (int z = 0; z < 4; z++) { + for (int x = 0; x < CHUNKS_SIZE; x++) { + for (int y = 0; y < CHUNKS_SIZE; y++) { + for (int z = 0; z < PLANES; z++) { RegionChunk chunk = chunks[x][y][z]; for (NPC npc : chunk.getNpcs()) { npc.clear(); diff --git a/Server/src/main/core/game/world/map/build/MapscapeParser.java b/Server/src/main/core/game/world/map/build/MapscapeParser.java index 567b308cb..16866d653 100644 --- a/Server/src/main/core/game/world/map/build/MapscapeParser.java +++ b/Server/src/main/core/game/world/map/build/MapscapeParser.java @@ -23,8 +23,8 @@ public final class MapscapeParser { } // The cache is packed by region, so we need to parse it along the local-x/y coordinates for (int z = 0; z < 4; z++) { - for (int localX = 0; localX < 64; localX++) { - for (int localY = 0; localY < 64; localY++) { + for (int localX = 0; localX < Region.SIZE; localX++) { + for (int localY = 0; localY < Region.SIZE; localY++) { int chunkX = localX >> 3; int chunkY = localY >> 3; int chunkOffsetX = localX & 7; @@ -33,7 +33,7 @@ public final class MapscapeParser { boolean[][] landscape; if (chunk == null) { // Still need to consume the buffer data even for null chunks - landscape = new boolean[8][8]; + landscape = new boolean[RegionChunk.SIZE][RegionChunk.SIZE]; } else { landscape = chunk.getFlags().getLandscape(); } @@ -71,15 +71,15 @@ public final class MapscapeParser { * @param mapscape The mapscape. */ public static void clipMapscape(Region r, RegionChunk[][][] chunks, byte[][][] mapscape) { - for (int z = 0; z < 4; z++) { - for (int chunkX = 0; chunkX < 8; chunkX++) { - for (int chunkY = 0; chunkY < 8; chunkY++) { + for (int z = 0; z < Region.PLANES; z++) { + for (int chunkX = 0; chunkX < RegionChunk.SIZE; chunkX++) { + for (int chunkY = 0; chunkY < RegionChunk.SIZE; chunkY++) { RegionChunk chunk = chunks[chunkX][chunkY][z]; - for (int x = 0; x < 8; x++) { - for (int y = 0; y < 8; y++) { + for (int x = 0; x < RegionChunk.SIZE; x++) { + for (int y = 0; y < RegionChunk.SIZE; y++) { chunk.getFlags().flagEmptyTile(x, y); - int chunkOffsetX = chunkX*8 + x; - int chunkOffsetY = chunkY*8 + y; + int chunkOffsetX = chunkX*RegionChunk.SIZE + x; + int chunkOffsetY = chunkY*RegionChunk.SIZE + y; if ((mapscape[z][chunkOffsetX][chunkOffsetY] & 0x1) == 1) { int plane = z; if ((mapscape[1][chunkOffsetX][chunkOffsetY] & 0x2) == 2) { diff --git a/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java b/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java index 56352e7b6..be5f59b64 100644 --- a/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java +++ b/Server/src/main/core/game/world/map/zone/impl/ModeratorZone.java @@ -64,11 +64,6 @@ public class ModeratorZone extends MapZone { return true; } - @Override - public boolean interact(Entity entity, Node target, Option option) { - return super.interact(entity, target, option); - } - @Override public void configure() { register(new ZoneBorders(2840, 5204, 2853, 5224)); diff --git a/Server/src/main/core/game/world/update/ChunkDirtyListener.kt b/Server/src/main/core/game/world/update/ChunkDirtyListener.kt index 668c73ce7..38fba5192 100644 --- a/Server/src/main/core/game/world/update/ChunkDirtyListener.kt +++ b/Server/src/main/core/game/world/update/ChunkDirtyListener.kt @@ -1,7 +1,22 @@ package core.game.world.update import core.game.world.map.RegionChunk +import java.util.Collections +import java.util.IdentityHashMap +object ChunkUpdateTracker : ChunkDirtyListener { + private val dirty = Collections.newSetFromMap(IdentityHashMap()) + + override fun onFlagged(chunk: RegionChunk) { + dirty.add(chunk) + } + + /** Resets flags on exactly the chunks flagged this tick. Must run after all per-player flushes. */ + fun resetAll() { + dirty.forEach { it.resetUpdateFlags() } + dirty.clear() + } +} fun interface ChunkDirtyListener { fun onFlagged(chunk: RegionChunk) -} +} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt b/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt deleted file mode 100644 index 3db33d592..000000000 --- a/Server/src/main/core/game/world/update/ChunkUpdateTracker.kt +++ /dev/null @@ -1,19 +0,0 @@ -package core.game.world.update - -import core.game.world.map.RegionChunk -import java.util.Collections -import java.util.IdentityHashMap - -object ChunkUpdateTracker : ChunkDirtyListener { - private val dirty = Collections.newSetFromMap(IdentityHashMap()) - - override fun onFlagged(chunk: RegionChunk) { - dirty.add(chunk) - } - - /** Resets flags on exactly the chunks flagged this tick. Must run after all per-player flushes. */ - fun resetAll() { - dirty.forEach { it.resetUpdateFlags() } - dirty.clear() - } -} diff --git a/Server/src/main/core/game/world/update/MapChunkRenderer.kt b/Server/src/main/core/game/world/update/MapChunkRenderer.kt index 883dd0d86..22fd11b8d 100644 --- a/Server/src/main/core/game/world/update/MapChunkRenderer.kt +++ b/Server/src/main/core/game/world/update/MapChunkRenderer.kt @@ -3,7 +3,6 @@ package core.game.world.update import core.game.node.entity.player.Player import core.game.world.map.Location import core.game.world.map.RegionChunk -import core.game.world.map.build.DynamicRegion import core.net.packet.PacketRepository import core.net.packet.context.ClearChunkContext import core.net.packet.out.ClearRegionChunk @@ -14,7 +13,8 @@ import java.util.* * @author Emperor */ object MapChunkRenderer { - const val buildAreaDepth = 6 + const val BUILD_AREA_DEPTH = 6 + const val BUILD_AREA_SIZE = 2*BUILD_AREA_DEPTH + 1 /** * Sends the map chunk rendering packet. @@ -23,8 +23,8 @@ object MapChunkRenderer { @JvmStatic fun render(player: Player) { val last = player.playerFlags.lastViewport - val updated: MutableList = ArrayList() - val current: MutableList> = ArrayList() + val updated: ArrayList = ArrayList() + val current: ArrayList> = ArrayList() // Center the build area on the loaded scene anchor (lastSceneGraph), NOT the live player position. // The client's 13x13 build area is anchored at lastSceneGraph; addressing chunks relative to it keeps @@ -33,9 +33,9 @@ object MapChunkRenderer { // pushes the viewport edge to drift+6 chunks from the anchor, off-window, so edge items never render. val anchor = player.playerFlags.lastSceneGraph ?: player.location val center = Location.create(anchor.x, anchor.y, player.location.z) - for (dcx in -buildAreaDepth..+buildAreaDepth) { + for (dcx in -BUILD_AREA_DEPTH..BUILD_AREA_DEPTH) { val addX = ArrayList() - for (dcy in -buildAreaDepth..+buildAreaDepth) { + for (dcy in -BUILD_AREA_DEPTH..BUILD_AREA_DEPTH) { val newloc = center.transform(dcx * 8, dcy * 8, 0) addX.add(newloc.chunk) } diff --git a/Server/src/main/core/game/world/update/NPCRenderer.kt b/Server/src/main/core/game/world/update/NPCRenderer.kt index 026c8860f..01997e849 100644 --- a/Server/src/main/core/game/world/update/NPCRenderer.kt +++ b/Server/src/main/core/game/world/update/NPCRenderer.kt @@ -6,6 +6,7 @@ import core.game.world.map.RegionManager import core.net.packet.IoBuffer import core.net.packet.PacketHeader import core.game.world.GameWorld +import core.game.world.map.MapDistance import java.nio.ByteBuffer import java.util.* @@ -30,7 +31,7 @@ object NPCRenderer { val it: Iterator = localNPCs.iterator() while (it.hasNext()) { val npc = it.next() - val withinDistance = player.location.withinDistance(npc.location, 15) + val withinDistance = player.location.withinDistance(npc.location, MapDistance.RENDERING.distance) if (npc.isHidden(player) || !withinDistance || npc.properties.isTeleporting) { buffer.putBits(1, 1).putBits(2, 3) toRemove.add(npc) @@ -51,7 +52,7 @@ object NPCRenderer { } } localNPCs.removeAll(toRemove) - for (npc in RegionManager.getLocalNPCs(player.location, 15)) { + for (npc in RegionManager.getLocalNPCs(player.location, MapDistance.RENDERING.distance)) { if (localNPCs.size >= 255) { break } diff --git a/Server/src/main/core/game/world/update/flag/PlayerFlags.java b/Server/src/main/core/game/world/update/flag/PlayerFlags.java index 41d0cb441..2b9ea7c97 100644 --- a/Server/src/main/core/game/world/update/flag/PlayerFlags.java +++ b/Server/src/main/core/game/world/update/flag/PlayerFlags.java @@ -2,6 +2,7 @@ package core.game.world.update.flag; import core.game.world.map.Location; import core.game.world.map.RegionChunk; +import core.game.world.update.MapChunkRenderer; /** * A class holding a player's updating flags. @@ -17,7 +18,7 @@ public final class PlayerFlags { /** * The last viewport. */ - private RegionChunk[][] lastViewport = new RegionChunk[13][13]; + private RegionChunk[][] lastViewport = new RegionChunk[MapChunkRenderer.BUILD_AREA_SIZE][MapChunkRenderer.BUILD_AREA_SIZE]; /** * The location the player was standing on when last scene graph update diff --git a/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt b/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt index 9482068c7..c10d937f2 100644 --- a/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt +++ b/Server/src/main/core/game/worldevents/holiday/christmas/randoms/SnowStormHolidayRandomNPC.kt @@ -69,4 +69,4 @@ class SnowStormHolidayRandomNPC : HolidayRandomEventNPC(NPCs.SNOW_6740) { override fun talkTo(npc: NPC) { } -} +} \ No newline at end of file diff --git a/Server/src/main/core/net/packet/out/BuildDynamicScene.java b/Server/src/main/core/net/packet/out/BuildDynamicScene.java index f9719651f..d8fba5d7a 100644 --- a/Server/src/main/core/net/packet/out/BuildDynamicScene.java +++ b/Server/src/main/core/net/packet/out/BuildDynamicScene.java @@ -5,6 +5,7 @@ import core.game.world.map.Region; import core.game.world.map.RegionChunk; import core.game.world.map.RegionManager; import core.game.world.map.build.DynamicRegion; +import core.game.world.update.MapChunkRenderer; import core.net.packet.IoBuffer; import core.net.packet.OutgoingPacket; import core.net.packet.PacketHeader; @@ -29,12 +30,12 @@ public final class BuildDynamicScene implements OutgoingPacket> 3) << 8 | (y >> 3)); if (r instanceof DynamicRegion) { chunks[x - baseX][y - baseY][z] = r.getChunks()[x - (r.getX() << 3)][y - (r.getY() << 3)][z]; @@ -42,9 +43,9 @@ public final class BuildDynamicScene implements OutgoingPacket { - static final int buildAreaDepthInTiles = (2*MapChunkRenderer.buildAreaDepth+1) * 8; + static final int buildAreaDepthInTiles = (2*MapChunkRenderer.BUILD_AREA_DEPTH +1) * 8; @Override public void send(ClearChunkContext context) { diff --git a/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt b/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt index 870d1b265..8926443f1 100644 --- a/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt +++ b/Server/src/test/kotlin/content/activity/blastfurnace/BlastFurnaceAreaTests.kt @@ -242,4 +242,4 @@ class BlastFurnaceAreaTests { BlastFurnaceListeners().defineListeners() } } -} +} \ No newline at end of file