Strange Coding Problem

I was wondering exactly how to call, in code, to the disease property level on a plot (particularly within the city in CvCity.cpp). The generic coding is making it a bit confusing for me. I could probably sort it out but I thought it might make it a lot easier to just ask. ;)
 
I was wondering exactly how to call, in code, to the disease property level on a plot (particularly within the city in CvCity.cpp). The generic coding is making it a bit confusing for me. I could probably sort it out but I thought it might make it a lot easier to just ask. ;)

Well, firstly it's a slightly odd request, since generally the DLL should be dealing with properties on a generic level, so anything needing to access a specific property is a bit odd. However, if you really need to do this try something this this:
Code:
int CvPlot::getDiseasePropertyValue() const
{
	//	Check it exists in this game's definitions
	if ( eProperty != NO_PROPERTY )
	{
		CvGameObject* pGameObject = getGameObject();
		if ( pGameObject != NULL )
		{
			CvProperties* pProperties = pGameObject->getProperties();
			if ( pProperties != NULL && pProperties->getProperty(eProperty) != NULL )
			{
				return pProperties->getValue(eProperty);
			}
		}
	}
}
 
Ok, that's a good enough example I think I can work with it. Thanks!

I realize the system is supposed to work generically but there are some unique systems for disease in particular that I've been programming here that should interact with the generic disease property. Its possible some of it could be genericalized further upon evaluation but for now I just need to set up the structure and it can then be evaluated after the fact. I know this leads to some less than perfect hardcoding but it seems a necessary evil for now.
 
Ok, so, just to make sure, since I don't really get everything about this yet,

Code:
int CvCity::getDiseasePropertyValue() const
{
	PropertyTypes eDiseaseType = (PropertyTypes)GC.getInfoTypeForString("PROPERTY_DISEASE");
	//	Check it exists in this game's definitions
	if ( eDiseaseType != NO_PROPERTY )
	{
		CvGameObject* pGameObject = m_GameObject;
		if ( pGameObject != NULL )
		{
			CvProperties* pProperties = pGameObject->getProperties();
			if ( pProperties != NULL && pProperties->getProperty(eDiseaseType) != NULL )
			{
				return pProperties->getValue(eDiseaseType);
			}
		}
	}
}
This, as a function in CvCity should return the disease property value present, right?
 
Ok, so, just to make sure, since I don't really get everything about this yet,

Code:
int CvCity::getDiseasePropertyValue() const
{
	PropertyTypes eDiseaseType = (PropertyTypes)GC.getInfoTypeForString("PROPERTY_DISEASE");
	//	Check it exists in this game's definitions
	if ( eDiseaseType != NO_PROPERTY )
	{
		CvGameObject* pGameObject = m_GameObject;
		if ( pGameObject != NULL )
		{
			CvProperties* pProperties = pGameObject->getProperties();
			if ( pProperties != NULL && pProperties->getProperty(eDiseaseType) != NULL )
			{
				return pProperties->getValue(eDiseaseType);
			}
		}
	}
}
This, as a function in CvCity should return the disease property value present, right?

