Updated GMod 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
52 #define PLATFORM_NAME "linux"
53 #define PLATFORM_SERVER_BINARY "server_i486.so"
58 unsigned int s_ServerBinCRC;
59 bool s_ServerBinCRC_Ok = false;
61 bool DoesGameMatch(const char *value)
63 if (strcmp(value, game) == 0)
70 bool DoesEngineMatch(const char *value)
72 if (strcmp(value, engine) == 0)
79 CGameConfig::CGameConfig()
81 m_pStrings = new BaseStringTable(512);
85 m_CustomHandler = NULL;
88 CGameConfig::~CGameConfig()
93 SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
98 return SMCResult_Continue;
101 switch (m_ParseState)
105 if (strcmp(name, "Games") == 0)
107 m_ParseState = PSTATE_GAMES;
115 if (strcmp(name, "*") == 0 ||
116 strcmp(name, "#default") == 0 ||
119 bShouldBeReadingDefault = true;
120 m_ParseState = PSTATE_GAMEDEFS;
121 strncopy(m_Game, name, sizeof(m_Game));
127 case PSTATE_GAMEDEFS:
129 if (strcmp(name, "Offsets") == 0)
131 m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
133 else if (strcmp(name, "Keys") == 0)
135 m_ParseState = PSTATE_GAMEDEFS_KEYS;
137 else if ((strcmp(name, "#supported") == 0) && (strcmp(m_Game, "#default") == 0))
139 m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
140 /* Ignore this section unless we get a game. */
141 bShouldBeReadingDefault = false;
143 matched_game = false;
145 matched_engine = false;
147 else if (strcmp(name, "Signatures") == 0)
149 m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
154 case PSTATE_GAMEDEFS_OFFSETS:
158 tempOffset = new Offset();
159 tempOffset->setName(name);
160 m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
163 case PSTATE_GAMEDEFS_SIGNATURES:
166 tempSig->setName(name);
167 m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
170 /* No sub-sections allowed:
171 case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
172 case PSTATE_GAMEDEFS_KEYS:
173 case PSTATE_GAMEDEFS_SUPPORTED:
174 case PSTATE_GAMEDEFS_SIGNATURES_SIG:
175 case PSTATE_GAMEDEFS_CRC_BINARY:
179 /* If we don't know what we got, start ignoring */
185 return SMCResult_Continue;
188 SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
192 return SMCResult_Continue;
195 if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
197 if (strcmp(key, "class") == 0)
199 strncopy(m_Class, value, sizeof(m_Class));
200 } else if (strcmp(key, "prop") == 0) {
201 strncopy(m_Prop, value, sizeof(m_Prop));
203 int val = atoi(value);
204 if (strcmp(key, "windows") == 0) tempOffset->setWin(val);
205 else if (strcmp(key, "linux") == 0) tempOffset->setLin(val);
207 } else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
208 m_Keys.replace(key, m_pStrings->AddString(value));
209 } else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
210 if (strcmp(key, "game") == 0)
213 if (DoesGameMatch(value))
217 if ((!had_engine && matched_game) || (matched_engine && matched_game))
219 bShouldBeReadingDefault = true;
222 else if (strcmp(key, "engine") == 0)
225 if (DoesEngineMatch(value))
227 matched_engine = true;
229 if ((!had_game && matched_engine) || (matched_game && matched_engine))
231 bShouldBeReadingDefault = true;
234 } else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
235 if (strcmp(key, "windows") == 0) tempSig->setWin(value);
236 else if (strcmp(key, "linux") == 0) tempSig->setLin(value);
237 else if (strcmp(key, "library") == 0) tempSig->setLib(value);
238 } else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
239 if (strcmp(key, PLATFORM_NAME) == 0
241 && !bShouldBeReadingDefault)
243 unsigned int crc = 0;
244 sscanf(value, "%08X", &crc);
245 if (s_ServerBinCRC == crc)
247 bShouldBeReadingDefault = true;
250 } else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
251 return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
254 return SMCResult_Continue;
257 SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
262 return SMCResult_Continue;
268 m_CustomHandler->ReadSMC_LeavingSection(states);
269 return SMCResult_Continue;
272 switch (m_ParseState)
276 m_ParseState = PSTATE_NONE;
279 case PSTATE_GAMEDEFS:
281 m_ParseState = PSTATE_GAMES;
284 case PSTATE_GAMEDEFS_CUSTOM:
286 m_ParseState = PSTATE_GAMEDEFS;
287 m_CustomHandler->ReadSMC_ParseEnd(false, false);
290 case PSTATE_GAMEDEFS_KEYS:
291 case PSTATE_GAMEDEFS_OFFSETS:
293 m_ParseState = PSTATE_GAMEDEFS;
296 case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
298 for (list<Offset>::iterator it = m_Offsets.begin(); it != m_Offsets.end(); it++)
300 if (strcmp(it->name, tempOffset->name) == 0)
306 m_Offsets.push_back(*tempOffset);
307 m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
310 case PSTATE_GAMEDEFS_CRC:
311 case PSTATE_GAMEDEFS_SUPPORTED:
313 if (!bShouldBeReadingDefault)
315 /* If we shouldn't read the rest of this section, set the ignore level. */
317 m_ParseState = PSTATE_GAMES;
319 m_ParseState = PSTATE_GAMEDEFS;
323 case PSTATE_GAMEDEFS_CRC_BINARY:
325 m_ParseState = PSTATE_GAMEDEFS_CRC;
328 case PSTATE_GAMEDEFS_SIGNATURES:
330 m_ParseState = PSTATE_GAMEDEFS;
333 case PSTATE_GAMEDEFS_SIGNATURES_SIG:
335 m_Sigs.push_back(*tempSig);
336 m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
342 return SMCResult_Continue;
345 #define MSTATE_NONE 0
346 #define MSTATE_MAIN 1
347 #define MSTATE_FILE 2
349 class MasterReader : public ITextListener_SMC
352 virtual void ReadSMC_ParseStart()
358 virtual SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
362 return SMCResult_Continue;
365 if (state == MSTATE_NONE)
367 if (strcmp(name, "Game Master") == 0)
376 else if (state == MSTATE_MAIN)
378 strncopy(cur_file, name, sizeof(cur_file));
380 matched_engine = false;
382 matched_game = false;
385 else if (state == MSTATE_FILE)
390 return SMCResult_Continue;
393 virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
395 if (ignoreLevel || state != MSTATE_FILE)
397 return SMCResult_Continue;
400 if (strcmp(key, "engine") == 0)
403 if (DoesEngineMatch(value))
405 matched_engine = true;
408 else if (strcmp(key, "game") == 0)
411 if (DoesGameMatch(value))
417 return SMCResult_Continue;
420 virtual SMCResult ReadSMC_LeavingSection(const SMCStates *states)
425 return SMCResult_Continue;
428 if (state == MSTATE_FILE)
430 /* The four success conditions:
432 * 2. Needed game only.
433 * 3. Needed engine only.
434 * 4. Needed both engine and game.
435 * Final result is minimized via k-map.
438 if ((!had_engine && !had_game) ||
439 (!had_engine && matched_game) ||
440 (!had_game && matched_engine) ||
441 (matched_engine && matched_game))
443 fileList->push_back(cur_file);
447 else if (state == MSTATE_MAIN)
452 return SMCResult_Continue;
455 list<char*> *fileList;
457 unsigned int ignoreLevel;
458 char cur_file[PLATFORM_MAX_PATH];
465 static MasterReader master_reader;
467 bool CGameConfig::Reparse(char *error, size_t maxlength)
469 /* Reset cached data */
475 char path[PLATFORM_MAX_PATH];
477 /* See if we can use the extended gamedata format. */
478 //TODO pass in path to gamedata somehow
480 /* Otherwise, it's time to parse the master. */
482 SMCStates state = {0, 0};
483 list<char*> fileList;
484 master_reader.fileList = &fileList;
486 err = textparsers->ParseSMCFile(path, &master_reader, &state, error, maxlength);
487 if (err != SMCError_Okay)
489 const char *msg = textparsers->GetSMCErrorString(err);
491 printf("[SM] Error parsing master gameconf file \"%s\":", path);
492 printf("[SM] Error %d on line %d, col %d: %s",
496 msg ? msg : "Unknown error");
500 /* Go through each file we found and parse it. */
501 list<char*>::iterator iter;
502 for (iter = fileList.begin(); iter != fileList.end(); iter++)
504 UTIL_Format(path, sizeof(path), "%s/%s", m_File, *iter);
505 if (!EnterFile(path, error, maxlength))
514 bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
517 SMCStates state = {0, 0};
519 /* Initialize parse states */
521 bShouldBeReadingDefault = true;
522 m_ParseState = PSTATE_NONE;
524 if ((err=textparsers->ParseSMCFile(file, this, &state, error, maxlength))
529 msg = textparsers->GetSMCErrorString(err);
531 printf("[SM] Error parsing gameconfig file \"%s\":\n", file);
532 printf("[SM] Error %d on line %d, col %d: %s\n",
536 msg ? msg : "Unknown error");
538 if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM)
540 //error occurred while parsing a custom section
541 m_CustomHandler->ReadSMC_ParseEnd(true, true);
542 m_CustomHandler = NULL;
552 const char *CGameConfig::GetKeyValue(const char *key)
555 if ((pkey = m_Keys.retrieve(key)) == NULL)
557 return m_pStrings->GetString(*pkey);
560 list<Offset> CGameConfig::GetOffsets() { return m_Offsets; }
561 list<Sig> CGameConfig::GetSigs() { return m_Sigs; }