Question about pointers

trystero49

Prince
Joined
Apr 30, 2012
Messages
515
Edit: Because my question got moved to a separate thread, I'd like to point out that these questions are made in reaction to this post:

Spoiler :
Adding this code to the CvCity.cpp file inside of CvCity::CreateBuilding(BuildingTypes eBuildingType) function after the line:
Code:
m_pCityBuildings->SetNumRealBuilding(eBuildingType, m_pCityBuildings->GetNumRealBuilding(eBuildingType) + 1);
fires an event each time a building is created. I'm not sure if there are any edge cases I missed - I don't know what will happen if you grant the building through lua, say - but it should fire on at least purchasing and production.

The parameters are: City X coordinate, City Y coordinate, Building ID, Player ID, City ID.

Code:
	// STRABO - Adding new GameEvent: StraboOnBuildingCreated	
	ICvEngineScriptSystem1* pkScriptSystem = gDLL->GetScriptSystem();
	if(pkScriptSystem)
	{
		CvLuaArgsHandle args;
		args->Push(this->getX());
		args->Push(this->getY());
		args->Push(eBuildingType);
		args->Push(kPlayer.GetID());
		args->Push(GetID());

		bool bResult;
		LuaSupport::CallHook(pkScriptSystem, "StraboOnBuildingCreated", args.get(), bResult);
	}

I tested with the following lua code:

Code:
function OnBuildingCreated(Xcoord, Ycoord, buildingID, ownerID, cityID)
	print("OnBuildingCreated");

	local pPlayer = Players[ ownerID ];
	print("Player: " .. Locale.ConvertTextKey(pPlayer:GetCivilizationShortDescriptionKey()));
	local pBuilding = GameInfo.Buildings[ buildingID ];
	print("Building: " .. Locale.ConvertTextKey(GameInfo.Buildings[ buildingID ].Description));
	local pCity = pPlayer:GetCityByID( cityID );
	print("City: " .. pCity:GetName() );

end
GameEvents.StraboOnBuildingCreated.Add(OnBuildingCreated)

I did not test the X,Y coordinates yet, so I don't know for sure that they're working, but I at least know that all the other parameters work and that the building fires appropriately.


OK, this thread has a lot of useful information but it is a little arcane for someone who doesn't know programming very well. So I'm going to ask some questions and hopefully someone can answer?

Code:
m_pCityBuildings->SetNumRealBuilding(eBuildingType, m_pCityBuildings->GetNumRealBuilding(eBuildingType) + 1);

So, m_pCityBuildings is some kind of pointer, and then -> is the deference operator. But I don't understand what m_pCityBuildings is pointing to. Presumably some kind of array?

Code:
SetNumRealBuilding(eBuildingType, m_pCityBuildings->GetNumRealBuilding(eBuildingType) + 1)[Code]

This part is what sets the number of buildings in the city of a specific building type to however many there were before plus one more. But why not do

[Code]SetNumRealBuilding(eBuildingType, GetNumRealBuilding(eBuildingType) + 1)

instead? Why is it necessary to have the pointer and deference? The same goes for the pointer and derefence to SetNumRealBuilding. Does m_pCityBuildings point to an array of functions? I guess it would help if I knew what m_p stood for.

I have questions about the actual defined event too, but I'll ask them after this question so the thread doesn't get bogged down in a bunch of parallel questions.
 
So, m_pCityBuildings is some kind of pointer, and then -> is the deference operator. But I don't understand what m_pCityBuildings is pointing to. Presumably some kind of array?
Don't guess, use a good search tool and find it in the DLL source code. It's a pointer to a CvCityBuildings object

But why not do

Code:
SetNumRealBuilding(eBuildingType, GetNumRealBuilding(eBuildingType) + 1)

Because the CvCity object does NOT have either of those methods - they are on the CvCityBuildings object and what CvCity does have is a pointer to such an object for that city
 
