Caveman 2 Cosmos (ideas/discussions thread)

TB can correct me if im wrong but I think there is an array (list) of true/false or a 1/0 for each building in each city to record if the building is built whether or not its active/obsolete. The XML part will be remembered once plus 1 num per city, theres a canBuildCache, and probably a couple things im missing. if I can have an opinion I think going big on the XML was the right move. A piece of XML is worth the little bit of memory. The SpyUtility in Python -> BUG seems to be unused. It seems to keep a second record of espionage for some reason. how bout the unusable xml for the npc leaders? I think u guys should enable it or remove it. I already mentioned the defaults in BugGameUtil. How about the mountain leaders? isn't that promo a not so good option now?
Spoiler CvPlot.h :

Code:
    //    Koshling - need to cache presence of mountain leaders in mountain
    //    plots so that CanMoveThrough calculations don't get bogged down
    //    searching unit stacks.  This is a count of mountain leader units
    //    in the plot for each team.  The array is only created if the plot is
    //    a mountain plot and at least one team has a mountain leader present.
    //    The array is cleared when the last leader leaves, so the memory overhead is
    //    low
    short* m_aiMountainLeaderCount;
 
Regarding cultural merchant types, have you been able to get to them with the cutlure rewrites I remember being planned or did you not get to them in favor of other avenues?
 
I at least believe we are at a point where we should really focus more on quality rather than quantity.
Yeah, I have no problem with a few extra buildings coming in now and then, but I'm more interested in seeing us try to improve the overall use of buildings in the mod in some areas and rebalancing decisions. A given building is not a culprit of slowdown but all together, the mass of them is part of that problem, though there probably are some things we can do to improve processing in those regards.
if I can have an opinion I think going big on the XML was the right move.
Not sure I'm clear on what you mean here.
The SpyUtility in Python -> BUG seems to be unused. It seems to keep a second record of espionage for some reason.
I'm not at all familiar with this. If it's completely vestigial and unused now, sure, we should get rid of it since in all the time I've been here I've seen no interactive use in it.
how bout the unusable xml for the npc leaders?
What unusable XML? I haven't yet evaluated leaders as much as I intend to at some point and maybe you're pointing at some leftovers from a project that never got off the ground fully...dunno. Leader entries don't cycle too much in the code so we wouldn't stand to lose much time delay and though we might lose some memory there, not too much since there aren't many iterations of leaders in use in the game like with units and plots. Buildings or units would be a better place to shave. Building entries themselves have more impact on slowdown because of all the very many loops through cities to check for the existence of buildings there (autobuildings used as city condition tags add a lot of slowdown here and we might be better off building out a new city status boolean vector or something for this purpose which would save a lot of memory and time.)
How about the mountain leaders? isn't that promo a not so good option now?
I think this is still quite functional and effective as applied in the game. What makes you think it's a bad option?
Regarding cultural merchant types, have you been able to get to them with the culture rewrites I remember being planned or did you not get to them in favor of other avenues?
Merchants did pick up cultural variations. Not all cultural units have been adapted to some of the proposals that have been made on them in the past and it's STILL on my list of tasks to eventually look into that proposal set and implement as much as I can. I've been feeling I should get to the full core unit rework first, which could really tweak the plans on those.
 
Merchants did pick up cultural variations. Not all cultural units have been adapted to some of the proposals that have been made on them in the past and it's STILL on my list of tasks to eventually look into that proposal set and implement as much as I can. I've been feeling I should get to the full core unit rework first, which could really tweak the plans on those.

So the fact that they're more expensive than the same tier trade caravans is intentional as of the moment?
 
The SpyUtility in Python -> BUG seems to be unused. It seems to keep a second record of espionage for some reason.
SpyUtil.py isn't used for anything with PPIO, but without PPIO it is actually used by the espionage advisor python code.
So to remove it in the core one would have to make some changes to the CvEspionageAdvisor.py file to accommodate it.

I guess I can change PPIO to stop the game from loading those files (SpyUtil.py and "Better Espionage.xml") at all.
 
Last edited:
MattCA said:
How about the mountain leaders? isn't that promo a not so good option now?
Click to expand...
I think this is still quite functional and effective as applied in the game. What makes you think it's a bad option?

no idea nevermind that 1.

SpyUtil.py isn't used for anything with PPIO, but without PPIO it is actually used by the espionage advisor python code.
So to remove it in the core one would have to make some changes to the CvEspionageAdvisor.py file to accommodate it.

I guess I can change PPIO to stop the game from loading those files (one xml and one py) at all.

hmm I think ill look again. maybe parts are good.

what about sevopedia? does your pedia use parts of it?

