Closed igorko closed 10 years ago
Update: The file has been renamed to MapRenderer.cpp and the line is about 1230 now.
I've worked bit on it, but never got to finished it. Since it is clearly ownership issue - I've taken "brute force" approach to the problem and added simple RefPtr (which every respectful C++ project has in some form, so why flare wouldn't? :D) . It still needs some testing, cleanups, so I am not pushing it here. Also since recently got very little time for hacking on this, wanted to ensure that we want to go this route...
Pasted diff-stats so we know about what kind of invasive change we are talking:
commit 41707de30fc40c01d69d194d2b84014cf9a63c1d Author: Piotr Rak piotr.rak@gmail.com Date: Thu Dec 27 16:10:15 2012 +0100
Add simple RefPtr.
src/Utils.h | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+)
I am feeling bad taste in my mouth after comiting this one somehow :S.
And mostly mechanical huge commit ala s/stat./stat->/
commit 5cfc50018490c93d87a5324d3ce590a849c617fd Author: Piotr Rak piotr.rak@gmail.com Date: Thu Dec 27 18:20:23 2012 +0100
Use RefPtr for StatBlock.
Fixes #122.
src/Avatar.cpp | 438 +++++++++++++++++++++++----------------------- src/Avatar.h | 4 +- src/BehaviorStandard.cpp | 264 ++++++++++++++-------------- src/CampaignManager.h | 2 +- src/Enemy.cpp | 136 +++++++------- src/EnemyManager.cpp | 75 ++++---- src/Entity.cpp | 41 ++--- src/Entity.h | 2 +- src/GameStateNew.cpp | 10 +- src/GameStatePlay.cpp | 122 ++++++------- src/Hazard.cpp | 1 + src/Hazard.h | 2 +- src/HazardManager.cpp | 8 +- src/ItemManager.cpp | 2 +- src/ItemManager.h | 2 +- src/LootManager.cpp | 36 ++-- src/LootManager.h | 4 +- src/MapRenderer.cpp | 4 +- src/MenuActionBar.cpp | 2 +- src/MenuActionBar.h | 4 +- src/MenuActiveEffects.cpp | 2 +- src/MenuActiveEffects.h | 4 +- src/MenuCharacter.cpp | 3 +- src/MenuCharacter.h | 4 +- src/MenuEnemy.cpp | 14 +- src/MenuInventory.cpp | 2 +- src/MenuInventory.h | 4 +- src/MenuItemStorage.cpp | 2 +- src/MenuItemStorage.h | 2 +- src/MenuManager.cpp | 2 +- src/MenuManager.h | 4 +- src/MenuPowers.cpp | 2 +- src/MenuPowers.h | 4 +- src/MenuStash.cpp | 3 +- src/MenuStash.h | 4 +- src/MenuVendor.cpp | 2 +- src/MenuVendor.h | 4 +- src/NPCManager.cpp | 2 +- src/NPCManager.h | 4 +- src/PowerManager.cpp | 28 +-- src/PowerManager.h | 28 +-- src/SaveLoad.cpp | 114 ++++++------ src/StatBlock.h | 2 +- src/Utils.h | 4 +- 44 files changed, 699 insertions(+), 704 deletions(-)
Pretty sane alternative to mine NIH RefPtr would be go for tr1::shared_ptr if it isn't to new. It's been available in gcc-4.1.2 in somewhat usable form, also supported by MSVC++ quite early too (can't remember exact version).
So general question is - do we want duck typing destructors with delete, or pay price of reference counting? TBH: I would go for std::unique_ptr which is much cheaper and we could use in most of places, but it is c++11.
Please let me know, if you think it's worth it, or better to hack-around this one, if we want this fixed for release I'll try to find some time soon.
With the engine being so close to feature-completeness, we have to consider that we have precisely one obvious case for a RefPtr. For now I'm holding out for a more specific solution to this single issue.
Sure, that's why I've asked. I'll revisit it sometime in future.
697016d LGTM, however it might get little confusing with time in regard to copy-ctrors. Please note that refCounter will be copied too if you do:
StatBlock newstats = new StatBlock(*oldstats); newStats->getRef() == oldstats->getRef();
and I believe it shouldn't be the case. Also little nitpick, about refCounter initialization (I've added inline comment).
With apologies to everyone who's worked on this: I believe I've figured out a correct solution to the root of the problem.
We want map events to use powers (e.g. for traps) but before we weren't treating the map events as persistent "entities" that have a permanent statblock. So every time the trap fired we were creating a StatBlock which would never get deleted.
The fix: Add a StatBlock * to the Map Event class (default null). After loading a map, look through each map event to find ones that need a StatBlock (as in traps). Allocate a new StatBlock for them.
Now we're creating those StatBlocks on map load (one per event that needs one) instead of every time the event activates.
When it's time to unload a map, delete all those non-null StatBlocks pointers.
Advantages:
This makes indeed sense to me while reading it the first time.
I implemented the idea @clintbellanger had. However I modified the idea a little. The memory allocation for the statblock belonging to the map events is not done beforehand, but lazily, i.e. when the statblock is needed the first time. This makes the implementation super easy, as we do not need to iterate over the events beforehand and decide whether we need to allocate a statblock.
The StatBlock leak is still present. It might be because it's late, but I can't see why its not getting deleted when we erase events.
However, I think if event erasing was functioning properly, we'd get a segfault when deleting events. Hazards last an arbitrary amount of time and require a StatBlock pointer. So if the event gets deleted before the hazard is done, that's invalid access.
I have a rough idea of how we can sidestep all of this and add some more flexibility. I propose we allow loading a set of stat files (use the StatBlock load code) that get loaded on map load. These can then be referenced by events that use power
. The StatBlocks would be stored in a vector that is a member of the Map class. This has some advantages:
Migrated from clintbellanger/flare#256
Powers and Hazards assume a live StatBlock pointer.
MapIso.cpp around line 800 we create a dummy StatBlock for map-generated powers (e.g. traps). Once that data reaches the Hazard level, I think it's mainly only used to carry the Accuracy stat.
The issue is that we're not currently deleting the dummy pointer, so it's causing a tiny memory leak. We need to be deleting that right after the powers->activate() call.
Make it so that Hazards aren't absolutely dependent on having a StatBlock. Check the Hazard code and the TakeHit code. Perhaps for Map-generated powers we give Hazard a NULL statblock. Give Hazards a 100% accuracy flag for map events. In the Hazard and TakeHit code, always check to see if statblock is NULL before using it.