1.1 --- a/core/GameDataFetcher.cpp Fri Jul 11 06:51:21 2008 +0000
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,693 +0,0 @@
1.4 -/**
1.5 -* vim: set ts=4 :
1.6 -* =============================================================================
1.7 -* SourceMod
1.8 -* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 -* =============================================================================
1.10 -*
1.11 -* This program is free software; you can redistribute it and/or modify it under
1.12 -* the terms of the GNU General Public License, version 3.0, as published by the
1.13 -* Free Software Foundation.
1.14 -*
1.15 -* This program is distributed in the hope that it will be useful, but WITHOUT
1.16 -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 -* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 -* details.
1.19 -*
1.20 -* You should have received a copy of the GNU General Public License along with
1.21 -* this program. If not, see <http://www.gnu.org/licenses/>.
1.22 -*
1.23 -* As a special exception, AlliedModders LLC gives you permission to link the
1.24 -* code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 -* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 -* by the Valve Corporation. You must obey the GNU General Public License in
1.27 -* all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 -* this exception to all derivative works. AlliedModders LLC defines further
1.29 -* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 -* or <http://www.sourcemod.net/license.php>.
1.31 -*
1.32 -* Version: $Id$
1.33 -*/
1.34 -
1.35 -#include "GameDataFetcher.h"
1.36 -#include "bitbuf.h"
1.37 -
1.38 -#ifdef PLATFORM_WINDOWS
1.39 -#include <winsock2.h>
1.40 -#else
1.41 -#include <unistd.h>
1.42 -#include <sys/types.h>
1.43 -#include <sys/socket.h>
1.44 -#include <netinet/in.h>
1.45 -#include <netdb.h>
1.46 -#include <arpa/inet.h>
1.47 -
1.48 -#define INVALID_SOCKET -1
1.49 -#define closesocket close
1.50 -#endif
1.51 -
1.52 -#include "sh_vector.h"
1.53 -#include "sh_string.h"
1.54 -#include "sm_version.h"
1.55 -
1.56 -#ifdef ORANGEBOX_BUILD
1.57 -#include "convar_sm_ob.h"
1.58 -#else
1.59 -#include "convar_sm.h"
1.60 -#endif
1.61 -
1.62 -#include "sourcemm_api.h"
1.63 -#include "time.h"
1.64 -#include "TimerSys.h"
1.65 -#include "compat_wrappers.h"
1.66 -
1.67 -#define QUERY_MAX_LENGTH 1024
1.68 -
1.69 -BuildMD5ableBuffer g_MD5Builder;
1.70 -FetcherThread g_FetchThread;
1.71 -
1.72 -FILE *logfile = NULL;
1.73 -
1.74 -bool g_disableGameDataUpdate = false;
1.75 -bool g_restartAfterUpdate = false;
1.76 -
1.77 -void FetcherThread::RunThread( IThreadHandle *pHandle )
1.78 -{
1.79 - char lock_path[PLATFORM_MAX_PATH];
1.80 - g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp");
1.81 - g_LibSys.CreateFolder(lock_path);
1.82 -
1.83 - g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp/gamedata.lock");
1.84 -
1.85 - g_Logger.LogMessage("Starting experimental gamedata update fetcher... please report problems to bugs.alliedmods.net");
1.86 -
1.87 - char log_path[PLATFORM_MAX_PATH];
1.88 - g_SourceMod.BuildPath(Path_SM, log_path, sizeof(log_path), "logs/gamedata");
1.89 -
1.90 - g_LibSys.CreateFolder(log_path);
1.91 -
1.92 - time_t t;
1.93 - GetAdjustedTime(&t);
1.94 - tm *curtime = localtime(&t);
1.95 -
1.96 - g_SourceMod.BuildPath(Path_SM, log_path, sizeof(log_path), "logs/gamedata/L%02d%02d.log", curtime->tm_mon + 1, curtime->tm_mday);
1.97 -
1.98 - logfile = fopen(log_path, "a");
1.99 -
1.100 - if (!logfile)
1.101 - {
1.102 - g_Logger.LogError("Failed to create GameData log file");
1.103 - return;
1.104 - }
1.105 -
1.106 - //Create a blank lock file
1.107 - FILE *fp = fopen(lock_path, "w");
1.108 - if (fp)
1.109 - {
1.110 - fclose(fp);
1.111 - }
1.112 -
1.113 - /* Create a new socket for this connection */
1.114 - int socketDescriptor = ConnectSocket();
1.115 -
1.116 - if (socketDescriptor == INVALID_SOCKET)
1.117 - {
1.118 - fclose(logfile);
1.119 - unlink(lock_path);
1.120 - return;
1.121 - }
1.122 -
1.123 - char query[QUERY_MAX_LENGTH];
1.124 -
1.125 - /* Check for updated gamedata files */
1.126 - int len = BuildGameDataQuery(query, QUERY_MAX_LENGTH);
1.127 -
1.128 - if (len == 0)
1.129 - {
1.130 - g_Logger.LogToOpenFile(logfile, "Query Writing failed");
1.131 -
1.132 - closesocket(socketDescriptor);
1.133 - fclose(logfile);
1.134 - unlink(lock_path);
1.135 - return;
1.136 - }
1.137 -
1.138 - if (g_disableGameDataUpdate)
1.139 - {
1.140 - g_Logger.LogMessage("Skipping GameData Query due to DisableAutoUpdate being set to true");
1.141 -
1.142 - closesocket(socketDescriptor);
1.143 - fclose(logfile);
1.144 - unlink(lock_path);
1.145 - return;
1.146 - }
1.147 -
1.148 - int sent = NonBlockingSend(socketDescriptor, query, len);
1.149 -
1.150 - g_Logger.LogToOpenFile(logfile, "Sent Query!");
1.151 -
1.152 - if (sent == 0)
1.153 - {
1.154 - g_Logger.LogToOpenFile(logfile, "Failed to send data");
1.155 -
1.156 - closesocket(socketDescriptor);
1.157 - fclose(logfile);
1.158 - unlink(lock_path);
1.159 - return;
1.160 - }
1.161 -
1.162 - ProcessGameDataQuery(socketDescriptor);
1.163 -
1.164 - /* And we're done! */
1.165 - closesocket(socketDescriptor);
1.166 - fclose(logfile);
1.167 - unlink(lock_path);
1.168 -}
1.169 -
1.170 -void FetcherThread::OnTerminate( IThreadHandle *pHandle, bool cancel )
1.171 -{
1.172 - //delete this;
1.173 -}
1.174 -
1.175 -int FetcherThread::BuildGameDataQuery( char *buffer, int maxlen )
1.176 -{
1.177 - char gamedata_path[PLATFORM_MAX_PATH];
1.178 - g_SourceMod.BuildPath(Path_SM, gamedata_path, sizeof(gamedata_path), "gamedata");
1.179 -
1.180 - IDirectory *dir = g_LibSys.OpenDirectory(gamedata_path);
1.181 -
1.182 - if (dir == NULL)
1.183 - {
1.184 - return 0;
1.185 - }
1.186 -
1.187 - bf_write Writer = bf_write("GameDataQuery", buffer, maxlen);
1.188 -
1.189 - Writer.WriteByte('A'); //Generic Header char
1.190 - Writer.WriteByte('G'); //G for gamedata query, or green, like my hat.
1.191 -
1.192 - short build[4] = { SVN_FILE_VERSION };
1.193 -
1.194 - Writer.WriteBytes(&build[0], 8);
1.195 -
1.196 - Writer.WriteByte(0); // Initialize the file counter - Index 10
1.197 -
1.198 - while (dir->MoreFiles())
1.199 - {
1.200 - if (dir->IsEntryFile())
1.201 - {
1.202 - const char *name = dir->GetEntryName();
1.203 - size_t len = strlen(name);
1.204 - if (len >= 4
1.205 - && strcmp(&name[len-4], ".txt") == 0)
1.206 - {
1.207 - char file[PLATFORM_MAX_PATH];
1.208 -
1.209 - g_LibSys.PathFormat(file, sizeof(file), "%s/%s", gamedata_path, name);
1.210 -
1.211 - SMCStates states;
1.212 - if (g_TextParser.ParseFile_SMC(file, &g_MD5Builder, &states) == SMCError_Okay)
1.213 - {
1.214 - unsigned char *md5 = g_MD5Builder.GetMD5();
1.215 - if (md5 != NULL)
1.216 - {
1.217 - (uint8_t)buffer[10]++; //Increment the file counter
1.218 - Writer.WriteBytes(md5, 16);
1.219 -
1.220 - g_Logger.LogToOpenFile(logfile, "%s - \"%s\"", file, g_MD5Builder.GetMD5String());
1.221 -
1.222 - FileData *data = new FileData();
1.223 - data->filename = new SourceHook::String(file);
1.224 - memcpy(data->checksum, g_MD5Builder.GetMD5String(), 33);
1.225 - filenames.push_back(data);
1.226 - }
1.227 - else
1.228 - {
1.229 - g_Logger.LogToOpenFile(logfile, "%s no md5?", file);
1.230 - }
1.231 - }
1.232 - else
1.233 - {
1.234 - g_Logger.LogToOpenFile(logfile, "%s failed!", file);
1.235 - }
1.236 - }
1.237 - }
1.238 -
1.239 - dir->NextEntry();
1.240 - }
1.241 -
1.242 - return Writer.GetNumBytesWritten();
1.243 -}
1.244 -
1.245 -int FetcherThread::ConnectSocket()
1.246 -{
1.247 - struct protoent *ptrp;
1.248 - ptrp = getprotobyname("tcp");
1.249 -
1.250 -#ifdef WIN32
1.251 - WSADATA wsaData;
1.252 - WSAStartup(0x0101, &wsaData);
1.253 -#endif
1.254 -
1.255 - if (ptrp == NULL)
1.256 - {
1.257 - g_Logger.LogToOpenFile(logfile, "Failed to find TCP");
1.258 - return INVALID_SOCKET;
1.259 - }
1.260 -
1.261 - int socketDescriptor = socket(AF_INET, SOCK_STREAM, ptrp->p_proto);
1.262 -
1.263 - if (socketDescriptor == INVALID_SOCKET)
1.264 - {
1.265 - //bugger aye?
1.266 - g_Logger.LogToOpenFile(logfile, "Failed to create a new socket");
1.267 - closesocket(socketDescriptor);
1.268 - return INVALID_SOCKET;
1.269 - }
1.270 -
1.271 - struct hostent *he;
1.272 - struct sockaddr_in local_addr;
1.273 -
1.274 - local_addr.sin_family = AF_INET;
1.275 - local_addr.sin_port = htons((u_short)6500);
1.276 -
1.277 - he = gethostbyname("hayate.alliedmods.net");
1.278 -
1.279 - if (!he)
1.280 - {
1.281 - if ((local_addr.sin_addr.s_addr = inet_addr("hayate.alliedmods.net")) == INADDR_NONE)
1.282 - {
1.283 - g_Logger.LogToOpenFile(logfile, "Couldnt locate address");
1.284 - closesocket(socketDescriptor);
1.285 - return INVALID_SOCKET;
1.286 - }
1.287 - }
1.288 - else
1.289 - {
1.290 - memcpy(&local_addr.sin_addr, (struct in_addr *)he->h_addr, he->h_length);
1.291 - }
1.292 -
1.293 - if (connect(socketDescriptor, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0)
1.294 - {
1.295 - g_Logger.LogToOpenFile(logfile, "Couldn't connect");
1.296 - closesocket(socketDescriptor);
1.297 - return INVALID_SOCKET;
1.298 - }
1.299 -
1.300 - return socketDescriptor;
1.301 -}
1.302 -
1.303 -void FetcherThread::ProcessGameDataQuery(int socketDescriptor)
1.304 -{
1.305 - char buffer[50];
1.306 -
1.307 - g_Logger.LogToOpenFile(logfile, "Waiting for reply!");
1.308 -
1.309 - //Read in the header bytes
1.310 - int returnLen = NonBlockingRecv(socketDescriptor, buffer, 12);
1.311 -
1.312 - g_Logger.LogToOpenFile(logfile, "Recv Completed");
1.313 -
1.314 - if (returnLen == 0)
1.315 - {
1.316 - g_Logger.LogToOpenFile(logfile, ",but it failed.");
1.317 - /* Timeout or fail? */
1.318 - return;
1.319 - }
1.320 -
1.321 - g_Logger.LogToOpenFile(logfile, "Received Header!");
1.322 -
1.323 - bf_read Reader = bf_read("GameDataQuery", buffer, 12);
1.324 -
1.325 - if (Reader.ReadByte() != 'A' || Reader.ReadByte() != 'G')
1.326 - {
1.327 - g_Logger.LogToOpenFile(logfile, "Invalid Query to handle");
1.328 - return;
1.329 - }
1.330 -
1.331 - UpdateStatus updateStatus = (UpdateStatus)Reader.ReadByte();
1.332 -
1.333 - short build[4] = {0,0,0,0};
1.334 -
1.335 - build[0] = Reader.ReadShort();
1.336 - build[1] = Reader.ReadShort();
1.337 - build[2] = Reader.ReadShort();
1.338 - build[3] = Reader.ReadShort();
1.339 -
1.340 - g_Logger.LogToOpenFile(logfile, "Update Status: %i - Latest %i.%i.%i.%i", updateStatus, build[0], build[1], build[2], build[3]);
1.341 -
1.342 - HandleUpdateStatus(updateStatus, build);
1.343 -
1.344 - int changedFiles = Reader.ReadByte();
1.345 -
1.346 - g_Logger.LogToOpenFile(logfile, "Files to download: %i", changedFiles);
1.347 -
1.348 - for (int i=0; i<changedFiles; i++)
1.349 - {
1.350 - //Read in the file index and byte count
1.351 - returnLen = NonBlockingRecv(socketDescriptor, buffer, 5);
1.352 -
1.353 - if (returnLen == 0)
1.354 - {
1.355 - /* Timeout or fail? */
1.356 - return;
1.357 - }
1.358 -
1.359 - Reader.StartReading(buffer, 5);
1.360 -
1.361 - int index = Reader.ReadByte();
1.362 - int tempLen = Reader.ReadUBitLong(32);
1.363 -
1.364 - g_Logger.LogToOpenFile(logfile, "File index %i and length %i", index, tempLen);
1.365 -
1.366 - void *memPtr;
1.367 - memtable->CreateMem(tempLen+1, &memPtr);
1.368 -
1.369 - //Read the contents of our file into the memtable
1.370 - returnLen = NonBlockingRecv(socketDescriptor, (char *)memPtr, tempLen);
1.371 -
1.372 - g_Logger.LogToOpenFile(logfile, "Recieved %i bytes", returnLen);
1.373 -
1.374 - if (returnLen == 0)
1.375 - {
1.376 - /* Timeout or fail? */
1.377 - return;
1.378 - }
1.379 -
1.380 - ((unsigned char *)memPtr)[tempLen] = '\0';
1.381 -
1.382 - FileData *data = filenames.at(index);
1.383 - const char* filename;
1.384 - if (data != NULL)
1.385 - {
1.386 - filename = data->filename->c_str();
1.387 -
1.388 - FILE *fp = fopen(filename, "w");
1.389 -
1.390 - if (fp)
1.391 - {
1.392 - fprintf(fp, (const char *)memPtr);
1.393 - fclose(fp);
1.394 - }
1.395 - }
1.396 - else
1.397 - {
1.398 - filename = "";
1.399 - }
1.400 -
1.401 - memtable->Reset();
1.402 -
1.403 - g_Logger.LogToOpenFile(logfile, "Updated File %s", filename);
1.404 - }
1.405 -
1.406 - g_Logger.LogToOpenFile(logfile, "File Downloads Completed!");
1.407 -
1.408 - bool needsRestart = false;
1.409 -
1.410 - if (changedFiles > 0)
1.411 - {
1.412 - needsRestart = true;
1.413 - g_Logger.LogMessage("New GameData Files have been downloaded to your gamedata directory. Please restart your server for these to take effect");
1.414 - }
1.415 -
1.416 - //Read changed file count
1.417 - returnLen = NonBlockingRecv(socketDescriptor, buffer, 1);
1.418 -
1.419 - if (returnLen == 0)
1.420 - {
1.421 - /* Timeout or fail? */
1.422 - g_Logger.LogToOpenFile(logfile, "Failed to receive unknown count");
1.423 - return;
1.424 - }
1.425 -
1.426 - Reader.StartReading(buffer, 1);
1.427 -
1.428 - changedFiles = Reader.ReadByte();
1.429 -
1.430 - if (changedFiles == 0)
1.431 - {
1.432 - g_Logger.LogToOpenFile(logfile, "No unknown files. We're all done");
1.433 - return;
1.434 - }
1.435 -
1.436 - char *changedFileIndexes = new char[changedFiles];
1.437 -
1.438 - g_Logger.LogToOpenFile(logfile, "%i Files were unknown", changedFiles);
1.439 -
1.440 - returnLen = NonBlockingRecv(socketDescriptor, changedFileIndexes, changedFiles);
1.441 -
1.442 - if (returnLen == 0)
1.443 - {
1.444 - /* Timeout or fail? */
1.445 - g_Logger.LogToOpenFile(logfile, "Failed to receive unknown list");
1.446 - return;
1.447 - }
1.448 -
1.449 - Reader.StartReading(changedFileIndexes, changedFiles);
1.450 -
1.451 - for (int i=0; i<changedFiles; i++)
1.452 - {
1.453 - int index = Reader.ReadByte();
1.454 - char fileName[30];
1.455 -
1.456 - FileData *data = filenames.at(index);
1.457 - const char* pathname;
1.458 - if (data != NULL)
1.459 - {
1.460 - pathname = data->filename->c_str();
1.461 - }
1.462 - else
1.463 - {
1.464 - pathname = "";
1.465 - }
1.466 -
1.467 - g_LibSys.GetFileFromPath(fileName, sizeof(fileName), pathname);
1.468 -
1.469 - g_Logger.LogToOpenFile(logfile, "Unknown File %i : %s", index, fileName);
1.470 - }
1.471 -
1.472 - delete [] changedFileIndexes;
1.473 -
1.474 - if (needsRestart && g_restartAfterUpdate)
1.475 - {
1.476 - g_Logger.LogMessage("Automatically restarting server after a successful gamedata update!");
1.477 - engine->ServerCommand("quit\n");
1.478 - }
1.479 -}
1.480 -
1.481 -int FetcherThread::NonBlockingRecv( int socketDescriptor, char *buffer, int len )
1.482 -{
1.483 - fd_set fds;
1.484 - struct timeval tv;
1.485 -
1.486 - /* Create a 10 Second Timeout */
1.487 - tv.tv_sec = 10;
1.488 - tv.tv_usec = 0;
1.489 -
1.490 - /* Add our socket to a socket set */
1.491 - FD_ZERO(&fds);
1.492 - FD_SET(socketDescriptor, &fds);
1.493 -
1.494 - /* Wait max of 10 seconds for recv to become available */
1.495 - select(socketDescriptor+1, &fds, NULL, NULL, &tv);
1.496 -
1.497 - int bytesReceived = 0;
1.498 -
1.499 - /* Is there a limit on how much we can receive? Some site said 1024 bytes, which will be well short of a file */
1.500 - if (FD_ISSET(socketDescriptor, &fds))
1.501 - {
1.502 - bytesReceived = recv(socketDescriptor, buffer, len, 0);
1.503 - }
1.504 -
1.505 - if (bytesReceived == 0 || bytesReceived == -1)
1.506 - {
1.507 - return 0;
1.508 - }
1.509 -
1.510 - if (bytesReceived < len)
1.511 - {
1.512 - return bytesReceived + NonBlockingRecv(socketDescriptor, buffer+bytesReceived, len-bytesReceived);
1.513 - }
1.514 -
1.515 - return bytesReceived;
1.516 -}
1.517 -
1.518 -int FetcherThread::NonBlockingSend( int socketDescriptor, char *buffer, int len )
1.519 -{
1.520 - fd_set fds;
1.521 - struct timeval tv;
1.522 -
1.523 - tv.tv_sec = 10;
1.524 - tv.tv_usec = 0;
1.525 -
1.526 - FD_ZERO(&fds);
1.527 - FD_SET(socketDescriptor, &fds);
1.528 -
1.529 - select(socketDescriptor+1, NULL, &fds, NULL, &tv);
1.530 -
1.531 - int sentBytes = 0;
1.532 -
1.533 - if (FD_ISSET(socketDescriptor, &fds))
1.534 - {
1.535 - sentBytes = send(socketDescriptor, buffer, len, 0);
1.536 - }
1.537 -
1.538 - if (sentBytes == 0 || sentBytes == -1)
1.539 - {
1.540 - return 0;
1.541 - }
1.542 -
1.543 - if (sentBytes < len)
1.544 - {
1.545 - return sentBytes + NonBlockingSend(socketDescriptor, buffer+sentBytes, len-sentBytes);
1.546 - }
1.547 -
1.548 - return sentBytes;
1.549 -}
1.550 -
1.551 -void FetcherThread::HandleUpdateStatus( UpdateStatus status, short version[4] )
1.552 -{
1.553 - switch (status)
1.554 - {
1.555 - case Update_Unknown:
1.556 - case Update_Current:
1.557 - {
1.558 - break;
1.559 - }
1.560 -
1.561 - case Update_NewBuild:
1.562 - {
1.563 - g_Logger.LogMessage("SourceMod Update: A new SVN build is available from sourcemod.net");
1.564 - g_Logger.LogMessage("Current Version: %i.%i.%i.%i Available: %i.%i.%i.%i", version[0], version[1], version[2], version[3], version[0], version[1], version[2], version[3]);
1.565 - break;
1.566 - }
1.567 -
1.568 - case Update_MinorAvailable:
1.569 - {
1.570 - g_Logger.LogMessage("SourceMod Update: An incremental minor release of SourceMod is now available from sourcemod.net");
1.571 - g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
1.572 - break;
1.573 - }
1.574 -
1.575 - case Update_MajorAvailable:
1.576 - {
1.577 - g_Logger.LogMessage("SourceMod Update: An major release of SourceMod is now available from sourcemod.net");
1.578 - g_Logger.LogMessage("Current Version: %i.%i.%i Available: %i.%i.%i", version[0], version[1], version[2], version[0], version[1], version[2]);
1.579 - break;
1.580 - }
1.581 -
1.582 - case Update_CriticalAvailable:
1.583 - {
1.584 - g_Logger.LogError("SourceMod Update: A new critical release of SourceMod is now available from sourcemod.net. It is strongly recommended that you update");
1.585 - g_Logger.LogMessage("Current Version: %i.%i.%i.%i Available: %i.%i.%i.%i", version[0], version[1], version[2], version[3], version[0], version[1], version[2], version[3]);
1.586 - break;
1.587 - }
1.588 - }
1.589 -}
1.590 -
1.591 -bool g_blockGameDataLoad = false;
1.592 -
1.593 -class InitFetch : public SMGlobalClass
1.594 -{
1.595 -public:
1.596 - void OnSourceModAllInitialized_Post()
1.597 - {
1.598 - char lock_path[PLATFORM_MAX_PATH];
1.599 - g_SourceMod.BuildPath(Path_SM, lock_path, sizeof(lock_path), "data/temp/gamedata.lock");
1.600 -
1.601 - if (g_LibSys.IsPathFile(lock_path) && g_LibSys.PathExists(lock_path))
1.602 - {
1.603 - g_Logger.LogError("sourcemod/data/temp/gamedata.lock file detected. This is most likely due to a crash during GameData updating - Blocking GameData loading");
1.604 - g_Logger.LogError("If this error persists delete the file manually");
1.605 - g_blockGameDataLoad = true;
1.606 - }
1.607 -
1.608 - ThreadParams fetchThreadParams = ThreadParams();
1.609 - fetchThreadParams.prio = ThreadPrio_Low;
1.610 - g_pThreader->MakeThread(&g_FetchThread, &fetchThreadParams);
1.611 - }
1.612 -
1.613 - ConfigResult OnSourceModConfigChanged(const char *key,
1.614 - const char *value,
1.615 - ConfigSource source,
1.616 - char *error,
1.617 - size_t maxlength)
1.618 - {
1.619 - if (strcmp(key, "DisableAutoUpdate") == 0)
1.620 - {
1.621 - if (strcmp(value, "yes") == 0)
1.622 - {
1.623 - g_disableGameDataUpdate = true;
1.624 - return ConfigResult_Accept;
1.625 - }
1.626 - else if (strcmp(value, "no") == 0)
1.627 - {
1.628 - g_disableGameDataUpdate = false;
1.629 - return ConfigResult_Accept;
1.630 - }
1.631 -
1.632 - return ConfigResult_Reject;
1.633 - }
1.634 -
1.635 - if (strcmp(key, "ForceRestartAfterUpdate") == 0)
1.636 - {
1.637 - if (strcmp(value, "yes") == 0)
1.638 - {
1.639 - g_restartAfterUpdate = true;
1.640 - return ConfigResult_Accept;
1.641 - }
1.642 - else if (strcmp(value, "no") == 0)
1.643 - {
1.644 - g_restartAfterUpdate = false;
1.645 - return ConfigResult_Accept;
1.646 - }
1.647 -
1.648 - return ConfigResult_Reject;
1.649 - }
1.650 -
1.651 - return ConfigResult_Ignore;
1.652 - }
1.653 -} g_InitFetch;
1.654 -
1.655 -CON_COMMAND(sm_gamedata_md5, "Checks the MD5 sum for a given gamedata file")
1.656 -{
1.657 -#if !defined ORANGEBOX_BUILD
1.658 - CCommand args;
1.659 -#endif
1.660 -
1.661 - if (args.ArgC() < 2)
1.662 - {
1.663 - g_SMAPI->ConPrint("Usage: sm_gamedata_md5 <file>\n");
1.664 - return;
1.665 - }
1.666 -
1.667 - const char *file = args.Arg(1);
1.668 - if (!file || file[0] == '\0')
1.669 - {
1.670 - g_SMAPI->ConPrint("Usage: sm_gamedata_md5 <file>\n");
1.671 - return;
1.672 - }
1.673 -
1.674 - SourceHook::CVector<FileData *>::iterator iter = g_FetchThread.filenames.begin();
1.675 -
1.676 - FileData *curData;
1.677 -
1.678 - while (iter != g_FetchThread.filenames.end())
1.679 - {
1.680 - curData = (*iter);
1.681 -
1.682 - char fileName[30];
1.683 -
1.684 - g_LibSys.GetFileFromPath(fileName, sizeof(fileName), curData->filename->c_str());
1.685 -
1.686 - if (strcmpi(fileName, file) == 0)
1.687 - {
1.688 - g_SMAPI->ConPrintf("MD5 Sum: %s\n", curData->checksum);
1.689 - return;
1.690 - }
1.691 -
1.692 - iter++;
1.693 - }
1.694 -
1.695 - g_SMAPI->ConPrint("File not found!\n");
1.696 -}