Связь SDK и XML.
Как только вы запускаете игру, вы видите Init Python, init XML, Init engine, и т.д. в общем Цива проверяет наличие всех необходимых, для нормальной работы, компонентов. В том числе и наличие XML файлов. SDK, считывает информацию из XML файлов и готовит объекты для игры. В свою очередь напомню – класс это описатель всех переменных и функций, которые работают с этими переменными. На основе классов готовятся объекты. (при этом класс один – а объектов может быть много). Но и объект может описываться при помощи нескольких классов. Например объект Build (класс CvBuildInfo) он описывается в 3 или 4х классах (смотря что Build). На примере этого класса мы и рассмотрим связь SDK и XML файлов.
Описание класса CvBuildInfo есть на модиках (описание Civ4CvBuildInfoXML). Поэтому я не буду описывать каждую переменную, просто приведу пример программы, как это описывается со своими комментариями. Описание в SDK – лежит в файле CvInfos.cpp. Причем, как я понял здесь описаны не все функции класса CvBuildInfo. Где они еще описаны – это мы посмотрим потом, а сейчас посмотрим, как считывается XML файл:
[codebox]
//====================================================================
// CvBuildInfo
//====================================================================
//------------------------------------------------------------------------------------------------------
//
// FUNCTION: CvBuildInfo()
//
// PURPOSE : Default constructor
//
//------------------------------------------------------------------------------------------------------
CvBuildInfo::CvBuildInfo() :
m_iTime(0), //Переменные описанные в Civ4CvBuildInfo
m_iTechPrereq(NO_TECH),
m_iImprovement(NO_IMPROVEMENT),
m_iRoute(NO_ROUTE),
m_iEntityEvent(ENTEVENT_NONE),
m_iMissionType(NO_MISSION),
m_bKill(false),
m_paiFeatureTech(NULL),
m_paiFeatureTime(NULL),
m_paiFeatureProduction(NULL),
m_pabFeatureRemove(NULL)
{
}
//------------------------------------------------------------------------------------------------------
//
// FUNCTION: ~CvBuildInfo()
//
// PURPOSE : Default destructor
//
//------------------------------------------------------------------------------------------------------
CvBuildInfo::~CvBuildInfo()
{
SAFE_DELETE_ARRAY(m_paiFeatureTech);
SAFE_DELETE_ARRAY(m_paiFeatureTime);
SAFE_DELETE_ARRAY(m_paiFeatureProduction);
SAFE_DELETE_ARRAY(m_pabFeatureRemove);
}
int CvBuildInfo::getTime() const
{
return m_iTime;
}
int CvBuildInfo::getTechPrereq() const
{
return m_iTechPrereq;
}
int CvBuildInfo::getImprovement() const
{
return m_iImprovement;
}
int CvBuildInfo::getRoute() const
{
return m_iRoute;
}
int CvBuildInfo::getEntityEvent() const
{
return m_iEntityEvent;
}
int CvBuildInfo::getMissionType() const
{
return m_iMissionType;
}
void CvBuildInfo::setMissionType(int iNewType)
{
m_iMissionType = iNewType;
}
bool CvBuildInfo::isKill() const
{
return m_bKill;
}
// Arrays
int CvBuildInfo::getFeatureTech(int i) const
{
FAssertMsg(i < GC.getNumFeatureInfos(), "Index out of bounds");
FAssertMsg(i > -1, "Index out of bounds");
return m_paiFeatureTech ? m_paiFeatureTech[i] : -1;
}
int CvBuildInfo::getFeatureTime(int i) const
{
FAssertMsg(i < GC.getNumFeatureInfos(), "Index out of bounds");
FAssertMsg(i > -1, "Index out of bounds");
return m_paiFeatureTime ? m_paiFeatureTime[i] : -1;
}
int CvBuildInfo::getFeatureProduction(int i) const
{
FAssertMsg(i < GC.getNumFeatureInfos(), "Index out of bounds");
FAssertMsg(i > -1, "Index out of bounds");
return m_paiFeatureProduction ? m_paiFeatureProduction[i] : -1;
}
bool CvBuildInfo::isFeatureRemove(int i) const
{
FAssertMsg(i < GC.getNumFeatureInfos(), "Index out of bounds");
FAssertMsg(i > -1, "Index out of bounds");
return m_pabFeatureRemove ? m_pabFeatureRemove[i] : false;
}
bool CvBuildInfo::read(CvXMLLoadUtility* pXML)
{
CvString szTextVal;
if (!CvHotkeyInfo::read(pXML))
{
return false;
}
pXML->GetChildXmlValByName(szTextVal, "PrereqTech");
m_iTechPrereq = pXML->FindInInfoClass(szTextVal, GC.getTechInfo(), sizeof(GC.getTechInfo((TechTypes)0)), GC.getNumTechInfos());
pXML->GetChildXmlValByName(&m_iTime, "iTime");
pXML->GetChildXmlValByName(&m_bKill, "bKill");
pXML->GetChildXmlValByName(szTextVal, "ImprovementType");
m_iImprovement = pXML->FindInInfoClass(szTextVal, GC.getImprovementInfo(), sizeof(GC.getImprovementInfo((ImprovementTypes)0)), GC.getNumImprovementInfos());
pXML->GetChildXmlValByName(szTextVal, "RouteType");
m_iRoute = pXML->FindInInfoClass(szTextVal, GC.getRouteInfo(), sizeof(GC.getRouteInfo((RouteTypes)0)), GC.getNumRouteInfos());
pXML->GetChildXmlValByName(szTextVal, "EntityEvent");
m_iEntityEvent = pXML->FindInInfoClass(szTextVal, GC.getEntityEventInfo(), sizeof(GC.getEntityEventInfo((EntityEventTypes)0)),
GC.getNumEntityEventInfos());
pXML->SetFeatureStruct(&m_paiFeatureTech, &m_paiFeatureTime, &m_paiFeatureProduction, &m_pabFeatureRemove);
return true;
}
[/codebox]
Первая функция – это конструктор, которая устанавливает начальные значения для переменных. Вторая функция – это деструктор, которая высвобождает память (вызывается при разрушении объекта). Конструктор вызывается каждый раз, когда идет обращение к классу, Функция CvBuildInfo::read инициализирует переменные конкретного Build-a. В итоге получается, что переменных будет столько, сколько описано Build-ов в файле Civ4BuildInfos.XML, а функции будут храниться в памяти только в единственном экземпляре. Чтобы вызвать конкретно ту функцию, которая вас интересует, вам придется написать примерно так:
iTime = GC.getBuildInfo (eBuild).getTime();
eBuild – описывается в Срр как:
BuildTypes eBuild;
eBuild – это конкретно BUILD_ROAD, BUILD_RAILROAD, BUILD_FARM и т.д. или эквивалент 0,1,2,…(идут по порядку друг за другом).
Поэтому при вызове функции время возьмется то, для какого Build-а оно предназначено. Ну а само значение eBuild устанавливается при нажатии на кнопку у рабочего.
Те функции Build – у которых стоит ImprovementType (в XML) обрабатываются в классе Improvement, соответственно те у которых RouteType – обрабатываются в классе Route.(Там подставляются кнопки) Но потом все они приходят в класс CvPlot.
При считывании Civ4CvBuildInfo.XML одновременно с установкой класса CvBuildInfo Устанавливается класс CvHotKeyInfo (if (!CvHotkeyInfo::read(pXML))) Причем, если вы забудете указать клавиши в XML файле, ваш класс не инициализируется и будет выдана ошибка при загрузке. (Вот так объект Build описывается уже двумя классами – а где то есть еще описание и Button). Загрузка массива (Arrays) происходит совсем в другом месте (вероятнее всего в классе XML). Видно про него забыли, когда писали программу (или в том месте его легче загружать).
[codebox]//------------------------------------------------------------------------------------------------------
//
// FUNCTION: SetFeatureStruct(int** ppiFeatureTech, int** ppiFeatureTime, int** ppiFeatureProduction, bool** ppbFeatureRemove)
//
// PURPOSE : allocate and set the feature struct variables for the CvBuildInfo class
//
//------------------------------------------------------------------------------------------------------
void CvXMLLoadUtility::SetFeatureStruct(int** ppiFeatureTech, int** ppiFeatureTime, int** ppiFeatureProduction, bool** ppbFeatureRemove)
{
int i=0; //loop counter
int iNumSibs; // the number of siblings the current xml node has
int iFeatureIndex;
TCHAR szTextVal[256]; // temporarily hold the text value of the current xml node
int* paiFeatureTech = NULL;
int* paiFeatureTime = NULL;
int* paiFeatureProduction = NULL;
bool* pabFeatureRemove = NULL;
if(GC.getNumFeatureInfos() < 1)
{
char szMessage[1024];
sprintf( szMessage, "no feature infos set yet! \n Current XML file is: %s", GC.getCurrentXMLFile().GetCString());
gDLL->MessageBox(szMessage, "XML Error");
}
InitList(ppiFeatureTech, GC.getNumFeatureInfos(), -1);
InitList(ppiFeatureTime, GC.getNumFeatureInfos());
InitList(ppiFeatureProduction, GC.getNumFeatureInfos());
InitList(ppbFeatureRemove, GC.getNumFeatureInfos());
paiFeatureTech = *ppiFeatureTech;
paiFeatureTime = *ppiFeatureTime;
paiFeatureProduction = *ppiFeatureProduction;
pabFeatureRemove = *ppbFeatureRemove;
if (gDLL->getXMLIFace()->SetToChildByTagName(m_pFXml,"FeatureStructs"))
{
iNumSibs = gDLL->getXMLIFace()->GetNumChildren(m_pFXml);
if (0 < iNumSibs)
{
if (gDLL->getXMLIFace()->SetToChildByTagName(m_pFXml,"FeatureStruct"))
{
if(!(iNumSibs <= GC.getNumFeatureInfos()))
{
char szMessage[1024];
sprintf( szMessage, "iNumSibs is greater than GC.getNumFeatureInfos in SetFeatureStruct function \n Current XML file is: %s", GC.getCurrentXMLFile().GetCString());
gDLL->MessageBox(szMessage, "XML Error");
}
for (i=0;i<iNumSibs;i++)
{
GetChildXmlValByName(szTextVal, "FeatureType");
iFeatureIndex = FindInInfoClass(szTextVal, GC.getFeatureInfo(), sizeof(GC.getFeatureInfo((FeatureTypes) 0)), GC.getNumFeatureInfos());
if(!(iFeatureIndex != -1))
{
char szMessage[1024];
sprintf( szMessage, "iFeatureIndex is -1 inside SetFeatureStruct function \n Current XML file is: %s", GC.getCurrentXMLFile().GetCString());
gDLL->MessageBox(szMessage, "XML Error");
}
GetChildXmlValByName(szTextVal, "PrereqTech");
paiFeatureTech[iFeatureIndex] = FindInInfoClass(szTextVal, GC.getTechInfo(), sizeof(GC.getTechInfo((TechTypes) 0)), GC.getNumTechInfos());
GetChildXmlValByName(&paiFeatureTime[iFeatureIndex], "iTime");
GetChildXmlValByName(&paiFeatureProduction[iFeatureIndex], "iProduction");
GetChildXmlValByName(&pabFeatureRemove[iFeatureIndex], "bRemove");
if (!gDLL->getXMLIFace()->NextSibling(m_pFXml))
{
break;
}
}
gDLL->getXMLIFace()->SetToParent(m_pFXml);
}
}
gDLL->getXMLIFace()->SetToParent(m_pFXml);
}
}
[/codebox]
Здесь устанавливается массив на проверку структуры (лес, джунгли, вернее их вырубка). И опять же эти переменные запоминаются в своих уникальных переменных и запоминаются также ссылки на них.
После того, как мы посмотрим классы CvUnit и CvPlot мы попробуем поподробней разобрать этот класс. (Уже на примере какого нибудь конкретного Builda.)





Ответить с цитированием