the XML is just this bit here. im pretty sure whats in Define.h is whats being used.
Code:
    <Define>
        <DefineName>AGGRESSIVE_ANIMAL_CIVILIZATION</DefineName>
        <DefineTextVal>CIVILIZATION_ANIMAL_PREDATOR</DefineTextVal>
    </Define>
    <Define>
        <DefineName>AGGRESSIVE_ANIMAL_LEADER</DefineName>
        <DefineTextVal>LEADER_GREEN_MAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>PASSIVE_ANIMAL_CIVILIZATION</DefineName>
        <DefineTextVal>CIVILIZATION_ANIMAL_PREY</DefineTextVal>
    </Define>
    <Define>
        <DefineName>PASSIVE_ANIMAL_LEADER</DefineName>
        <DefineTextVal>LEADER_GREEN_MAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC8_CIVILIZATION</DefineName>
        <DefineTextVal>CIVILIZATION_ANIMAL_BEAST</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC8_LEADER</DefineName>
        <DefineTextVal>LEADER_GREEN_MAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC7_CIVILIZATION</DefineName>
        <DefineTextVal>CIVILIZATION_NPC_NEANDERTHAL</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC7_LEADER</DefineName>
        <DefineTextVal>LEADER_NEANDERTHAL</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC6_CIVILIZATION</DefineName>
        <DefineTextVal>CIVILIZATION_INSECTOID</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC6_LEADER</DefineName>
        <DefineTextVal>LEADER_BARBARIAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC1_CIVILIZATION</DefineName>
        <DefineTextVal>CIVILIZATION_BARBARIAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC1_LEADER</DefineName>
        <DefineTextVal>LEADER_BARBARIAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC2_CIVILIZATION</DefineName>
        <DefineTextVal>CIVILIZATION_BARBARIAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC2_LEADER</DefineName>
        <DefineTextVal>LEADER_BARBARIAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC3_CIVILIZATION</DefineName>
        <DefineTextVal>CIVILIZATION_BARBARIAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC3_LEADER</DefineName>
        <DefineTextVal>LEADER_BARBARIAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC4_CIVILIZATION</DefineName>
        <DefineTextVal>CIVILIZATION_BARBARIAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC4_LEADER</DefineName>
        <DefineTextVal>LEADER_BARBARIAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC5_CIVILIZATION</DefineName>
        <DefineTextVal>CIVILIZATION_BARBARIAN</DefineTextVal>
    </Define>
    <Define>
        <DefineName>NPC5_LEADER</DefineName>
        <DefineTextVal>LEADER_BARBARIAN</DefineTextVal>
    </Define>
 
what about sevopedia? does your pedia use parts of it?
Only CvEspionageAdvisor.py use SpyUtil.py.
the XML is just this bit here. im pretty sure whats in Define.h is whats being used.
CvGame.cpp does use the values within that xml.
e.g. else if (ePlayer == AGGRESSIVE_ANIMAL_PLAYER && GC.getDefineINT("AGGRESSIVE_ANIMAL_CIVILIZATION") != GC.getDefineINT("BARBARIAN_CIVILIZATION"))
The blue one is defined in the CvDefines.h
The green ones are fetched from GlobalDefines.xml
 
interesting. Im pretty sure the last 2 will never change values and will never be equal so the second half is a useless check.

EDIT: turns out its the opposite. False. none of that passes. so you have xml that get loaded then code in CvGame to make sure its not used. But after checking that I realize I actually don't remember what I did. so nevermind maybe
 
Last edited:
So the fact that they're more expensive than the same tier trade caravans is intentional as of the moment?
That's always the case with cultural units vs the core ones they are based on - but all of them have benefits over their contemporaries, including adjustments to their trade outputs that compare to the adjusted production costs.
 
So, in the main C2C thread, there was a mention of how steel is not very useful when first discovered (late medieval), and doesn't become useful until the industrial era. What if there "copies" of certain units, like "iron swordsman" and "steel swordsman"? Or perhaps there could be a building (steel shop?) that requires steel, and provides a custom "steel weapons/armor" promotion to certain units that boosts strength.
 
So, in the main C2C thread, there was a mention of how steel is not very useful when first discovered (late medieval), and doesn't become useful until the industrial era. What if there "copies" of certain units, like "iron swordsman" and "steel swordsman"? Or perhaps there could be a building (steel shop?) that requires steel, and provides a custom "steel weapons/armor" promotion to certain units that boosts strength.
Equipment mod has been in devel for years. It may see the light of day at some point.
 
Equipment mod has been in devel for years. It may see the light of day at some point.
Meanwhile we do have promos like VCrakeV has suggested. Poison Tips, Bamboo Armour, Copper Plating and Wootz Steel to name a few.

A few more wouldn't hurt...
 
Meanwhile we do have promos like VCrakeV has suggested. Poison Tips, Bamboo Armour, Copper Plating and Wootz Steel to name a few.

A few more wouldn't hurt...
All of those will be removed. I don't make a practice of working on things that fill in for now when a planned future will eliminate what I'm working on.
 
All of those will be removed. I don't make a practice of working on things that fill in for now when a planned future will eliminate what I'm working on.

Would you not build a quern, knowing you will eventually replace it with a donkey mill? So long as it's not particularly laborious or tedious, I don't see why we shouldn't make measures to improve the game in the short term, even if these measures would become redundant in the long term. Based on what you said, it seems the wait for the equipment mod could be long enough to make another equipment building worthwhile.
 
Would you not build a quern, knowing you will eventually replace it with a donkey mill? So long as it's not particularly laborious or tedious, I don't see why we shouldn't make measures to improve the game in the short term, even if these measures would become redundant in the long term. Based on what you said, it seems the wait for the equipment mod could be long enough to make another equipment building worthwhile.
If someone else wants to do it, I won't tell them not to.
 