Even without any particularly up to date search tools, just highlight m_pCityBuildings and press Ctrl+Shift+F to bring up the Find in Files functionality of Visual C++ 2008 (presumably the same or similar commands would work in 2010). Make sure you've chosen Look in: Entire Solution. That'll give you a complete list - sorted by file names - of places it's used in the CvGameCoreDLL and CvGameCoreDLL_Expansion1. In this case, you're looking for how the CvGameCoreDLL_Expansion1 CvCity.cpp file defines it, so just go look at all the places where it gets defined, that'll tell you what they're doing.
 
Even without any particularly up to date search tools, just highlight m_pCityBuildings and press Ctrl+Shift+F to bring up the Find in Files functionality of Visual C++

I'd classify that as "a good search tool" ;)
 
The way you phrased it made me assume there was some super secret code-fu for searching that I wasn't aware of >.>

Bad search tools
1) Not bothering to look, just asking
2) The annoying dog from Windows
3) Opening lots of files in Notepad

Good search tools
1) Pretty much anything else!
2) Notepad++
3) Visual Studio
4) Agent Ransack
5) Add your own favourite here

(There is a thread about useful dev tools somewhere)

Edit: Cunningly hidden in the Tutorials sub-forum under Finding Data
 
Hrm, yes, I did control F it at first and I got this

Code:
m_pCityBuildings(FNEW(CvCityBuildings, c_eCiv5GameplayDLL, 0))

in a code block beginning with "m_syncArchive(*this)" but I didn't understand what that meant, so I posted up here without thinking about it.


Ok, so the "this" pointer of a function stores the address of the object which it is the function of, correct? I got that from this: http://publib.boulder.ibm.com/infoc.../com.ibm.xlcpp8a.doc/language/ref/cplr035.htm. So because m_syncArchive is a part of "CvCity::CvCity()" (the code in CvCity.cpp is
Code:
CvCity::CvCity() :
	m_syncArchive(*this)

So m_syncArchive is a list of pointers (or whatever) of type CvCity(), and it inherits all the properties of the CvCity() class, which I found in CvCity.h and has quite a lot of properties that I didn't bother trying to understand.

Anyway, so m_pCityBuildings is a pointer defined under CvCity, so if I wanted to do
Code:
m_pCityBuildings->SetNumRealBuilding(eBuildingType, m_pCityBuildings->GetNumRealBuilding(eBuildingType) + 1);
in some file that was not CvCity.cpp and didn't include it I would have to do

Code:
CvCity::m_pCityBuildings->SetNumRealBuilding(eBuildingType, CvCity::m_pCityBuildings->GetNumRealBuilding(eBuildingType) + 1);

or otherwise define a pointer to m_pCityBuildings. Obviously there's a better way to do it, but the point still stands, right?

Finally, the code
Code:
m_pCityBuildings(FNEW(CvCityBuildings, c_eCiv5GameplayDLL, 0))
is basically gibberish to me. FNEW is, I assume, a Civspecific thing, because there's nothing on the internet regarding "FNEW C++". So what the heck does it do? Judging by the code, it tells m_pCityBuildings that it is a pointer and it is building to the CvCityBuildings class, which is in CvCityBuildings.h. But what are the other two arguments?
 
In CvCity.h:
Code:
CvCityBuildings* m_pCityBuildings;

This means that for a CvCity object, they store a pointer to a CvCityBuildings object (whatever that might be). So CvCityBuildings is its own type, with its own data and it's own functions.

Code:
m_pCityBuildings(FNEW(CvCityBuildings, c_eCiv5GameplayDLL, 0))

FNEW is civ-specific, and this roughly means that we're going to create a new CvCityBuildings object when we create a new City, but the specifics are a bit out of bounds for modders.

In CvCity::reset()
Code:
m_pCityBuildings->Init(GC.GetGameBuildings(), this);

So when we reset a CvCity - which is called in CvCity::init, so we're going to do this every time we create a new city - we initialize our CvCityBuildings.

