2012-06-29 16:44:26 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
// This file is part of Remere's Map Editor
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
2020-07-30 11:42:28 -03:00
|
|
|
// Remere's Map Editor is free software: you can redistribute it and/or modify
|
2012-06-29 16:44:26 +02:00
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
2016-09-29 19:24:45 -03:00
|
|
|
//
|
2020-07-30 11:42:28 -03:00
|
|
|
// Remere's Map Editor is distributed in the hope that it will be useful,
|
2012-06-29 16:44:26 +02:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2020-07-30 11:42:28 -03:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2012-06-29 16:44:26 +02:00
|
|
|
// GNU General Public License for more details.
|
2016-09-29 19:24:45 -03:00
|
|
|
//
|
2012-06-29 16:44:26 +02:00
|
|
|
// You should have received a copy of the GNU General Public License
|
2020-07-30 11:42:28 -03:00
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2012-06-29 16:44:26 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
|
|
|
|
|
|
#include "brush.h"
|
|
|
|
|
|
|
|
|
|
#include "tile.h"
|
2021-05-25 00:29:12 -03:00
|
|
|
#include "monster.h"
|
2012-06-29 16:44:26 +02:00
|
|
|
#include "house.h"
|
|
|
|
|
#include "basemap.h"
|
2021-05-25 00:29:12 -03:00
|
|
|
#include "spawn_monster.h"
|
2012-06-29 16:44:26 +02:00
|
|
|
#include "ground_brush.h"
|
|
|
|
|
#include "wall_brush.h"
|
|
|
|
|
#include "carpet_brush.h"
|
|
|
|
|
#include "table_brush.h"
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
#include "graphics.h"
|
2021-05-25 00:29:12 -03:00
|
|
|
#include "npc.h"
|
|
|
|
|
#include "spawn_npc.h"
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
#include "object_pool.h"
|
|
|
|
|
|
|
|
|
|
void* Tile::operator new(size_t size) {
|
|
|
|
|
return rme::allocatePooledObject(size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tile::operator delete(void* ptr) noexcept {
|
|
|
|
|
rme::deallocatePooledObject(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_MEM
|
|
|
|
|
void* Tile::operator new(size_t size, const char*, int) {
|
|
|
|
|
return rme::allocatePooledObject(size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tile::operator delete(void* ptr, const char*, int) noexcept {
|
|
|
|
|
rme::deallocatePooledObject(ptr);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2012-06-29 16:44:26 +02:00
|
|
|
|
|
|
|
|
Tile::Tile(int x, int y, int z) :
|
2014-01-22 20:16:17 +01:00
|
|
|
location(nullptr),
|
|
|
|
|
ground(nullptr),
|
2021-05-25 00:29:12 -03:00
|
|
|
spawnMonster(nullptr),
|
|
|
|
|
npc(nullptr),
|
|
|
|
|
spawnNpc(nullptr),
|
2012-06-29 16:44:26 +02:00
|
|
|
house_id(0),
|
|
|
|
|
mapflags(0),
|
2018-04-22 10:54:06 -03:00
|
|
|
statflags(0),
|
2023-10-09 19:12:16 -07:00
|
|
|
minimapColor(INVALID_MINIMAP_COLOR) {
|
2015-12-06 11:42:37 -03:00
|
|
|
////
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
Tile::Tile(TileLocation &loc) :
|
2012-06-29 16:44:26 +02:00
|
|
|
location(&loc),
|
2014-01-22 20:16:17 +01:00
|
|
|
ground(nullptr),
|
2021-05-25 00:29:12 -03:00
|
|
|
spawnMonster(nullptr),
|
|
|
|
|
npc(nullptr),
|
|
|
|
|
spawnNpc(nullptr),
|
2012-06-29 16:44:26 +02:00
|
|
|
house_id(0),
|
|
|
|
|
mapflags(0),
|
2018-04-22 10:54:06 -03:00
|
|
|
statflags(0),
|
2023-10-09 19:12:16 -07:00
|
|
|
minimapColor(INVALID_MINIMAP_COLOR) {
|
2015-12-06 11:42:37 -03:00
|
|
|
////
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
Tile::~Tile() {
|
|
|
|
|
while (!items.empty()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
delete items.back();
|
|
|
|
|
items.pop_back();
|
|
|
|
|
}
|
2024-10-02 16:01:28 -03:00
|
|
|
|
|
|
|
|
while (!monsters.empty()) {
|
|
|
|
|
delete monsters.back();
|
|
|
|
|
monsters.pop_back();
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
// printf("%d,%d,%d,%p\n", tilePos.x, tilePos.y, tilePos.z, ground);
|
2012-06-29 16:44:26 +02:00
|
|
|
delete ground;
|
2021-05-25 00:29:12 -03:00
|
|
|
delete spawnMonster;
|
|
|
|
|
delete npc;
|
|
|
|
|
delete spawnNpc;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
Tile* Tile::deepCopy(BaseMap &map) const {
|
2012-06-29 16:44:26 +02:00
|
|
|
Tile* copy = map.allocator.allocateTile(location);
|
|
|
|
|
copy->flags = flags;
|
|
|
|
|
copy->house_id = house_id;
|
2023-10-09 19:12:16 -07:00
|
|
|
if (spawnMonster) {
|
|
|
|
|
copy->spawnMonster = spawnMonster->deepCopy();
|
|
|
|
|
}
|
|
|
|
|
if (spawnNpc) {
|
|
|
|
|
copy->spawnNpc = spawnNpc->deepCopy();
|
|
|
|
|
}
|
|
|
|
|
if (npc) {
|
|
|
|
|
copy->npc = npc->deepCopy();
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
// Spawncount & exits are not transferred on copy!
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground) {
|
|
|
|
|
copy->ground = ground->deepCopy();
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2024-10-02 16:01:28 -03:00
|
|
|
for (const auto monster : monsters) {
|
|
|
|
|
copy->monsters.emplace_back(monster->deepCopy());
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
for (const Item* item : items) {
|
2023-10-09 23:02:37 -03:00
|
|
|
copy->items.push_back(item->deepCopy());
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
2023-11-08 17:04:13 -08:00
|
|
|
for (unsigned int zone : zones) {
|
|
|
|
|
copy->zones.insert(zone);
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
return copy;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
uint32_t Tile::memsize() const {
|
2014-02-28 22:34:25 +01:00
|
|
|
uint32_t mem = sizeof(*this);
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground) {
|
|
|
|
|
mem += ground->memsize();
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (const Item* item : items) {
|
2023-10-09 23:02:37 -03:00
|
|
|
mem += item->memsize();
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mem += sizeof(Item*) * items.capacity();
|
|
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
int Tile::size() const {
|
2012-06-29 16:44:26 +02:00
|
|
|
int sz = 0;
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground) {
|
|
|
|
|
++sz;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
sz += items.size();
|
2024-10-02 16:01:28 -03:00
|
|
|
sz += monsters.size();
|
2023-10-09 19:12:16 -07:00
|
|
|
if (spawnMonster) {
|
|
|
|
|
++sz;
|
|
|
|
|
}
|
|
|
|
|
if (npc) {
|
|
|
|
|
++sz;
|
|
|
|
|
}
|
|
|
|
|
if (spawnNpc) {
|
|
|
|
|
++sz;
|
|
|
|
|
}
|
|
|
|
|
if (location) {
|
|
|
|
|
if (location->getHouseExits()) {
|
|
|
|
|
++sz;
|
|
|
|
|
}
|
|
|
|
|
if (location->getSpawnMonsterCount()) {
|
|
|
|
|
++sz;
|
|
|
|
|
}
|
|
|
|
|
if (location->getSpawnNpcCount()) {
|
|
|
|
|
++sz;
|
|
|
|
|
}
|
|
|
|
|
if (location->getWaypointCount()) {
|
|
|
|
|
++sz;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
return sz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tile::merge(Tile* other) {
|
2023-10-09 23:02:37 -03:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (!other) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-10-09 23:02:37 -03:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (other->isPZ()) {
|
|
|
|
|
setPZ(true);
|
|
|
|
|
}
|
|
|
|
|
if (other->house_id) {
|
2012-06-29 16:44:26 +02:00
|
|
|
house_id = other->house_id;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (other->ground) {
|
2012-06-29 16:44:26 +02:00
|
|
|
delete ground;
|
|
|
|
|
ground = other->ground;
|
2014-01-22 20:16:17 +01:00
|
|
|
other->ground = nullptr;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (other->spawnMonster) {
|
2021-05-25 00:29:12 -03:00
|
|
|
delete spawnMonster;
|
|
|
|
|
spawnMonster = other->spawnMonster;
|
|
|
|
|
other->spawnMonster = nullptr;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (other->npc) {
|
2021-05-25 00:29:12 -03:00
|
|
|
delete npc;
|
|
|
|
|
npc = other->npc;
|
|
|
|
|
other->npc = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (other->spawnNpc) {
|
2021-05-25 00:29:12 -03:00
|
|
|
delete spawnNpc;
|
|
|
|
|
spawnNpc = other->spawnNpc;
|
|
|
|
|
other->spawnNpc = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-02 16:01:28 -03:00
|
|
|
for (const auto monster : other->monsters) {
|
|
|
|
|
addMonster(monster);
|
|
|
|
|
}
|
|
|
|
|
other->monsters.clear();
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (Item* item : other->items) {
|
2023-10-09 23:02:37 -03:00
|
|
|
addItem(item);
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
other->items.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
bool Tile::hasProperty(enum ITEMPROPERTY prop) const {
|
|
|
|
|
if (prop == PROTECTIONZONE && isPZ()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
return true;
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground && ground->hasProperty(prop)) {
|
2012-06-29 16:44:26 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (const Item* item : items) {
|
|
|
|
|
if (item->hasProperty(prop)) {
|
2012-06-29 16:44:26 +02:00
|
|
|
return true;
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
uint16_t Tile::getGroundSpeed() const noexcept {
|
|
|
|
|
if (ground && !ground->isMetaItem()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
return ground->getGroundSpeed();
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
int Tile::getIndexOf(Item* item) const {
|
|
|
|
|
if (!item) {
|
2021-10-02 22:41:32 -03:00
|
|
|
return wxNOT_FOUND;
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
2021-10-02 22:41:32 -03:00
|
|
|
|
|
|
|
|
int index = 0;
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground) {
|
|
|
|
|
if (ground == item) {
|
2021-10-02 22:41:32 -03:00
|
|
|
return index;
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
2021-10-02 22:41:32 -03:00
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (!items.empty()) {
|
2021-10-02 22:41:32 -03:00
|
|
|
auto it = std::find(items.begin(), items.end(), item);
|
2023-10-09 19:12:16 -07:00
|
|
|
if (it != items.end()) {
|
2021-10-02 22:41:32 -03:00
|
|
|
index += (it - items.begin());
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return wxNOT_FOUND;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
Item* Tile::getTopItem() const {
|
|
|
|
|
if (!items.empty() && !items.back()->isMetaItem()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
return items.back();
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
|
|
|
|
if (ground && !ground->isMetaItem()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
return ground;
|
|
|
|
|
}
|
2014-01-22 20:16:17 +01:00
|
|
|
return nullptr;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
Item* Tile::getItemAt(int index) const {
|
|
|
|
|
if (index < 0) {
|
2021-10-02 22:41:32 -03:00
|
|
|
return nullptr;
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
|
|
|
|
if (ground) {
|
|
|
|
|
if (index == 0) {
|
2021-10-02 22:41:32 -03:00
|
|
|
return ground;
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
2021-10-02 22:41:32 -03:00
|
|
|
index--;
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
if (!items.empty() && index >= 0 && index < items.size()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
return items.at(index);
|
2021-10-02 22:41:32 -03:00
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-02 16:01:28 -03:00
|
|
|
void Tile::addMonster(Monster* monster) {
|
|
|
|
|
if (!monster) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
monsters.emplace_back(monster);
|
|
|
|
|
|
|
|
|
|
if (monster->isSelected()) {
|
|
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::addItem(Item* item) {
|
|
|
|
|
if (!item) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
|
|
|
|
|
addItem(item, item->getItemType());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
FORCEINLINE ItemVector::iterator findBottomInsertPosition(ItemVector &items, int topOrder) {
|
|
|
|
|
return std::find_if(items.begin(), items.end(), [topOrder](const Item* existingItem) {
|
|
|
|
|
const ItemType &existingType = existingItem->getItemType();
|
|
|
|
|
return !existingType.alwaysOnBottom || topOrder < existingType.alwaysOnTopOrder;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tile::addItem(Item* item, const ItemType &type) {
|
|
|
|
|
if (!item) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (type.isGroundTile()) {
|
2023-10-09 19:12:16 -07:00
|
|
|
// printf("ADDING GROUND\n");
|
2012-06-29 16:44:26 +02:00
|
|
|
delete ground;
|
|
|
|
|
ground = item;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
if (items.empty()) {
|
|
|
|
|
constexpr size_t initialTileItemCapacity = 4;
|
|
|
|
|
items.reserve(initialTileItemCapacity);
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-29 16:44:26 +02:00
|
|
|
ItemVector::iterator it;
|
2016-09-29 19:24:45 -03:00
|
|
|
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
uint16_t gid = type.ground_equivalent;
|
2023-10-09 19:12:16 -07:00
|
|
|
if (gid != 0) {
|
2012-06-29 16:44:26 +02:00
|
|
|
delete ground;
|
|
|
|
|
ground = Item::Create(gid);
|
|
|
|
|
// At the very bottom!
|
|
|
|
|
it = items.begin();
|
|
|
|
|
} else {
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
if (type.alwaysOnBottom) {
|
|
|
|
|
it = findBottomInsertPosition(items, type.alwaysOnTopOrder);
|
2012-06-29 16:44:26 +02:00
|
|
|
} else {
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
items.emplace_back(item);
|
|
|
|
|
|
|
|
|
|
if (item->isSelected()) {
|
|
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
|
|
|
|
return;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
2016-09-29 19:24:45 -03:00
|
|
|
|
2012-06-29 16:44:26 +02:00
|
|
|
items.insert(it, item);
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (item->isSelected()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
void Tile::addLoadedItem(Item* item, const ItemType &type) {
|
|
|
|
|
if (!item) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool createsGroundEquivalent = !type.isGroundTile() && type.ground_equivalent != 0;
|
|
|
|
|
addItem(item, type);
|
|
|
|
|
|
|
|
|
|
if (type.isGroundTile()) {
|
|
|
|
|
updateStateForItem(item, type);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (createsGroundEquivalent && ground) {
|
|
|
|
|
updateStateForItem(ground, ground->getItemType());
|
|
|
|
|
}
|
|
|
|
|
updateStateForItem(item, type);
|
|
|
|
|
}
|
|
|
|
|
|
feat: add Lua API modules and Script Manager UI (#161)
This commit adds the full Lua scripting API and integrates the Script Manager into the application.
It builds on top of the scripting engine introduced in #158, exposing all the API modules that Lua scripts can use and making everything accessible from the UI.
Changes:
- Added all Lua API modules: map, tile, item, brush, image, position, selection, creature, color, app, dialog, noise, algo, geo, json, http.
- Added map overlay system for scripts to draw on the map view.
- Added event system, context menu registration, persistent storage, and transaction support with undo/redo.
- Added support for package scripts (directory with manifest.lua) and script metadata tags.
- Added Scripts menu to the menubar with per-script execution and reload.
- Connected the Script Manager window to the UI.
- Added missing build dependencies and fixed MSVC compilation errors.
Notes:
- Build dependencies were added for HTTP and noise generation support.
- Some code was adjusted to compile correctly on MSVC.
2026-03-28 19:15:57 -03:00
|
|
|
bool Tile::removeItem(const Item* item) {
|
|
|
|
|
for (auto it = items.begin(); it != items.end(); ++it) {
|
|
|
|
|
if (*it == item) {
|
|
|
|
|
delete *it;
|
|
|
|
|
items.erase(it);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tile::clearGround() {
|
|
|
|
|
delete ground;
|
|
|
|
|
ground = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tile::replaceGround(Item* newGround) {
|
|
|
|
|
delete ground;
|
|
|
|
|
ground = newGround;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tile::clearMonsters() {
|
|
|
|
|
for (Monster* m : monsters) {
|
|
|
|
|
delete m;
|
|
|
|
|
}
|
|
|
|
|
monsters.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tile::clearSpawnMonster() {
|
|
|
|
|
delete spawnMonster;
|
|
|
|
|
spawnMonster = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::select() {
|
|
|
|
|
if (size() == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (ground) {
|
|
|
|
|
ground->select();
|
|
|
|
|
}
|
|
|
|
|
if (spawnMonster) {
|
|
|
|
|
spawnMonster->select();
|
|
|
|
|
}
|
|
|
|
|
if (spawnNpc) {
|
|
|
|
|
spawnNpc->select();
|
|
|
|
|
}
|
|
|
|
|
if (npc) {
|
|
|
|
|
npc->select();
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2024-10-02 16:01:28 -03:00
|
|
|
for (const auto monster : monsters) {
|
|
|
|
|
monster->select();
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
for (Item* item : items) {
|
2023-10-09 23:02:37 -03:00
|
|
|
item->select();
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
2016-09-29 19:24:45 -03:00
|
|
|
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::deselect() {
|
|
|
|
|
if (ground) {
|
|
|
|
|
ground->deselect();
|
|
|
|
|
}
|
|
|
|
|
if (spawnMonster) {
|
|
|
|
|
spawnMonster->deselect();
|
|
|
|
|
}
|
|
|
|
|
if (spawnNpc) {
|
|
|
|
|
spawnNpc->deselect();
|
|
|
|
|
}
|
|
|
|
|
if (npc) {
|
|
|
|
|
npc->deselect();
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2024-10-02 16:01:28 -03:00
|
|
|
for (const auto monster : monsters) {
|
|
|
|
|
monster->deselect();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (Item* item : items) {
|
2023-10-09 23:02:37 -03:00
|
|
|
item->deselect();
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
statflags &= ~TILESTATE_SELECTED;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-02 16:01:28 -03:00
|
|
|
Monster* Tile::getTopMonster() const {
|
|
|
|
|
return !monsters.empty() ? monsters.back() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<Monster*> Tile::popSelectedMonsters() {
|
|
|
|
|
std::vector<Monster*> popMonsters;
|
|
|
|
|
|
|
|
|
|
std::erase_if(monsters, [&](const auto monster) {
|
|
|
|
|
if (monster->isSelected()) {
|
|
|
|
|
popMonsters.emplace_back(monster);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
statflags &= ~TILESTATE_SELECTED;
|
|
|
|
|
return popMonsters;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<Monster*> Tile::getSelectedMonsters() {
|
|
|
|
|
std::vector<Monster*> selectedMonters;
|
|
|
|
|
std::copy_if(monsters.begin(), monsters.end(), std::back_inserter(selectedMonters), [](const auto monster) {
|
|
|
|
|
return monster->isSelected();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return selectedMonters;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Tile::isMonsterRepeated(const std::string &searchMonster) const {
|
|
|
|
|
return std::ranges::find_if(monsters, [&](const auto monster) {
|
|
|
|
|
return monster->getTypeName() == searchMonster;
|
|
|
|
|
})
|
|
|
|
|
!= monsters.end();
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
Item* Tile::getTopSelectedItem() {
|
|
|
|
|
for (auto it = items.rbegin(); it != items.rend(); ++it) {
|
|
|
|
|
if ((*it)->isSelected() && !(*it)->isMetaItem()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
return *it;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground && ground->isSelected() && !ground->isMetaItem()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
return ground;
|
|
|
|
|
}
|
2014-01-22 20:16:17 +01:00
|
|
|
return nullptr;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
ItemVector Tile::popSelectedItems(bool ignoreTileSelected) {
|
2012-06-29 16:44:26 +02:00
|
|
|
ItemVector pop_items;
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (!ignoreTileSelected && !isSelected()) {
|
|
|
|
|
return pop_items;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground && ground->isSelected()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
pop_items.push_back(ground);
|
2014-01-22 20:16:17 +01:00
|
|
|
ground = nullptr;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (auto it = items.begin(); it != items.end();) {
|
2023-10-09 23:02:37 -03:00
|
|
|
Item* item = (*it);
|
2023-10-09 19:12:16 -07:00
|
|
|
if (item->isSelected()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
pop_items.push_back(item);
|
2012-06-29 16:44:26 +02:00
|
|
|
it = items.erase(it);
|
|
|
|
|
} else {
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
statflags &= ~TILESTATE_SELECTED;
|
|
|
|
|
return pop_items;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
ItemVector Tile::getSelectedItems() {
|
2012-06-29 16:44:26 +02:00
|
|
|
ItemVector selected_items;
|
2016-09-29 19:24:45 -03:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (!isSelected()) {
|
|
|
|
|
return selected_items;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground && ground->isSelected()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
selected_items.push_back(ground);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (Item* item : items) {
|
|
|
|
|
if (item->isSelected()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
selected_items.push_back(item);
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
2016-09-29 19:24:45 -03:00
|
|
|
|
2012-06-29 16:44:26 +02:00
|
|
|
return selected_items;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
uint8_t Tile::getMiniMapColor() const {
|
|
|
|
|
if (minimapColor != INVALID_MINIMAP_COLOR) {
|
2018-04-22 10:54:06 -03:00
|
|
|
return minimapColor;
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
2018-04-22 10:54:06 -03:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (auto it = items.rbegin(); it != items.rend(); ++it) {
|
2023-10-09 23:02:37 -03:00
|
|
|
uint8_t color = (*it)->getMiniMapColor();
|
2023-10-09 19:12:16 -07:00
|
|
|
if (color != 0) {
|
2023-10-09 23:02:37 -03:00
|
|
|
return color;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-04-22 10:54:06 -03:00
|
|
|
|
2012-06-29 16:44:26 +02:00
|
|
|
// check ground too
|
2023-10-09 19:12:16 -07:00
|
|
|
if (hasGround()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
return ground->getMiniMapColor();
|
|
|
|
|
}
|
2018-04-22 10:54:06 -03:00
|
|
|
|
2012-06-29 16:44:26 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
void Tile::updateStateForItem(const Item* item, const ItemType &type) {
|
|
|
|
|
if (item->isSelected()) {
|
|
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
|
|
|
|
if (item->getUniqueID() != 0) {
|
|
|
|
|
statflags |= TILESTATE_UNIQUE;
|
|
|
|
|
}
|
|
|
|
|
if (type.sprite) {
|
|
|
|
|
const uint8_t color = type.sprite->getMiniMapColor();
|
|
|
|
|
if (color != 0) {
|
|
|
|
|
minimapColor = color;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (type.unpassable) {
|
|
|
|
|
statflags |= TILESTATE_BLOCKING;
|
|
|
|
|
}
|
|
|
|
|
if (type.isOptionalBorder) {
|
|
|
|
|
statflags |= TILESTATE_OP_BORDER;
|
|
|
|
|
}
|
|
|
|
|
if (type.isTable) {
|
|
|
|
|
statflags |= TILESTATE_HAS_TABLE;
|
|
|
|
|
}
|
|
|
|
|
if (type.isCarpet) {
|
|
|
|
|
statflags |= TILESTATE_HAS_CARPET;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tile::finalizeLoadedState() {
|
|
|
|
|
if ((statflags & TILESTATE_BLOCKING) == 0 && !ground && items.empty()) {
|
|
|
|
|
statflags |= TILESTATE_BLOCKING;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::update() {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags &= TILESTATE_MODIFIED;
|
feat: add Cyclopedia protobuf export pipeline (#160)
Add editor support for exporting Cyclopedia and CipSoft protobuf assets from the currently loaded map.
Main changes:
- Add File > Client Assets actions for Static House Data export, Cyclopedia minimap and satellite export, and restoring timestamped client asset backups.
- Keep generic minimap and tileset exports under File > Export.
- Export staticdata, staticmapdata, and mapdata protobuf files with content-hashed filenames.
- Update catalog-content.json so generated assets are picked up by the client.
- Merge compatible CipSoft templates when they match the loaded map.
- Fall back to generated data for custom maps instead of failing the export.
- Support filtered house exports.
- Report warnings for missing or failed static map entries.
- Emit aligned MINIMAP and sprite-based SATELLITE assets for the documented scales, including the 1/16 layer.
- Keep Cyclopedia export progress in the status bar instead of using a blocking modal progress dialog.
Performance:
- Precompute floor and chunk plans for global map exports.
- Write BMP output directly.
- Reuse minimap renders for matching satellite assets.
- Parallelize asset hash and LZMA encoding through a bounded worker queue.
- Remove modal progress overhead from the export path.
- Revert the tile-grid satellite optimization after profiling showed it shifted cost without improving total export time.
Documentation:
- Document the export contract in docs/static-data.md.
- Add docs/cyclopedia-export-roadmap.md with deferred optimization candidates and follow-up notes.
Scope:
- Focus this change on the Cyclopedia/staticdata protobuf export path and the export-specific performance work needed for practical global map exports.
- Move unrelated runtime, performance, and UI experiments out of this branch.
Validation:
- Ran static inspection and git diff checks during the export changes.
- Reviewed Visual Studio CPU profiles after each global map export performance pass.
- Verified hash and LZMA work moved into bounded async workers.
- Verified the restore action is labeled as restore and grouped under File > Client Assets, not File > Export.
This adds the editor-side pipeline needed to generate client Cyclopedia assets from a loaded map while keeping the export flow recoverable, documented, and practical for large maps.
2026-05-28 08:35:21 -03:00
|
|
|
minimapColor = INVALID_MINIMAP_COLOR;
|
2016-09-29 19:24:45 -03:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (spawnMonster && spawnMonster->isSelected()) {
|
2021-05-25 00:29:12 -03:00
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
if (spawnNpc && spawnNpc->isSelected()) {
|
2021-05-25 00:29:12 -03:00
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
2024-10-02 16:01:28 -03:00
|
|
|
if (!monsters.empty()) {
|
|
|
|
|
for (const auto monster : monsters) {
|
|
|
|
|
if (monster->isSelected()) {
|
|
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
if (npc && npc->isSelected()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground) {
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
const ItemType &groundType = ground->getItemType();
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground->isSelected()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
if (groundType.unpassable) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_BLOCKING;
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground->getUniqueID() != 0) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_UNIQUE;
|
|
|
|
|
}
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
if (groundType.sprite) {
|
|
|
|
|
const uint8_t color = groundType.sprite->getMiniMapColor();
|
|
|
|
|
if (color != 0) {
|
|
|
|
|
minimapColor = color;
|
|
|
|
|
}
|
2018-04-22 10:54:06 -03:00
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (const Item* item : items) {
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
const ItemType &type = item->getItemType();
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (item->isSelected()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
if (item->getUniqueID() != 0) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_UNIQUE;
|
|
|
|
|
}
|
perf: otbm load save and preview/map renderization (#188)
Improve OTBM load/save and map view performance
This change improves Remere's Map Editor performance in OTBM load/save paths,
object allocation, binary serialization, tile lookup, and idle map rendering.
Measured impact:
Object pool allocation:
- Slab refill events reduced from 17,830 to 2,230, about 87.5% fewer refills.
- 48-byte class refills reduced from 4,276 to 535, about 87.5% fewer refills.
- 64-byte class refills reduced from 5 to 1, about 80.0% fewer refills.
- 128-byte class refills reduced from 8,776 to 1,097, about 87.5% fewer refills.
- 1024-byte class refills reduced from 4,773 to 597, about 87.5% fewer refills.
- rme::allocatePooledObject sampled CPU share reduced from 20.01% to 14.62%,
about 26.9% lower sampled share.
- Total pooled allocation calls stayed at 42,559,971 for the measured workload.
- Heap fallback allocations stayed at 0, confirming the hot load path remains pooled.
Latest mixed load/save profile:
- GUI::LoadMap remained the dominant sampled cost at 67.02%.
- IOMapOTBM::loadMap accounted for 60.23% total sampled CPU, with 56.34% in
the inner load body.
- GUI::SaveMap and Editor::saveMap accounted for 28.16%.
- IOMapOTBM::saveMap accounted for 27.63%.
- BaseMap::forEachTileLocation during save accounted for 23.01%.
- Tile::Tile accounted for 11.53%.
- Tile::addLoadedItem accounted for 8.15%.
- Item::Create accounted for 6.99%.
- QTreeNode::createFloor accounted for 6.71%.
- BinaryNode::advance and BinaryNode::load accounted for 5.37% and 3.81%.
Map view idle and preview rendering:
- Static map-view sampled CPU dropped from 139,767 sampled units to 126 sampled
units after overlay-only refresh reuse.
- MapCanvas::OnPaint dropped from 46,229 sampled units and 32.20% to 19 sampled
units and 15.08%.
- GLRenderer::flushCommands dropped from 24,321 sampled units and 16.94% to
4 sampled units and 3.17%.
- Performance stats refresh changed from a 16 ms scene-dirty timer to a 500 ms
overlay-only timer.
- Show Preview changed from a 16 ms scene-dirty timer to a 250 ms scene-dirty
timer.
- Position indicator keeps the 16 ms scene-dirty timer because it is expected
to animate smoothly while active.
Main changes:
- Added cached floor and tile lookup while loading OTBM map data and spawn files.
- Added direct TileLocation assignment for parser paths that already resolved
the destination location.
- Added BaseMap::forEachTileLocation for direct save traversal of existing tile
locations.
- Added a small-object slab allocator for hot Item, Tile, and Floor allocations.
- Added pool owner-thread binding and diagnostics for allocation validation.
- Increased slab sizing to reduce refill pressure in large-map loads.
- Improved binary node writing by batching raw bytes and avoiding redundant cache
renewal checks.
- Avoided rewriting XML sidecar files when serialized content only differs by
line endings.
- Fixed invalid ground serialization so placeholder ground id 0 no longer drops
the rest of the tile contents during save.
- Split map canvas refresh into scene-dirty and overlay-only paths.
- Adjusted animation timer behavior for position indicator, Show Preview, and
performance stats.
- Scaled tooltip rendering with map zoom, clamped to 55% minimum.
- Kept review and Sonar cleanups away from hot path regressions with targeted
NOSONAR annotations or FORCEINLINE where needed.
- Added AGENTS.md guidance for future Git, build, and PCH discipline.
Notes:
- The Visual Studio captures are sampling profiles, so percentages represent CPU
sample share, not direct wall-clock speedup.
- The latest profile is a mixed interaction profile, not a strict load-only or
save-only benchmark.
- The allocator counters are the strongest before/after measurement in this
change.
- No OTBM format or map semantics are intended to change.
2026-05-22 15:14:34 -03:00
|
|
|
if (type.sprite) {
|
|
|
|
|
const uint8_t color = type.sprite->getMiniMapColor();
|
|
|
|
|
if (color != 0) {
|
|
|
|
|
minimapColor = color;
|
|
|
|
|
}
|
2018-04-22 10:54:06 -03:00
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (type.unpassable) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_BLOCKING;
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
if (type.isOptionalBorder) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_OP_BORDER;
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
if (type.isTable) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_HAS_TABLE;
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
if (type.isCarpet) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_HAS_CARPET;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if ((statflags & TILESTATE_BLOCKING) == 0) {
|
|
|
|
|
if (!ground && items.empty()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
statflags |= TILESTATE_BLOCKING;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::borderize(BaseMap* parent) {
|
2012-06-29 16:44:26 +02:00
|
|
|
GroundBrush::doBorders(parent, this);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::addBorderItem(Item* item) {
|
|
|
|
|
if (!item) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
ASSERT(item->isBorder());
|
|
|
|
|
items.insert(items.begin(), item);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
GroundBrush* Tile::getGroundBrush() const {
|
|
|
|
|
if (ground && ground->getGroundBrush()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
return ground->getGroundBrush();
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
2014-01-22 20:16:17 +01:00
|
|
|
return nullptr;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::cleanBorders() {
|
|
|
|
|
if (items.empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (auto it = items.begin(); it != items.end();) {
|
2023-10-09 23:02:37 -03:00
|
|
|
Item* item = (*it);
|
|
|
|
|
// Borders should only be on the bottom, we can ignore the rest of the items
|
2023-10-09 19:12:16 -07:00
|
|
|
if (!item->isBorder()) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-10-09 23:02:37 -03:00
|
|
|
|
|
|
|
|
delete item;
|
|
|
|
|
it = items.erase(it);
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::wallize(BaseMap* parent) {
|
2012-06-29 16:44:26 +02:00
|
|
|
WallBrush::doWalls(parent, this);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
Item* Tile::getWall() const {
|
|
|
|
|
for (Item* item : items) {
|
|
|
|
|
if (item->isWall()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
return item;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
2014-01-22 20:16:17 +01:00
|
|
|
return nullptr;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
Item* Tile::getCarpet() const {
|
|
|
|
|
for (Item* item : items) {
|
|
|
|
|
if (item->isCarpet()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
return item;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
2014-01-22 20:16:17 +01:00
|
|
|
return nullptr;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
Item* Tile::getTable() const {
|
|
|
|
|
for (Item* item : items) {
|
|
|
|
|
if (item->isTable()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
return item;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
2014-01-22 20:16:17 +01:00
|
|
|
return nullptr;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::addWallItem(Item* item) {
|
|
|
|
|
if (!item) {
|
2012-06-29 16:44:26 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ASSERT(item->isWall());
|
|
|
|
|
|
|
|
|
|
addItem(item);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::cleanWalls(bool dontdelete) {
|
|
|
|
|
if (items.empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (auto it = items.begin(); it != items.end();) {
|
2023-10-09 23:02:37 -03:00
|
|
|
Item* item = (*it);
|
2023-10-09 19:12:16 -07:00
|
|
|
if (item && item->isWall()) {
|
|
|
|
|
if (!dontdelete) {
|
2023-10-09 23:02:37 -03:00
|
|
|
delete item;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
it = items.erase(it);
|
2023-10-09 23:02:37 -03:00
|
|
|
} else {
|
2023-10-09 19:12:16 -07:00
|
|
|
++it;
|
2023-10-09 23:02:37 -03:00
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::cleanWalls(WallBrush* brush) {
|
2012-06-29 16:44:26 +02:00
|
|
|
ItemVector::iterator it;
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (auto it = items.begin(); it != items.end();) {
|
2023-10-09 23:02:37 -03:00
|
|
|
Item* item = (*it);
|
2023-10-09 19:12:16 -07:00
|
|
|
if (item && item->isWall() && brush->hasWall(item)) {
|
2023-10-09 23:02:37 -03:00
|
|
|
delete item;
|
2012-06-29 16:44:26 +02:00
|
|
|
it = items.erase(it);
|
2023-10-09 23:02:37 -03:00
|
|
|
} else {
|
|
|
|
|
++it;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::cleanTables(bool dontdelete) {
|
|
|
|
|
if (items.empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (auto it = items.begin(); it != items.end();) {
|
2023-10-09 23:02:37 -03:00
|
|
|
Item* item = (*it);
|
2023-10-09 19:12:16 -07:00
|
|
|
if (item && item->isTable()) {
|
|
|
|
|
if (!dontdelete) {
|
2023-10-09 23:02:37 -03:00
|
|
|
delete item;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
it = items.erase(it);
|
2023-10-09 23:02:37 -03:00
|
|
|
} else {
|
|
|
|
|
++it;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::tableize(BaseMap* parent) {
|
2012-06-29 16:44:26 +02:00
|
|
|
TableBrush::doTables(parent, this);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::carpetize(BaseMap* parent) {
|
2012-06-29 16:44:26 +02:00
|
|
|
CarpetBrush::doCarpets(parent, this);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::selectGround() {
|
2023-10-09 23:02:37 -03:00
|
|
|
bool selected = false;
|
2023-10-09 19:12:16 -07:00
|
|
|
if (ground) {
|
2012-06-29 16:44:26 +02:00
|
|
|
ground->select();
|
2023-10-09 23:02:37 -03:00
|
|
|
selected = true;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
ItemVector::iterator it;
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
for (Item* item : items) {
|
|
|
|
|
if (!item->isBorder()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
break;
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
2023-10-09 23:02:37 -03:00
|
|
|
item->select();
|
|
|
|
|
selected = true;
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
2023-10-09 23:02:37 -03:00
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
if (selected) {
|
|
|
|
|
statflags |= TILESTATE_SELECTED;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::deselectGround() {
|
|
|
|
|
if (ground) {
|
2012-06-29 16:44:26 +02:00
|
|
|
ground->deselect();
|
|
|
|
|
}
|
2023-10-09 19:12:16 -07:00
|
|
|
for (Item* item : items) {
|
|
|
|
|
if (!item->isBorder()) {
|
2012-06-29 16:44:26 +02:00
|
|
|
break;
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
2023-10-09 23:02:37 -03:00
|
|
|
|
|
|
|
|
item->deselect();
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::setHouse(House* house) {
|
2023-10-09 23:02:37 -03:00
|
|
|
house_id = (house ? house->id : 0);
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::addHouseExit(House* house) {
|
|
|
|
|
if (!house) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-10-09 23:02:37 -03:00
|
|
|
|
|
|
|
|
HouseExitList* exits = location->createHouseExits();
|
|
|
|
|
exits->push_back(house->id);
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
void Tile::removeHouseExit(House* house) {
|
|
|
|
|
if (!house) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-12-06 11:42:37 -03:00
|
|
|
|
2023-10-09 23:02:37 -03:00
|
|
|
HouseExitList* exits = location->getHouseExits();
|
2023-10-09 19:12:16 -07:00
|
|
|
if (!exits || exits->empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
|
2023-10-09 23:02:37 -03:00
|
|
|
auto it = std::find(exits->begin(), exits->end(), house->id);
|
2023-10-09 19:12:16 -07:00
|
|
|
if (it != exits->end()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
exits->erase(it);
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
2012-06-29 16:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-09 19:12:16 -07:00
|
|
|
bool Tile::hasHouseExit(uint32_t houseId) const {
|
2023-10-09 23:02:37 -03:00
|
|
|
const HouseExitList* exits = getHouseExits();
|
2023-10-09 19:12:16 -07:00
|
|
|
if (!exits || exits->empty()) {
|
2023-10-09 23:02:37 -03:00
|
|
|
return false;
|
2023-10-09 19:12:16 -07:00
|
|
|
}
|
2023-10-09 23:02:37 -03:00
|
|
|
|
|
|
|
|
auto it = std::find(exits->begin(), exits->end(), houseId);
|
|
|
|
|
return it != exits->end();
|
|
|
|
|
}
|