You are right that as there is currently no consideration about when a unit is accessed, this would likely cause huge slowdowns and that despite being a huge effort in implementing it.


The reduction of the amount of memory used up by units is definitely the low hanging fruit here. As a first step you could check if a lot of the ints in there actually need to be ints or if they can be shorter (might need pragma pack to get an actual result). Or you could pack bools into bits. Especially if they are rarely accessed so the potentially slower access matters less.
Then you could split off more of the data that tends to be the default value for most units into one or more separate structs similar to how the keyed infos are done (e.g. info that is only used for a specific type of unit).
Another optimization possibility is that a lot of those structs that can be split off have the same value for a lot of units (as the value comes from the unit type and maybe a promotion or two). It is possible to store that value in a map as key with a reference count as value (so you can delete it if it is no more referenced) as then a simple pointer to that map entry can be stored in the unit itself. The difficulty about that is that you cannot simply change the value in there then but instead each time you change something in that struct for one unit you have to create a new separate entry (potentially deleting the old one). This would not be that great currently as there are a lot of changes to single values while the unit is created.

I won't pretend I completely understand your suggestions but I think I get an inkling about what you're suggesting and I might be able to eventually research my way through to a deeper grasp of it.

The first suggestion is the easiest. Consider if you really need 32 bit integers for each of the entries variables in a unit. If the value never gets larger than 32k, then a 16 bit integer (short, but I prefer typedefs like int16_t) is enough to store it. If the value is always smaller than 255, then an 8 bit integer (signed char, or better a typedef like int8_t) is sufficient. Of course that change can introduce subtle overflow buffs and integer promotion rules can be weird.
Bools only store true/false, so they can be stored in 1 bit instead of 1 byte. The easiest way to get that effect is to group them into a bit field inside the class. The disadvantage is that access to that kind of compressed bool is slower.

The second suggestion is still rather easy. Move some of the data to a separate struct, then only store the pointer to that struct within the unit class. If the values in the struct are all default, then you don't allocate the struct and just point to NULL. That way you save memory if most units don't have that separate struct.

The third is more complicated so should only be considered as a second step.

I can't help you with where it is in the code, but this method is used for the setting that determines what city buildings are graphically represented on the map.
(Something along the lines of:
if bit 0 only is set, the integer has the value 1, and this means show only military buildings
if bit 1 only is set, integer has value 2, and only religious buildings are displayed
at integer value 3, both these 'bools' are 'true', so only military AND religious buildings are represented.
Etc.)
These are probably not the actual uses of these bits, 8 bits in all are used although valid values only go up to about 131 (ie. 10000011 binary)

Yes, that is how you do it manually. Very commonly used while programming on microcontrollers where RAM is at a premium (on Cortex-M4 you usually have something like 128KB) and hardware peripherals are accessed with registers that pack a lot of different info or settings into 32 bits.
The easier way to get that without masking and shifting yourself is to use bit fields. In bit fields you specify for each variable how many bits it should occupy. That way you can also have integers with uncommon sizes. You access them like normal variables but the compiler will generate different code, which is usually slower. The main difference is that you can't take the address of these variables (they don't occupy a full byte after all). So for the save/load code you need to change it to load into a normal local variable before storing it into the bit field variable.
Bit fields are declared like normal variables except with the size in bits of the variable added at the end:
Code:
struct Foo
{
  bool b1 : 1;
  bool b2 : 1;
  int veryshort : 3;
}
You should probably group all variables that get the bit field treatment within the class.
One of the disadvantages of bit fields is that a lot of it is implementation defined so the compiler is not under an obligation to really pack the variables and might sometimes align them for faster access but more space usage.
This means that you should check the real size before and after with sizeof.

Much of what you said there, Bit field treatment, grouping variables, Implementation defined, pack the variables, sizeof, is Greek, but I think I get the idea of the struct somewhat. The operator ':' apparently is there to define the bit space that a variable takes up? Why wouldn't bools already only be 1?

Does : only work within the span of a struct definition? Or does that work anywhere where a variable is declared?

I think these should work for the first idea. If anyone sees a mistake let me know.
Spoiler :

//!===================================
//! typedef int16_t (32,000)
//!===================================
int m_iX;
int m_iY;
int m_iReconX;
int m_iReconY;
int m_iAttackPlotX;
int m_iAttackPlotY;
int m_iGameTurnCreated;
int m_iLastMoveTurn;
int m_iLevel;
int m_iControlPointsLeft;
int m_iAttackFromPlotX;
int m_iAttackFromPlotY;
int m_iMADTargetPlotX;
int m_iMADTargetPlotY;
int m_iExtraWorkPercent;
int m_iExtraCityAttackPercent;
int m_iExtraCityDefensePercent;
int m_iExtraHillsAttackPercent;
int m_iExtraHillsDefensePercent;
int m_iExtraHillsWorkPercent;
int m_iExtraPeaksWorkPercent;