Basically, when you see the game core doing this stuff, it means it's going to handle some portion of the functionality for the City (or whatever context it's happening in) with a different object.

You can find the specifics for that object in CvBuildingClasses.h and CvBuildingClasses.cpp (I just searched CvCityBuildings to find that out - "class CvCityBuildings" is the relevant text).

The best quick-and-dirty (not totally reliable, but generally reasonable) way to figure out in general terms what it's for is just reading over the functions list and member variables in CvBuildingClasses.h - you'll see that this class handles how many of a building you have (in a city, since it's initialized in the context of a single city), handles building sales for that city, handles building maintenance for that city, handles building production, checks for wonders built and handles wonder stats, and a few other things (building yield changes, etc.).

So if you're trying to figure out how to do something related to building maintenance, construction, number of buildings, defense from buildings, etc., you're normally going to need to go look in CvCityBuildings for some of it.



One other way of figuring out how the game is doing something, by the way, is to follow the lua hooks. If you want to know how to create a new unit through the Game Core, you can find a lua function that does what you're looking for (in this case, player:InitUnit(params) does the trick) and search that in the Game Core.

Searching "InitUnit" gives a ton of hits, because the lua function is by far not the only function named that in the game core, but it's not hard to filter down to the relevant spots. Every Player Lua function (not event) exposed from the game core is defined in at least 3 places:

In CvLuaPlayer.cpp:
Code:
Method(InitUnit);
Code:
int CvLuaPlayer::lInitUnit(lua_State* L)
(that's lower case L followed by InitUnit, if the fonts aren't clear enough)

and in CvLuaPlayer.h
Code:
int CvLuaPlayer::lInitUnit(lua_State* L);

It's *always* Method(TheExactNameOfTheFunction); and it's ALWAYS int CvLuaPlayer::lTheExactNameOfTheFunction(lua_State* L)

(if you were following a Game.SomeFunction, that'd be in CvLuaGame; if it were City:SomeFunction, CvLuaCity, and so on).

The logic that will actually be executed when that lua function is called is at CvLuaPlayer::lInitUnit(lua_State* L):
Code:
//------------------------------------------------------------------------------
//CyUnit* initUnit(UnitTypes eUnit, int iX, int iY, UnitAITypes eUnitAI = NO_UNITAI, DirectionTypes eFacingDirection = NO_DIRECTION);
int CvLuaPlayer::lInitUnit(lua_State* L)
{
	CvPlayerAI* pkPlayer = GetInstance(L);
	const UnitTypes eUnit = (UnitTypes)lua_tointeger(L, 2);
	const int x = lua_tointeger(L, 3);
	const int y = lua_tointeger(L, 4);
	const UnitAITypes eUnitAI = (UnitAITypes)luaL_optint(L, 5, NO_UNITAI);
	const DirectionTypes eFacingDirection = (DirectionTypes)luaL_optint(L, 6, NO_DIRECTION);

	CvUnit* pkUnit = pkPlayer->initUnit(eUnit, x, y, eUnitAI, eFacingDirection);
	CvLuaUnit::Push(L, pkUnit);
	return 1;
}

CvPlayerAI* pkPlayer = GetInstance(L); -> this just grabs the player we're calling the function on.

const UnitTypes eUnit = (UnitTypes)lua_tointeger(L, 2); -> grab the first parameter, cast its type to be of enum UnitTypes. Same goes for the next few lines - they grab the parameters passed in from the Lua.

The actual logic that gets executed is:
CvUnit* pkUnit = pkPlayer->initUnit(eUnit, x, y, eUnitAI, eFacingDirection);

So, by following the logic for the lua Player:InitUnit() function, we've learned how to create a new unit through a CvPlayer or CvPlayerAI in the game core: we just call pPlayer->initUnit() with the right parameters.

For completeness, this line just sends the return value back to the lua:
CvLuaUnit::Push(L, pkUnit);
 
Back
Top Bottom