Updated more ep2v gamedata.
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
34 #include "GameConfigs.h"
37 #define PSTATE_GAMES 1
38 #define PSTATE_GAMEDEFS 2
39 #define PSTATE_GAMEDEFS_OFFSETS 3
40 #define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4
41 #define PSTATE_GAMEDEFS_KEYS 5
42 #define PSTATE_GAMEDEFS_SUPPORTED 6
43 #define PSTATE_GAMEDEFS_SIGNATURES 7
44 #define PSTATE_GAMEDEFS_SIGNATURES_SIG 8
45 #define PSTATE_GAMEDEFS_CRC 9
46 #define PSTATE_GAMEDEFS_CRC_BINARY 10
47 #define PSTATE_GAMEDEFS_CUSTOM 11
48 #define PSTATE_GAMEDEFS_OPTIONS 12
53 #define PLATFORM_NAME "linux"
54 #define PLATFORM_SERVER_BINARY "server_i486.so"
59 unsigned int s_ServerBinCRC;
60 bool s_ServerBinCRC_Ok = false;
62 bool DoesGameMatch(const char *value)
64 if (strcmp(value, game) == 0)
71 bool DoesEngineMatch(const char *value)
73 if (strcmp(value, engine) == 0)
80 CGameConfig::CGameConfig()
82 m_pStrings = new BaseStringTable(512);
86 m_CustomHandler = NULL;
89 CGameConfig::~CGameConfig()
94 SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
99 return SMCResult_Continue;
102 switch (m_ParseState)
106 if (strcmp(name, "Games") == 0)
108 m_ParseState = PSTATE_GAMES;
116 if (strcmp(name, "*") == 0 ||
117 strcmp(name, "#default") == 0 ||
120 bShouldBeReadingDefault = true;
121 m_ParseState = PSTATE_GAMEDEFS;
122 strncopy(m_Game, name, sizeof(m_Game));
128 case PSTATE_GAMEDEFS:
130 if (strcmp(name, "Offsets") == 0)
132 m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
134 else if (strcmp(name, "Keys") == 0)
136 m_ParseState = PSTATE_GAMEDEFS_KEYS;
138 else if (strcmp(name, "Options") == 0)
140 m_ParseState = PSTATE_GAMEDEFS_OPTIONS;
142 else if ((strcmp(name, "#supported") == 0) && (strcmp(m_Game, "#default") == 0))
144 m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
145 /* Ignore this section unless we get a game. */
146 bShouldBeReadingDefault = false;
148 matched_game = false;
150 matched_engine = false;
152 else if (strcmp(name, "Signatures") == 0)
154 m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
159 case PSTATE_GAMEDEFS_OFFSETS:
163 tempOffset = new Offset();
164 tempOffset->setName(name);
165 m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
168 case PSTATE_GAMEDEFS_SIGNATURES:
171 tempSig->setName(name);
172 m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
175 /* No sub-sections allowed:
176 case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
177 case PSTATE_GAMEDEFS_KEYS:
178 case PSTATE_GAMEDEFS_SUPPORTED:
179 case PSTATE_GAMEDEFS_SIGNATURES_SIG:
180 case PSTATE_GAMEDEFS_CRC_BINARY:
184 /* If we don't know what we got, start ignoring */
190 return SMCResult_Continue;
193 SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
197 return SMCResult_Continue;
200 if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
202 if (strcmp(key, "class") == 0)
204 strncopy(m_Class, value, sizeof(m_Class));
205 } else if (strcmp(key, "prop") == 0) {
206 strncopy(m_Prop, value, sizeof(m_Prop));
208 int val = atoi(value);
209 if (strcmp(key, "windows") == 0) tempOffset->setWin(val);
210 else if (strcmp(key, "linux") == 0) tempOffset->setLin(val);
212 } else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
213 m_Keys.replace(key, m_pStrings->AddString(value));
214 } else if (m_ParseState == PSTATE_GAMEDEFS_OPTIONS) {
215 m_Options.replace(key, m_pStrings->AddString(value));
216 } else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
217 if (strcmp(key, "game") == 0)
220 if (DoesGameMatch(value))
224 if ((!had_engine && matched_game) || (matched_engine && matched_game))
226 bShouldBeReadingDefault = true;
229 else if (strcmp(key, "engine") == 0)
232 if (DoesEngineMatch(value))
234 matched_engine = true;
236 if ((!had_game && matched_engine) || (matched_game && matched_engine))
238 bShouldBeReadingDefault = true;
241 } else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
242 if (strcmp(key, "windows") == 0) tempSig->setWin(value);
243 else if (strcmp(key, "linux") == 0) tempSig->setLin(value);
244 else if (strcmp(key, "library") == 0) tempSig->setLib(value);
245 } else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
246 if (strcmp(key, PLATFORM_NAME) == 0
248 && !bShouldBeReadingDefault)
250 unsigned int crc = 0;
251 sscanf(value, "%08X", &crc);
252 if (s_ServerBinCRC == crc)
254 bShouldBeReadingDefault = true;
257 } else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
258 return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
261 return SMCResult_Continue;
264 SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
269 return SMCResult_Continue;
275 m_CustomHandler->ReadSMC_LeavingSection(states);
276 return SMCResult_Continue;
279 switch (m_ParseState)
283 m_ParseState = PSTATE_NONE;
286 case PSTATE_GAMEDEFS:
288 m_ParseState = PSTATE_GAMES;
291 case PSTATE_GAMEDEFS_CUSTOM:
293 m_ParseState = PSTATE_GAMEDEFS;
294 m_CustomHandler->ReadSMC_ParseEnd(false, false);
297 case PSTATE_GAMEDEFS_KEYS:
298 case PSTATE_GAMEDEFS_OFFSETS:
299 case PSTATE_GAMEDEFS_OPTIONS:
301 m_ParseState = PSTATE_GAMEDEFS;
304 case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
306 for (list<Offset>::iterator it = m_Offsets.begin(); it != m_Offsets.end(); it++)
308 if (strcmp(it->name, tempOffset->name) == 0)
314 m_Offsets.push_back(*tempOffset);
315 m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
318 case PSTATE_GAMEDEFS_CRC:
319 case PSTATE_GAMEDEFS_SUPPORTED:
321 if (!bShouldBeReadingDefault)
323 /* If we shouldn't read the rest of this section, set the ignore level. */
325 m_ParseState = PSTATE_GAMES;
327 m_ParseState = PSTATE_GAMEDEFS;
331 case PSTATE_GAMEDEFS_CRC_BINARY:
333 m_ParseState = PSTATE_GAMEDEFS_CRC;
336 case PSTATE_GAMEDEFS_SIGNATURES:
338 m_ParseState = PSTATE_GAMEDEFS;
341 case PSTATE_GAMEDEFS_SIGNATURES_SIG:
343 m_Sigs.push_back(*tempSig);
344 m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
350 return SMCResult_Continue;
353 #define MSTATE_NONE 0
354 #define MSTATE_MAIN 1
355 #define MSTATE_FILE 2
357 class MasterReader : public ITextListener_SMC
360 virtual void ReadSMC_ParseStart()
366 virtual SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
370 return SMCResult_Continue;
373 if (state == MSTATE_NONE)
375 if (strcmp(name, "Game Master") == 0)
384 else if (state == MSTATE_MAIN)
386 strncopy(cur_file, name, sizeof(cur_file));
388 matched_engine = false;
390 matched_game = false;
393 else if (state == MSTATE_FILE)
398 return SMCResult_Continue;
401 virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
403 if (ignoreLevel || state != MSTATE_FILE)
405 return SMCResult_Continue;
408 if (strcmp(key, "engine") == 0)
411 if (DoesEngineMatch(value))
413 matched_engine = true;
416 else if (strcmp(key, "game") == 0)
419 if (DoesGameMatch(value))
425 return SMCResult_Continue;
428 virtual SMCResult ReadSMC_LeavingSection(const SMCStates *states)
433 return SMCResult_Continue;
436 if (state == MSTATE_FILE)
438 /* The four success conditions:
440 * 2. Needed game only.
441 * 3. Needed engine only.
442 * 4. Needed both engine and game.
443 * Final result is minimized via k-map.
446 if ((!had_engine && !had_game) ||
447 (!had_engine && matched_game) ||
448 (!had_game && matched_engine) ||
449 (matched_engine && matched_game))
451 fileList->push_back(cur_file);
455 else if (state == MSTATE_MAIN)
460 return SMCResult_Continue;
463 list<char*> *fileList;
465 unsigned int ignoreLevel;
466 char cur_file[PLATFORM_MAX_PATH];
473 static MasterReader master_reader;
475 bool CGameConfig::Reparse(char *error, size_t maxlength)
477 /* Reset cached data */
484 char path[PLATFORM_MAX_PATH];
486 /* See if we can use the extended gamedata format. */
487 //TODO pass in path to gamedata somehow
489 /* Otherwise, it's time to parse the master. */
491 SMCStates state = {0, 0};
492 list<char*> fileList;
493 master_reader.fileList = &fileList;
495 err = textparsers->ParseSMCFile(path, &master_reader, &state, error, maxlength);
496 if (err != SMCError_Okay)
498 const char *msg = textparsers->GetSMCErrorString(err);
500 printf("[SM] Error parsing master gameconf file \"%s\":", path);
501 printf("[SM] Error %d on line %d, col %d: %s",
505 msg ? msg : "Unknown error");
509 /* Go through each file we found and parse it. */
510 list<char*>::iterator iter;
511 for (iter = fileList.begin(); iter != fileList.end(); iter++)
513 UTIL_Format(path, sizeof(path), "%s/%s", m_File, *iter);
514 if (!EnterFile(path, error, maxlength))
523 bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
526 SMCStates state = {0, 0};
528 /* Initialize parse states */
530 bShouldBeReadingDefault = true;
531 m_ParseState = PSTATE_NONE;
533 if ((err=textparsers->ParseSMCFile(file, this, &state, error, maxlength))
538 msg = textparsers->GetSMCErrorString(err);
540 printf("[SM] Error parsing gameconfig file \"%s\":\n", file);
541 printf("[SM] Error %d on line %d, col %d: %s\n",
545 msg ? msg : "Unknown error");
547 if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM)
549 //error occurred while parsing a custom section
550 m_CustomHandler->ReadSMC_ParseEnd(true, true);
551 m_CustomHandler = NULL;
561 const char *CGameConfig::GetKeyValue(const char *key)
564 if ((pkey = m_Keys.retrieve(key)) == NULL)
566 return m_pStrings->GetString(*pkey);
569 const char *CGameConfig::GetOptionValue(const char *key)
572 if ((pkey = m_Options.retrieve(key)) == NULL)
574 return m_pStrings->GetString(*pkey);
577 list<Offset> CGameConfig::GetOffsets() { return m_Offsets; }
578 list<Sig> CGameConfig::GetSigs() { return m_Sigs; }