//!===================================
//! typedef int8_t (255)
//!===================================
int m_iCanMovePeaksCount;
int m_iCanLeadThroughPeaksCount;
int m_iKamikazePercent;
int m_iMoves;
int m_iExtraMoves;
int m_iExtraMoveDiscount;
int m_iExtraAirRange;
int m_iAmphibCount;
int m_iZoneOfControlCount;
int m_iCelebrityHappy;
int m_iOffensiveVictoryMoveCount;
int m_iOneUpCount;
int m_iBlitzCount;
int m_iRiverCount;
int m_iIgnoreZoneofControlCount;
int m_iPillageCultureCount;
int m_iPillageEspionageCount;
int m_iPillageMarauderCount;
int m_iPillageOnMoveCount;
int m_iPillageOnVictoryCount;
int m_iPillageResearchCount;
int m_iHillsDoubleMoveCount;
int m_iBaseDCMBombRange;

bit field thing sounds interesting. Ill make an attempt at some point.

Any normal variable has to be addressable and you can only address bytes, not bits. That and speed is the reason that bools are at least 1 byte and not 1 bit in size. There is std::vector<bool> which actually packs the bools into bits but that is generally considered a mistake nowadays (more so because it makes it so different from the other vectors, not because it is a bad idea to pack bools into bits in large vectors).
But yes, the number after ':' specifies the number of bits assigned to that variable within the bit field. You can only have bit fields within structs or classes.

Please have this discussion in its own thread! Here it will never be found anymore in a few months or years.

Was thinking similar thoughts about that. I'd appreciate it if someone could take the time to quote this tech discussion into a new thread. I also hope AIAndy would be kind enough to continue the discussion there because I have lots more questions about this stuff and am currently reluctant to get too deep into this here. Thank you very much for your guidance so far @AIAndy - I'm surprised by how much this is making sense actually. Very interesting stuff to know. I'm also very wary of trying to implement any of it for fear of stepping into complex debugging territory where I'd want to just rage quit the whole project over it. lol. I'm not budgeting as much time and dedication to the project these days so small investments of effort that can make impacts here and there without being likely to cause a huge problem are certainly of interest but sweeping restructures are... intimidating.

The size of a CvUnit itself is only one part of the story you can't forget the memory consumed for things like textures the graphics engine itself.
Even if you reduce the size of every CvUnit by 200 byte by using smaller data types that would only make 200 kilobyte memory saving in a game with 1000 units.

The first thing that would make any sense at all would be to look at these because every Unit has multiple instances of these objects:
Code:
class PromotionKeyedInfo
{
public:
    PromotionKeyedInfo() :    m_bHasPromotion(false),
                            m_iAfflictOnAttackCount(0),
                            m_iCureAfflictionCount(0),
                            m_iAfflictionTurnCount(0),
                            m_iAfflictionHitCount(0),
                            m_iAfflictionTolerance(0),
                            m_iFortitudeModifierTypeAmount(0),
                            m_iPromotionFreeCount(0),
                            m_iTrapSetWithPromotionCount(0),
                            m_iPromotionFromTraitCount(0)
    {
    }

    bool Empty() const
    {
        return (!m_bHasPromotion &&
            m_iAfflictOnAttackCount == 0 &&
            m_iCureAfflictionCount == 0 &&
            m_iAfflictionTurnCount == 0 &&
            m_iAfflictionHitCount == 0 &&
            m_iAfflictionTolerance == 0 &&
            m_iFortitudeModifierTypeAmount == 0 &&
            m_iPromotionFreeCount == 0 &&
            m_iTrapSetWithPromotionCount == 0 &&
            m_iPromotionFromTraitCount == 0);
    }

    //TB Combat Mods Begin
    bool    m_bHasPromotion;
    int        m_iAfflictOnAttackCount;
    int        m_iCureAfflictionCount;
    int        m_iAfflictionTurnCount;
    int        m_iAfflictionHitCount;
    int        m_iAfflictionTolerance;
    int        m_iFortitudeModifierTypeAmount;
    int        m_iPromotionFreeCount;
    int        m_iTrapSetWithPromotionCount;
    int        m_iPromotionFromTraitCount;
};

typedef std::map<PromotionTypes, PromotionKeyedInfo>::iterator PromotionIterator;

class PromotionLineKeyedInfo
{
public:
    PromotionLineKeyedInfo() :    m_iCureAfflictionTypeCount(0),
                                m_iAfflictionTurnTypeCount(0),
                                m_iAfflictionLineCount(0),
                                m_iAfflictionTypeTolerance(0),
                                m_iFortitudeModifierAmount(0),
                                m_iAfflictOnAttackTypeProbability(0),
                                m_iAfflictOnAttackTypeCount(0),
                                m_iAfflictOnAttackTypeImmediateCount(0),
                                m_iAfflictOnAttackTypeAttemptedCount(0),
                                m_iDistanceAttackCommunicability(0),
                                m_bValidBuildUp(false),
                                m_iAfflictOnAttackTypeMeleeCount(0),
                                m_iAfflictOnAttackTypeDistanceCount(0)
    {   
    }

    bool Empty() const
    {
        return (m_iCureAfflictionTypeCount == 0 &&
            m_iAfflictionTurnTypeCount == 0 &&
            m_iAfflictionLineCount == 0 &&
            m_iAfflictionTypeTolerance == 0 &&
            m_iFortitudeModifierAmount == 0 &&
            m_iAfflictOnAttackTypeProbability == 0 &&
            m_iAfflictOnAttackTypeCount == 0 &&
            m_iAfflictOnAttackTypeImmediateCount == 0 &&
            m_iAfflictOnAttackTypeAttemptedCount == 0 &&
            m_iDistanceAttackCommunicability == 0 &&
            !m_bValidBuildUp &&
            m_iAfflictOnAttackTypeMeleeCount == 0 &&
            m_iAfflictOnAttackTypeDistanceCount == 0);
    }