Yes it should. It is better practise to use getGameObject() than to use m_gameObject directly though (in principal it allows the implementation to change so that some entities could share or proxy game objects (for example you could imagine the tile of a city using the city's game object or somthing [probably not an actual example that we would do, but the principle is sound]).
 
You noticed I changed that... I'm glad you spotted it. I want to explain why to see what I can do more appropriately about this in the future.

I changed it because when I went to find what getGameObject() was referring to, it asked me to clear up an ambiguity in the fact that there was a getGameObject line in a number of files and seemed to be unable to tell that I was trying to refer to the native CvCity getGameObject.

This kinda threw me into some concern so I searched a bit and found that all it does is return m_gameObject 's value so I wondered, why are we taking an interrim step in the first place? Of course, the coding here does that all OVER the place in the code so I get that its something that for some reason seems to be necessary, but I really don't get why. Anyhow, it seemed that if I changed it to m_gameObject, it would relieve itself of any ambiguity that could confuse the code in process.

At the same time I figured I wasn't doing it quite right and would get the response you gave if you noticed I'd changed it. But I wasn't sure why it couldn't define its way through the ambiguity... Was I overreacting to something there?


And this:
(in principal it allows the implementation to change so that some entities could share or proxy game objects (for example you could imagine the tile of a city using the city's game object or somthing [probably not an actual example that we would do, but the principle is sound]).
confuses me as I can't imagine how this could be exploited, accidentally or otherwise, any different than the potential use of getGameObject as well. Maybe it comes from a side of coding I don't get yet?
 
You noticed I changed that... I'm glad you spotted it. I want to explain why to see what I can do more appropriately about this in the future.

I changed it because when I went to find what getGameObject() was referring to, it asked me to clear up an ambiguity in the fact that there was a getGameObject line in a number of files and seemed to be unable to tell that I was trying to refer to the native CvCity getGameObject.

This kinda threw me into some concern so I searched a bit and found that all it does is return m_gameObject 's value so I wondered, why are we taking an interrim step in the first place? Of course, the coding here does that all OVER the place in the code so I get that its something that for some reason seems to be necessary, but I really don't get why. Anyhow, it seemed that if I changed it to m_gameObject, it would relieve itself of any ambiguity that could confuse the code in process.

At the same time I figured I wasn't doing it quite right and would get the response you gave if you noticed I'd changed it. But I wasn't sure why it couldn't define its way through the ambiguity... Was I overreacting to something there?


And this: confuses me as I can't imagine how this could be exploited, accidentally or otherwise, any different than the potential use of getGameObject as well. Maybe it comes from a side of coding I don't get yet?

It was a slightly stretched hypothetical example ;) The general point is that the use of a method there allows for some soprt of dynamic calculation to determine the game object to return (for another example maybe we might create the game object on-demand so that entities that never have thier game object referecned don't use up any storage for them).

In regards to the ambiguity are you talking about a compiler warning or a debugger issue? If it's a compiler warning could you post the exact text please.
 
It was a slightly stretched hypothetical example ;) The general point is that the use of a method there allows for some soprt of dynamic calculation to determine the game object to return (for another example maybe we might create the game object on-demand so that entities that never have thier game object referecned don't use up any storage for them).

In regards to the ambiguity are you talking about a compiler warning or a debugger issue? If it's a compiler warning could you post the exact text please.

Actually, this is kinda funny. I was thinking about it at work today and was wondering if it was remaining ambiguous for a particular reason. It was found to be ambiguous when selecting the getGameObject(); call and trying to 'go to definition' and finding it could've related to the getGameObject() in any number of files. I realized today that it was coming up as such when I had yet to declared the function the call was in in the header file. Apparently, if you haven't declared the function in the header file yet, references aren't pulled properly. I got home and tested the thought and it proved true... once the function was declared, going to the definition of getGameObject went directly to the native CvCity version. Duh... small thing - operator error on my end. Thanks for looking into it though.

I also realized, perhaps the return for 'getGameObject()' could be purposefully manipulated to include more than just m_GameObject and if someone did that expecting the new value to carry through to all expected references, it would create a problem in that way. So that's a small glimmer of understanding the warning you were sharing.
 
Actually, this is kinda funny. I was thinking about it at work today and was wondering if it was remaining ambiguous for a particular reason. It was found to be ambiguous when selecting the getGameObject(); call and trying to 'go to definition' and finding it could've related to the getGameObject() in any number of files. I realized today that it was coming up as such when I had yet to declared the function the call was in in the header file. Apparently, if you haven't declared the function in the header file yet, references aren't pulled properly. I got home and tested the thought and it proved true... once the function was declared, going to the definition of getGameObject went directly to the native CvCity version. Duh... small thing - operator error on my end. Thanks for looking into it though.

I also realized, perhaps the return for 'getGameObject()' could be purposefully manipulated to include more than just m_GameObject and if someone did that expecting the new value to carry through to all expected references, it would create a problem in that way. So that's a small glimmer of understanding the warning you were sharing.
There is no real ambiguity here except that the Intellisense code does not grasp all references as well as the compiler does later.

In principle you could just grab the properties directly from CvCity instead of going via the game object wrapper. The reasons why you might do one or the other have to do with what might change in the future and program architecture.
An example: You could declare all attributes of a class public and directly access them from everywhere. But now imagine you later want to change how you store the information. If you directly accessed the variable, you have to change every single code piece that accesses it but if you instead had get and set methods you might get away with only some added code to those methods.
So it is a matter of abstraction and information hiding.

Btw, there is a bug in that code: getProperty and getValue expect an index, not the property type, so it is not what you want in this case. Use getValueByProperty.

As someone who knows the depths of the code and the expectations I had in mind, I might write the method like this, but it might also make work if there are some future changes that I don't perceive yet:
Code:
return getProperties()->getValueByProperty(GC.getInfoTypeForString("PROPERTY_DISEASE"))
It will return 0 if the property does not exist on the object (or not at all in the XML).
 
hmm...

neither this:
Code:
int CvCity::getDiseasePropertyValue() const
{
	PropertyTypes eDiseaseType = (PropertyTypes)GC.getInfoTypeForString("PROPERTY_DISEASE");
	//	Check it exists in this game's definitions
	if ( eDiseaseType != NO_PROPERTY )
	{
		CvGameObject* pGameObject = getGameObject();
		if ( pGameObject != NULL )
		{
			CvProperties* pProperties = pGameObject->getProperties();
			if ( pProperties != NULL && pProperties->getProperty(eDiseaseType) != NULL )
			{
				return pProperties->getValue(eDiseaseType);
			}
		}
	}
}
Problem being:
1>CvCity.cpp(25653) : error C2662: 'CvCity::getGameObject' : cannot convert 'this' pointer from 'const CvCity' to 'CvCity &'
1> Conversion loses qualifiers


nor this:
Code:
int CvCity::getDiseasePropertyValue() const
{
	return getProperties()->getValueByProperty(GC.getInfoTypeForString("PROPERTY_DISEASE"))
}
Problem:
1>CvCity.cpp
1>CvCity.cpp(25649) : error C2662: 'CvCity::getProperties' : cannot convert 'this' pointer from 'const CvCity' to 'CvCity &'
1> Conversion loses qualifiers


seem to work. What am I doing wrong here?
 
hmm...

neither this:
Code:
int CvCity::getDiseasePropertyValue() const
{
	PropertyTypes eDiseaseType = (PropertyTypes)GC.getInfoTypeForString("PROPERTY_DISEASE");
	//	Check it exists in this game's definitions
	if ( eDiseaseType != NO_PROPERTY )
	{
		CvGameObject* pGameObject = getGameObject();
		if ( pGameObject != NULL )
		{
			CvProperties* pProperties = pGameObject->getProperties();
			if ( pProperties != NULL && pProperties->getProperty(eDiseaseType) != NULL )
			{
				return pProperties->getValue(eDiseaseType);
			}
		}
	}
}
Problem being:
1>CvCity.cpp(25653) : error C2662: 'CvCity::getGameObject' : cannot convert 'this' pointer from 'const CvCity' to 'CvCity &'
1> Conversion loses qualifiers


nor this:
Code:
int CvCity::getDiseasePropertyValue() const
{
	return getProperties()->getValueByProperty(GC.getInfoTypeForString("PROPERTY_DISEASE"))
}
Problem:
1>CvCity.cpp
1>CvCity.cpp(25649) : error C2662: 'CvCity::getProperties' : cannot convert 'this' pointer from 'const CvCity' to 'CvCity &'
1> Conversion loses qualifiers


seem to work. What am I doing wrong here?

By declaring a method const you are asserting that a call to it will not change the state of the object it is a member of. I thus follows that a const method cannot call a non-const method, which is what you are trippi over cases of here.

In some cases logically const methods actually do change some member variable state (for example suppose you add some caching to an existing const method, that has to recalculate and update cache values on a cache miss). To address that need individual member variables can be declared 'mutable' which basically just tells the compiler that const methods can legitimately modify them.

In general think about what you method is doing(from a logical viewpoint). If it is returning values based on the object state, but is not intended to change that state it should probably be declared const. Unfortunately previous authors have not always thought very hard about what should be const or not, which can make you life awkward.

The way out is usually either
1) To modify the const declaration on some existing methods that have 'got it wrong' if you can address the problem with small number of such changes ( but you cannot EVER change the declaration on a method that is declared DllExternal or else the game engine won't find the modified version); or
2) Just cast the this pointer at the point of call. So if you are in a const method that(legitimately!) needs to call a method not declared as const, you can (but yuck!) cast like this:
Code:
((CvCity*)this)->nonConstMethodX()
 
Thanks for the answer... oddly though I'm wondering how the system figures that asking for the disease value is going to somehow change the disease value. Is it good enough to evaluate all potential consequences down the road from any call to this variable?
 
Thanks for the answer... oddly though I'm wondering how the system figures that asking for the disease value is going to somehow change the disease value. Is it good enough to evaluate all potential consequences down the road from any call to this variable?

It doesn't know. It assumes that any method MIGHT change anythig about the objects state, so if you are in a method that assets that that will NOT happen, you cannot call something that doesn't also make that assertion.
 
Ah... that's making a bit more sense now... ok.

BTW... any idea why the debugger, during a minidump check, would be showing, on the hover over, a call to a local function coming up as the same as a completely unrelated function in an entirely different page?

I saw this... held the pointer over a local call, lets say for example's sake, 'getDiseasePropertyValue()' and it was returning the value of AI_SomeOtherFunction (sorry... can't remember right now which one it actually was). Is this just a minor confusion that can result from debugging through a minidump or do I have some sort of serious (and strange) problem here? It was doing this reliably through a number of checks as I went about trying a number of different methods debugging a completely separate problem located nearby.
 
Thanks for the answer... oddly though I'm wondering how the system figures that asking for the disease value is going to somehow change the disease value. Is it good enough to evaluate all potential consequences down the road from any call to this variable?
You can use getPropertiesConst to get the const version of the properties object (similar there is getGameObjectConst to get the constant version of the game object).
I have not provided const versions of all methods though.
 
Ah... that's making a bit more sense now... ok.

BTW... any idea why the debugger, during a minidump check, would be showing, on the hover over, a call to a local function coming up as the same as a completely unrelated function in an entirely different page?

I saw this... held the pointer over a local call, lets say for example's sake, 'getDiseasePropertyValue()' and it was returning the value of AI_SomeOtherFunction (sorry... can't remember right now which one it actually was). Is this just a minor confusion that can result from debugging through a minidump or do I have some sort of serious (and strange) problem here? It was doing this reliably through a number of checks as I went about trying a number of different methods debugging a completely separate problem located nearby.

Mismatched PDB or DLL?
 
You can use getPropertiesConst to get the const version of the properties object (similar there is getGameObjectConst to get the constant version of the game object).
I have not provided const versions of all methods though.
You know what? That was my patch in the interrim! I just wondered if that was the difference between the +/- Disease/round value and the total overall accumulated current value. Out of curiosity, I suppose I really should make sure I'm using the right tag in the first place here. I'm trying to call to the total, not the round by round modifying value. But I am a but curious what you'd use to ask for that value too, just so I know if I see it referenced what it means.

Mismatched PDB or DLL?
Oddly, no. Impossible. Came from the same build. PDB... maybe but unlikely as I'm now in the habit of keeping both in the assets folder and just copying both as a matter of process. I'll keep that in mind as a possibility though. Strangest darn thing... I may need to run it through the debugger with a stop on that portion to confirm for myself that the references are maintaining accuracy, if for no other reason than for my sanity alone ;).
 
Back
Top Bottom