    int        m_iCureAfflictionTypeCount;
    int        m_iAfflictionTurnTypeCount;
    int        m_iAfflictionLineCount;
    int        m_iAfflictionTypeTolerance;
    int        m_iFortitudeModifierAmount;
    int        m_iAfflictOnAttackTypeProbability;
    int        m_iAfflictOnAttackTypeCount;
    int        m_iAfflictOnAttackTypeImmediateCount;
    int        m_iAfflictOnAttackTypeAttemptedCount;
    int        m_iDistanceAttackCommunicability;
    bool    m_bValidBuildUp;
    int        m_iAfflictOnAttackTypeMeleeCount;
    int        m_iAfflictOnAttackTypeDistanceCount;
};

class TerrainKeyedInfo
{
public:
    TerrainKeyedInfo() :    m_iTerrainProtected(0),
                            m_iTerrainDoubleMoveCount(0),
                            m_iExtraTerrainAttackPercent(0),
                            m_iExtraTerrainDefensePercent(0),
                            m_iTerrainWorkPercent(0),
//Team Project (4)
    //WorkRateMod
                            m_iExtraTerrainWorkPercent(0),
                            m_iExtraWithdrawOnTerrainType(0)
    {
    }

    bool Empty() const
    {
        return (m_iTerrainProtected == 0 &&
            m_iTerrainDoubleMoveCount == 0 &&
            m_iExtraTerrainAttackPercent == 0 &&
            m_iExtraTerrainDefensePercent == 0 &&
            m_iTerrainWorkPercent == 0 &&
            m_iExtraTerrainWorkPercent == 0 &&
            m_iExtraWithdrawOnTerrainType == 0);
    }

    int    m_iTerrainProtected;
    int    m_iTerrainDoubleMoveCount;
    int    m_iExtraTerrainAttackPercent;
    int    m_iExtraTerrainDefensePercent;
    //ls612: Terrain Work Modifiers
    int m_iTerrainWorkPercent;
//Team Project (4)
    //WorkRateMod
    int m_iExtraTerrainWorkPercent;
    int m_iExtraWithdrawOnTerrainType;
};

class FeatureKeyedInfo
{
public:
    FeatureKeyedInfo() :    m_iFeatureDoubleMoveCount(0),
                            m_iExtraFeatureAttackPercent(0),
                            m_iExtraFeatureDefensePercent(0),
                            m_iFeatureWorkPercent(0),
//Team Project (4)
    //WorkRateMod
                            m_iExtraFeatureWorkPercent(0),
                            m_iExtraWithdrawOnFeatureType(0)
    {
    }

    bool Empty() const
    {
        return (m_iFeatureDoubleMoveCount == 0 &&
            m_iExtraFeatureAttackPercent == 0 &&
            m_iExtraFeatureDefensePercent == 0 &&
            m_iFeatureWorkPercent == 0 &&
            m_iExtraFeatureWorkPercent == 0 &&
            m_iExtraWithdrawOnFeatureType == 0);
    }

    int    m_iFeatureDoubleMoveCount;
    int    m_iExtraFeatureAttackPercent;
    int    m_iExtraFeatureDefensePercent;
    //ls612: Terrain Work Modifiers
    int m_iFeatureWorkPercent;
//Team Project (4)
    //WorkRateMod
    int m_iExtraFeatureWorkPercent;
    int m_iExtraWithdrawOnFeatureType;
};

class UnitCombatKeyedInfo
{
public:
    UnitCombatKeyedInfo() :        m_bHasUnitCombat(false),
                                m_iExtraUnitCombatModifier(0),
                                m_iSubCombatTypeCount(0),
                                m_iOngoingTrainingCount(0),
                                m_iRemovesUnitCombatTypeCount(0),
                                m_iExtraFlankingStrengthbyUnitCombatType(0),
                                m_iExtraWithdrawVSUnitCombatType(0),
                                m_iExtraPursuitVSUnitCombatType(0),
                                m_iExtraRepelVSUnitCombatType(0),
                                m_iExtraKnockbackVSUnitCombatType(0),
                                m_iExtraPunctureVSUnitCombatType(0),
                                m_iExtraArmorVSUnitCombatType(0),
                                m_iExtraDodgeVSUnitCombatType(0),
                                m_iExtraPrecisionVSUnitCombatType(0),
                                m_iExtraCriticalVSUnitCombatType(0),
                                m_iExtraRoundStunVSUnitCombatType(0),
                                m_iHealUnitCombatTypeVolume(0),
                                m_iHealUnitCombatTypeAdjacentVolume(0),
                                m_iHealAsDamage(0),
                                m_iTrapImmunityUnitCombatCount(0),
                                m_iTargetUnitCombatCount(0),
                                m_iExtraTrapDisableUnitCombatType(0),
                                m_iExtraTrapAvoidanceUnitCombatType(0),
                                m_iExtraTrapTriggerUnitCombatType(0)
    {
    }

    bool Empty() const
    {
        return (!m_bHasUnitCombat &&
            m_iExtraUnitCombatModifier == 0 &&
            m_iSubCombatTypeCount == 0 &&
            m_iOngoingTrainingCount == 0 &&
            m_iRemovesUnitCombatTypeCount == 0 &&
            m_iExtraFlankingStrengthbyUnitCombatType == 0 &&
            m_iExtraWithdrawVSUnitCombatType == 0 &&
            m_iExtraPursuitVSUnitCombatType == 0 &&
            m_iExtraRepelVSUnitCombatType == 0 &&
            m_iExtraKnockbackVSUnitCombatType == 0 &&
            m_iExtraPunctureVSUnitCombatType == 0 &&
            m_iExtraArmorVSUnitCombatType == 0 &&
            m_iExtraDodgeVSUnitCombatType == 0 &&
            m_iExtraPrecisionVSUnitCombatType == 0 &&
            m_iExtraCriticalVSUnitCombatType == 0 &&
            m_iExtraRoundStunVSUnitCombatType == 0 &&
            m_iHealUnitCombatTypeVolume == 0 &&
            m_iHealUnitCombatTypeAdjacentVolume == 0 &&
            m_iHealAsDamage == 0 &&
            m_iTrapImmunityUnitCombatCount == 0 &&
            m_iTargetUnitCombatCount == 0 &&
            m_iExtraTrapDisableUnitCombatType == 0 &&
            m_iExtraTrapAvoidanceUnitCombatType == 0 &&
            m_iExtraTrapTriggerUnitCombatType == 0);
    }

    bool m_bHasUnitCombat;
    int    m_iExtraUnitCombatModifier;
    int m_iSubCombatTypeCount;
    int m_iOngoingTrainingCount;
    int m_iRemovesUnitCombatTypeCount;
    int m_iExtraFlankingStrengthbyUnitCombatType;
    int m_iExtraWithdrawVSUnitCombatType;
    int m_iExtraPursuitVSUnitCombatType;
    int m_iExtraRepelVSUnitCombatType;
    int m_iExtraKnockbackVSUnitCombatType;
    int m_iExtraPunctureVSUnitCombatType;
    int m_iExtraArmorVSUnitCombatType;
    int m_iExtraDodgeVSUnitCombatType;
    int m_iExtraPrecisionVSUnitCombatType;
    int m_iExtraCriticalVSUnitCombatType;
    int m_iExtraRoundStunVSUnitCombatType;
    int m_iHealUnitCombatTypeVolume;
    int m_iHealUnitCombatTypeAdjacentVolume;
    int m_iHealAsDamage;
    int    m_iTrapImmunityUnitCombatCount;
    int    m_iTargetUnitCombatCount;
    int    m_iExtraTrapDisableUnitCombatType;
    int    m_iExtraTrapAvoidanceUnitCombatType;
    int    m_iExtraTrapTriggerUnitCombatType;
};
 
The size of a CvUnit itself is only one part of the story you can't forget the memory consumed for things like textures the graphics engine itself.
Even if you reduce the size of every CvUnit by 200 byte by using smaller data types that would only make 200 kilobyte memory saving in a game with 1000 units.
Yes, but at least it is a low hanging fruit. And yes, the variables in the keyed infos will help more.
Maybe it would be useful to add code that calculates the total memory usage for units, cities and the like and displays it somewhere in the UI.
To reduce the graphics usage for units there is the dynamic unit entities feature Koshling implemented. But I am not sure if you have that active or if it ever was fully debugged. It tries to replace the graphics entity of all units that are not actually visible by the same dummy entity.
 
The size of a CvUnit itself is only one part of the story you can't forget the memory consumed for things like textures the graphics engine itself.
Even if you reduce the size of every CvUnit by 200 byte by using smaller data types that would only make 200 kilobyte memory saving in a game with 1000 units.

The first thing that would make any sense at all would be to look at these because every Unit has multiple instances of these objects:
Code:
class PromotionKeyedInfo
{
public:
    PromotionKeyedInfo() :    m_bHasPromotion(false),
                            m_iAfflictOnAttackCount(0),
                            m_iCureAfflictionCount(0),
                            m_iAfflictionTurnCount(0),
                            m_iAfflictionHitCount(0),
                            m_iAfflictionTolerance(0),
                            m_iFortitudeModifierTypeAmount(0),
                            m_iPromotionFreeCount(0),
                            m_iTrapSetWithPromotionCount(0),
                            m_iPromotionFromTraitCount(0)
    {
    }

    bool Empty() const
    {
        return (!m_bHasPromotion &&
            m_iAfflictOnAttackCount == 0 &&
            m_iCureAfflictionCount == 0 &&
            m_iAfflictionTurnCount == 0 &&
            m_iAfflictionHitCount == 0 &&
            m_iAfflictionTolerance == 0 &&
            m_iFortitudeModifierTypeAmount == 0 &&
            m_iPromotionFreeCount == 0 &&
            m_iTrapSetWithPromotionCount == 0 &&
            m_iPromotionFromTraitCount == 0);
    }

    //TB Combat Mods Begin
    bool    m_bHasPromotion;
    int        m_iAfflictOnAttackCount;
    int        m_iCureAfflictionCount;
    int        m_iAfflictionTurnCount;
    int        m_iAfflictionHitCount;
    int        m_iAfflictionTolerance;
    int        m_iFortitudeModifierTypeAmount;
    int        m_iPromotionFreeCount;
    int        m_iTrapSetWithPromotionCount;
    int        m_iPromotionFromTraitCount;
};

typedef std::map<PromotionTypes, PromotionKeyedInfo>::iterator PromotionIterator;

class PromotionLineKeyedInfo
{
public:
    PromotionLineKeyedInfo() :    m_iCureAfflictionTypeCount(0),
                                m_iAfflictionTurnTypeCount(0),
                                m_iAfflictionLineCount(0),
                                m_iAfflictionTypeTolerance(0),
                                m_iFortitudeModifierAmount(0),
                                m_iAfflictOnAttackTypeProbability(0),
                                m_iAfflictOnAttackTypeCount(0),
                                m_iAfflictOnAttackTypeImmediateCount(0),
                                m_iAfflictOnAttackTypeAttemptedCount(0),
                                m_iDistanceAttackCommunicability(0),
                                m_bValidBuildUp(false),
                                m_iAfflictOnAttackTypeMeleeCount(0),
                                m_iAfflictOnAttackTypeDistanceCount(0)
    {  
    }

    bool Empty() const
    {
        return (m_iCureAfflictionTypeCount == 0 &&
            m_iAfflictionTurnTypeCount == 0 &&
            m_iAfflictionLineCount == 0 &&
            m_iAfflictionTypeTolerance == 0 &&
            m_iFortitudeModifierAmount == 0 &&
            m_iAfflictOnAttackTypeProbability == 0 &&
            m_iAfflictOnAttackTypeCount == 0 &&
            m_iAfflictOnAttackTypeImmediateCount == 0 &&
            m_iAfflictOnAttackTypeAttemptedCount == 0 &&
            m_iDistanceAttackCommunicability == 0 &&
            !m_bValidBuildUp &&
            m_iAfflictOnAttackTypeMeleeCount == 0 &&
            m_iAfflictOnAttackTypeDistanceCount == 0);
    }

    int        m_iCureAfflictionTypeCount;
    int        m_iAfflictionTurnTypeCount;
    int        m_iAfflictionLineCount;
    int        m_iAfflictionTypeTolerance;
    int        m_iFortitudeModifierAmount;
    int        m_iAfflictOnAttackTypeProbability;
    int        m_iAfflictOnAttackTypeCount;
    int        m_iAfflictOnAttackTypeImmediateCount;
    int        m_iAfflictOnAttackTypeAttemptedCount;
    int        m_iDistanceAttackCommunicability;
    bool    m_bValidBuildUp;
    int        m_iAfflictOnAttackTypeMeleeCount;
    int        m_iAfflictOnAttackTypeDistanceCount;
};

class TerrainKeyedInfo
{
public:
    TerrainKeyedInfo() :    m_iTerrainProtected(0),
                            m_iTerrainDoubleMoveCount(0),
                            m_iExtraTerrainAttackPercent(0),
                            m_iExtraTerrainDefensePercent(0),
                            m_iTerrainWorkPercent(0),
//Team Project (4)
    //WorkRateMod
                            m_iExtraTerrainWorkPercent(0),
                            m_iExtraWithdrawOnTerrainType(0)
    {
    }

    bool Empty() const
    {
        return (m_iTerrainProtected == 0 &&
            m_iTerrainDoubleMoveCount == 0 &&
            m_iExtraTerrainAttackPercent == 0 &&
            m_iExtraTerrainDefensePercent == 0 &&
            m_iTerrainWorkPercent == 0 &&
            m_iExtraTerrainWorkPercent == 0 &&
            m_iExtraWithdrawOnTerrainType == 0);
    }

    int    m_iTerrainProtected;
    int    m_iTerrainDoubleMoveCount;
    int    m_iExtraTerrainAttackPercent;
    int    m_iExtraTerrainDefensePercent;
    //ls612: Terrain Work Modifiers
    int m_iTerrainWorkPercent;
//Team Project (4)
    //WorkRateMod
    int m_iExtraTerrainWorkPercent;
    int m_iExtraWithdrawOnTerrainType;
};

class FeatureKeyedInfo
{
public:
    FeatureKeyedInfo() :    m_iFeatureDoubleMoveCount(0),
                            m_iExtraFeatureAttackPercent(0),
                            m_iExtraFeatureDefensePercent(0),
                            m_iFeatureWorkPercent(0),
//Team Project (4)
    //WorkRateMod
                            m_iExtraFeatureWorkPercent(0),
                            m_iExtraWithdrawOnFeatureType(0)
    {
    }

    bool Empty() const
    {
        return (m_iFeatureDoubleMoveCount == 0 &&
            m_iExtraFeatureAttackPercent == 0 &&
            m_iExtraFeatureDefensePercent == 0 &&
            m_iFeatureWorkPercent == 0 &&
            m_iExtraFeatureWorkPercent == 0 &&
            m_iExtraWithdrawOnFeatureType == 0);
    }

    int    m_iFeatureDoubleMoveCount;
    int    m_iExtraFeatureAttackPercent;
    int    m_iExtraFeatureDefensePercent;
    //ls612: Terrain Work Modifiers
    int m_iFeatureWorkPercent;
//Team Project (4)
    //WorkRateMod
    int m_iExtraFeatureWorkPercent;
    int m_iExtraWithdrawOnFeatureType;
};

class UnitCombatKeyedInfo
{
public:
    UnitCombatKeyedInfo() :        m_bHasUnitCombat(false),
                                m_iExtraUnitCombatModifier(0),
                                m_iSubCombatTypeCount(0),
                                m_iOngoingTrainingCount(0),
                                m_iRemovesUnitCombatTypeCount(0),
                                m_iExtraFlankingStrengthbyUnitCombatType(0),
                                m_iExtraWithdrawVSUnitCombatType(0),
                                m_iExtraPursuitVSUnitCombatType(0),
                                m_iExtraRepelVSUnitCombatType(0),
                                m_iExtraKnockbackVSUnitCombatType(0),
                                m_iExtraPunctureVSUnitCombatType(0),
                                m_iExtraArmorVSUnitCombatType(0),
                                m_iExtraDodgeVSUnitCombatType(0),
                                m_iExtraPrecisionVSUnitCombatType(0),
                                m_iExtraCriticalVSUnitCombatType(0),
                                m_iExtraRoundStunVSUnitCombatType(0),
                                m_iHealUnitCombatTypeVolume(0),
                                m_iHealUnitCombatTypeAdjacentVolume(0),
                                m_iHealAsDamage(0),
                                m_iTrapImmunityUnitCombatCount(0),
                                m_iTargetUnitCombatCount(0),
                                m_iExtraTrapDisableUnitCombatType(0),
                                m_iExtraTrapAvoidanceUnitCombatType(0),
                                m_iExtraTrapTriggerUnitCombatType(0)
    {
    }

    bool Empty() const
    {
        return (!m_bHasUnitCombat &&
            m_iExtraUnitCombatModifier == 0 &&
            m_iSubCombatTypeCount == 0 &&
            m_iOngoingTrainingCount == 0 &&
            m_iRemovesUnitCombatTypeCount == 0 &&
            m_iExtraFlankingStrengthbyUnitCombatType == 0 &&
            m_iExtraWithdrawVSUnitCombatType == 0 &&
            m_iExtraPursuitVSUnitCombatType == 0 &&
            m_iExtraRepelVSUnitCombatType == 0 &&
            m_iExtraKnockbackVSUnitCombatType == 0 &&
            m_iExtraPunctureVSUnitCombatType == 0 &&
            m_iExtraArmorVSUnitCombatType == 0 &&
            m_iExtraDodgeVSUnitCombatType == 0 &&
            m_iExtraPrecisionVSUnitCombatType == 0 &&
            m_iExtraCriticalVSUnitCombatType == 0 &&
            m_iExtraRoundStunVSUnitCombatType == 0 &&
            m_iHealUnitCombatTypeVolume == 0 &&
            m_iHealUnitCombatTypeAdjacentVolume == 0 &&
            m_iHealAsDamage == 0 &&
            m_iTrapImmunityUnitCombatCount == 0 &&
            m_iTargetUnitCombatCount == 0 &&
            m_iExtraTrapDisableUnitCombatType == 0 &&
            m_iExtraTrapAvoidanceUnitCombatType == 0 &&
            m_iExtraTrapTriggerUnitCombatType == 0);
    }

    bool m_bHasUnitCombat;
    int    m_iExtraUnitCombatModifier;
    int m_iSubCombatTypeCount;
    int m_iOngoingTrainingCount;
    int m_iRemovesUnitCombatTypeCount;
    int m_iExtraFlankingStrengthbyUnitCombatType;
    int m_iExtraWithdrawVSUnitCombatType;
    int m_iExtraPursuitVSUnitCombatType;
    int m_iExtraRepelVSUnitCombatType;
    int m_iExtraKnockbackVSUnitCombatType;
    int m_iExtraPunctureVSUnitCombatType;
    int m_iExtraArmorVSUnitCombatType;
    int m_iExtraDodgeVSUnitCombatType;
    int m_iExtraPrecisionVSUnitCombatType;
    int m_iExtraCriticalVSUnitCombatType;
    int m_iExtraRoundStunVSUnitCombatType;
    int m_iHealUnitCombatTypeVolume;
    int m_iHealUnitCombatTypeAdjacentVolume;
    int m_iHealAsDamage;
    int    m_iTrapImmunityUnitCombatCount;
    int    m_iTargetUnitCombatCount;
    int    m_iExtraTrapDisableUnitCombatType;
    int    m_iExtraTrapAvoidanceUnitCombatType;
    int    m_iExtraTrapTriggerUnitCombatType;
};
Ok, so Koshling setup the Keyed infos and I can't say I fully grasp them yet. Are these an example of a map? Is this where one could use the : operator in the declaration process and reduce things or are you tring to point towards another problem that might exist in this setup?
 
To reduce the graphics usage for units there is the dynamic unit entities feature Koshling implemented. But I am not sure if you have that active or if it ever was fully debugged. It tries to replace the graphics entity of all units that are not actually visible by the same dummy entity.
That thing was never enabled.
 
Top Bottom