mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-02-26 19:54:14 +01:00
Merged sourcemm-1.4.x back into default
This commit is contained in:
commit
2ea6e744bb
@ -31,8 +31,8 @@
|
||||
-M
|
||||
-$M16384,1048576
|
||||
-K$00400000
|
||||
-LE"c:\programme\borland\delphi7\Projects\Bpl"
|
||||
-LN"c:\programme\borland\delphi7\Projects\Bpl"
|
||||
-LE"c:\program files\borland\delphi7\Projects\Bpl"
|
||||
-LN"c:\program files\borland\delphi7\Projects\Bpl"
|
||||
-w-UNSAFE_TYPE
|
||||
-w-UNSAFE_CODE
|
||||
-w-UNSAFE_CAST
|
||||
|
@ -14,24 +14,31 @@ begin
|
||||
WriteLn('');
|
||||
WriteLn('// Looking up files...');
|
||||
{ Check files }
|
||||
if FileExists(ExtractFilePath(ParamStr(0)) + 'files\hl2launch.exe') then
|
||||
WriteLn('// Found files\hl2launch.exe')
|
||||
if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server.dll.source') then
|
||||
WriteLn('// Found files\server.dll.source')
|
||||
else begin
|
||||
WriteLn('// Error: Couldn''t find files\hl2launch.exe!');
|
||||
WriteLn('// Error: Couldn''t find files\server.dll.source!');
|
||||
ReadLn;
|
||||
exit;
|
||||
end;
|
||||
if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server.dll') then
|
||||
WriteLn('// Found files\server.dll')
|
||||
if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so.source') then
|
||||
WriteLn('// Found files\server_i486.so.source')
|
||||
else begin
|
||||
WriteLn('// Error: Couldn''t find files\server.dll!');
|
||||
WriteLn('// Error: Couldn''t find files\server_i486.so.source!');
|
||||
ReadLn;
|
||||
exit;
|
||||
end;
|
||||
if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so') then
|
||||
WriteLn('// Found files\server_i486.so')
|
||||
if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server.dll.orangebox') then
|
||||
WriteLn('// Found files\server.dll.orangebox')
|
||||
else begin
|
||||
WriteLn('// Error: Couldn''t find files\server_i486.so!');
|
||||
WriteLn('// Error: Couldn''t find files\server.dll.orangebox!');
|
||||
ReadLn;
|
||||
exit;
|
||||
end;
|
||||
if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so.orangebox') then
|
||||
WriteLn('// Found files\server_i486.so.orangebox')
|
||||
else begin
|
||||
WriteLn('// Error: Couldn''t find files\server_i486.so.orangebox!');
|
||||
ReadLn;
|
||||
exit;
|
||||
end;
|
||||
@ -53,9 +60,10 @@ begin
|
||||
{ Compress files }
|
||||
WriteLn('// Compressing files...');
|
||||
eFiles := TStringList.Create;
|
||||
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\hl2launch.exe');
|
||||
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server.dll');
|
||||
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so');
|
||||
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server.dll.source');
|
||||
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so.source');
|
||||
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server.dll.orangebox');
|
||||
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so.orangebox');
|
||||
eStream := TMemoryStream.Create;
|
||||
CompressFiles(eFiles, ExtractFilePath(ParamStr(0)) + 'temp.zip');
|
||||
eStream.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'temp.zip');
|
||||
@ -63,6 +71,7 @@ begin
|
||||
AttachToFile(ExtractFilePath(ParamStr(0)) + 'MMS_Installer.exe', eStream, Version);
|
||||
DeleteFile(ExtractFilePath(ParamStr(0)) + 'temp.zip');
|
||||
eStream.Free;
|
||||
eFiles.Free;
|
||||
WriteLn('// Done.');
|
||||
ReadLn;
|
||||
end.
|
||||
|
Binary file not shown.
@ -1,38 +0,0 @@
|
||||
-$A8
|
||||
-$B-
|
||||
-$C+
|
||||
-$D+
|
||||
-$E-
|
||||
-$F-
|
||||
-$G+
|
||||
-$H+
|
||||
-$I+
|
||||
-$J-
|
||||
-$K-
|
||||
-$L+
|
||||
-$M-
|
||||
-$N+
|
||||
-$O+
|
||||
-$P+
|
||||
-$Q-
|
||||
-$R-
|
||||
-$S-
|
||||
-$T-
|
||||
-$U-
|
||||
-$V+
|
||||
-$W-
|
||||
-$X+
|
||||
-$YD
|
||||
-$Z1
|
||||
-cg
|
||||
-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
|
||||
-H+
|
||||
-W+
|
||||
-M
|
||||
-$M16384,1048576
|
||||
-K$00400000
|
||||
-LE"c:\programme\borland\delphi7\Projects\Bpl"
|
||||
-LN"c:\programme\borland\delphi7\Projects\Bpl"
|
||||
-w-UNSAFE_TYPE
|
||||
-w-UNSAFE_CODE
|
||||
-w-UNSAFE_CAST
|
@ -1,189 +0,0 @@
|
||||
program HL2Launch;
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
uses
|
||||
SysUtils,
|
||||
ShellApi,
|
||||
Windows,
|
||||
Classes;
|
||||
|
||||
procedure LaunchFile(eFile, eStartDir, eParams: String);
|
||||
var eStartInfo: TStartupInfo;
|
||||
eProcInfo: TProcessInformation;
|
||||
begin
|
||||
FillChar(eStartInfo, SizeOf(TStartupInfo), 0);
|
||||
with eStartInfo do begin
|
||||
cb := SizeOf(eStartInfo);
|
||||
dwFlags := STARTF_USESHOWWINDOW;
|
||||
end;
|
||||
|
||||
if (CreateProcess(nil, PChar(eFile + #32 + eParams), nil, nil, False, NORMAL_PRIORITY_CLASS, nil, PChar(eStartDir), eStartInfo, eProcInfo)) then begin
|
||||
try
|
||||
WaitForSingleObject(eProcInfo.hProcess, INFINITE);
|
||||
finally
|
||||
CloseHandle(eProcInfo.hProcess);
|
||||
CloseHandle(eProcInfo.hThread);
|
||||
end;
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 2);
|
||||
Write(' Done.' + #13#10);
|
||||
end
|
||||
else begin
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
|
||||
Write(' Couldn''t start hl2.exe!' + #13#10);
|
||||
end;
|
||||
end;
|
||||
|
||||
function GetFileSize(eFile: String): Int64;
|
||||
var eFindHandle: THandle;
|
||||
eFindData: TWIN32FINDDATA;
|
||||
begin
|
||||
Result := 0;
|
||||
if not FileExists(eFile) then exit;
|
||||
eFindHandle := FindFirstFile(PChar(eFile), eFindData);
|
||||
if eFindHandle = INVALID_HANDLE_VALUE then exit;
|
||||
Result := (eFindData.nFileSizeHigh * (Int64(MAXDWORD) + 1)) + eFindData.nFileSizeLow;
|
||||
FindClose(eFindHandle);
|
||||
end;
|
||||
|
||||
var eStream: TFileStream;
|
||||
ePath, eParams: String;
|
||||
eModDir: String;
|
||||
eSearchRec: TSearchRec;
|
||||
eStr: TStringList;
|
||||
i: integer;
|
||||
CheckSuccessful: Boolean;
|
||||
StartTime: Cardinal;
|
||||
begin
|
||||
ePath := ExtractFilePath(ParamStr(0));
|
||||
for i := 1 to ParamCount do
|
||||
eParams := eParams + #32 + ParamStr(i);
|
||||
Delete(eParams, 1, 1);
|
||||
if Pos('console', LowerCase(eParams)) = 0 then
|
||||
eParams := eParams + ' -console';
|
||||
eStream := nil;
|
||||
eModDir := '';
|
||||
|
||||
SetConsoleTitle('HL2 Launcher');
|
||||
Sleep(200); // wait a few ms until the launch program is closed
|
||||
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 2);
|
||||
WriteLn(' _ _ _ ____ _ _ ');
|
||||
WriteLn('| | | | | |___ \ | | __ _ _ _ _ __ ___| |__ ___ _ __ ');
|
||||
WriteLn('| |_| | | __) | | | / _` | | | | ''_ \ / __| ''_ \ / _ \ ''__|');
|
||||
WriteLn('| _ | |___ / __/ | |__| (_| | |_| | | | | (__| | | | __/ | ');
|
||||
WriteLn('|_| |_|_____|_____| |_____\__,_|\__,_|_| |_|\___|_| |_|\___|_| ');
|
||||
WriteLn(' for listen servers using Metamod:Source');
|
||||
WriteLn('');
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
|
||||
{ Check files }
|
||||
WriteLn('Checking files...');
|
||||
if not FileExists(ePath + 'hl2.exe') then begin
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
|
||||
WriteLn('Error: hl2.exe is missing! Maybe wrong directory? If not, start your HL2 Mod again via Steam and try again.');
|
||||
ReadLn;
|
||||
exit;
|
||||
end;
|
||||
if not FileExists(Copy(ePath, 1, Pos('\steamapps\', LowerCase(ePath))) + 'steam.exe') then begin
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
|
||||
WriteLn('Error: Cannot find steam.exe! Make sure this application is located in your listen server''s directory.');
|
||||
ReadLn;
|
||||
exit;
|
||||
end;
|
||||
{ Verify GameInfo.txt ... }
|
||||
Write('Verifying GameInfo.txt...');
|
||||
if (FindFirst(ePath + '*.*', faDirectory, eSearchRec) = 0) then begin
|
||||
repeat
|
||||
if (FileExists(ePath + eSearchRec.Name + '\GameInfo.txt')) then begin
|
||||
eModDir := eSearchRec.Name;
|
||||
break;
|
||||
end;
|
||||
until (FindNext(eSearchRec) <> 0);
|
||||
end;
|
||||
FindClose(eSearchRec.FindHandle);
|
||||
if eModDir = '' then begin
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
|
||||
WriteLn('');
|
||||
WriteLn('Error: Couldn''t find GameInfo.txt!');
|
||||
ReadLn;
|
||||
exit;
|
||||
end
|
||||
else begin
|
||||
if Pos('game', LowerCase(eParams)) = 0 then // a small test which isn't worth a notice
|
||||
eParams := '-game ' + eSearchRec.Name + #32 + eParams;
|
||||
|
||||
eStr := TStringList.Create;
|
||||
eStr.LoadFromFile(ePath + eModDir + '\GameInfo.txt');
|
||||
if Pos('|gameinfo_path|addons/metamod/bin', LowerCase(eStr.Text)) = 0 then begin
|
||||
CheckSuccessful := False;
|
||||
for i := 0 to eStr.Count -1 do begin
|
||||
if Pos('searchpaths', LowerCase(Trim(eStr[i]))) = 1 then begin
|
||||
if i+3 >= eStr.Count then
|
||||
break;
|
||||
eStr.Insert(i+2, ' GameBin |gameinfo_path|addons/metamod/bin');
|
||||
CheckSuccessful := True;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
if CheckSuccessful then begin
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 2);
|
||||
SetFileAttributes(PChar(ePath + eModDir + '\GameInfo.txt'), 0);
|
||||
eStr.SaveToFile(ePath + eModDir + '\GameInfo.txt');
|
||||
SetFileAttributes(PChar(ePath + eModDir + '\GameInfo.txt'), faReadOnly);
|
||||
Write(' Registered MM:S sucessfully' + #13#10);
|
||||
end
|
||||
else begin
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4);
|
||||
Write(' Unexpected EOF, your GameInfo.txt seems to be corrupt' + #13#10);
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 2);
|
||||
Write(' Done' + #13#10);
|
||||
end;
|
||||
eStr.Free;
|
||||
end;
|
||||
{ ... and set it to write-protected }
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
|
||||
Write('Setting GameInfo.txt to write-protected...');
|
||||
try
|
||||
eStream := TFileStream.Create(ePath + eModDir + '\GameInfo.txt', fmShareDenyWrite);
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 2);
|
||||
Write(' Done.' + #13#10);
|
||||
except
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
|
||||
WriteLn('');
|
||||
WriteLn('Warning: Couldn''t set GameInfo.txt to write-protected!');
|
||||
eStream := nil;
|
||||
end;
|
||||
{ Launch Steam if not opened }
|
||||
ShellExecute(0, 'open', PChar(Copy(ePath, 1, Pos('\steamapps\', LowerCase(ePath))) + 'steam.exe'), nil, PChar(Copy(ePath, 1, Pos('\steamapps\', LowerCase(ePath)))), SW_SHOW);
|
||||
{ Launch game }
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
|
||||
Write('Starting HL2...');
|
||||
StartTime := GetTickCount;
|
||||
LaunchFile(ePath + 'hl2.exe', Copy(ePath, 1, Pos('Steam', ePath)+5), eParams);
|
||||
if (GetTickCount - StartTime < 10000) then begin
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
|
||||
WriteLn('Important: If you experience any problems starting HL2 using this program, please start it once via Steam and try again.');
|
||||
ReadLn;
|
||||
end;
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
|
||||
{ Free GameInfo.txt }
|
||||
Write('Removing read-only again from GameInfo.txt...');
|
||||
if Assigned(eStream) then begin
|
||||
eStream.Free;
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 2);
|
||||
Write(' Done' + #13#10);
|
||||
end
|
||||
else begin
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4);
|
||||
Write(' Skipped' + #13#10);
|
||||
end;
|
||||
{ End message }
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
|
||||
WriteLn('');
|
||||
WriteLn('Thanks for using Metamod:Source! Visit http://www.sourcemm.net/');
|
||||
Sleep(2500);
|
||||
end.
|
Binary file not shown.
@ -31,8 +31,8 @@
|
||||
-M
|
||||
-$M16384,1048576
|
||||
-K$00400000
|
||||
-LE"c:\program files (x86)\borland\delphi7\Projects\Bpl"
|
||||
-LN"c:\program files (x86)\borland\delphi7\Projects\Bpl"
|
||||
-LE"c:\program files\borland\delphi7\Projects\Bpl"
|
||||
-LN"c:\program files\borland\delphi7\Projects\Bpl"
|
||||
-w-UNSAFE_TYPE
|
||||
-w-UNSAFE_CODE
|
||||
-w-UNSAFE_CAST
|
||||
|
Binary file not shown.
@ -10,6 +10,8 @@ function GetAllFiles(Mask: String; Attr: Integer; Recursive: Boolean; ShowDirs:
|
||||
// ftp
|
||||
function GetAllDirs: TStringList;
|
||||
|
||||
function GetModName(const Path: String): String;
|
||||
|
||||
implementation
|
||||
|
||||
uses UnitfrmMain;
|
||||
@ -121,6 +123,20 @@ begin
|
||||
Result := eList;
|
||||
end; }
|
||||
|
||||
function GetModName(const Path: String): String;
|
||||
var i: integer;
|
||||
begin
|
||||
Result := '';
|
||||
for i := Length(Path) -1 downto 1 do begin
|
||||
if (Path[i] = '\') or (Path[i] = '/') then begin
|
||||
Result := Copy(Path, i +1, Length(Path) -i);
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
if (Copy(Result, Length(Result), 1) = '\') or (Copy(Result, Length(Result), 1) = '/') then
|
||||
Result := Copy(Result, 1, Length(Result) -1);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
||||
|
@ -13,11 +13,11 @@ procedure AddSkipped;
|
||||
procedure AddNotFound;
|
||||
procedure DownloadFile(eFile: String; eDestination: String);
|
||||
|
||||
procedure BasicInstallation(ePath: String; SteamInstall, ListenInstall: Boolean; OS: TOS);
|
||||
procedure InstallDedicated(eModPath: String; UseSteam: Boolean);
|
||||
procedure InstallListen(ePath: String);
|
||||
procedure InstallCustom(ePath: String; eOS: TOS);
|
||||
procedure InstallFTP(OS: TOS);
|
||||
procedure BasicInstallation(ePath: String; SteamInstall, ListenInstall: Boolean; OS: TOS; const Source: Boolean);
|
||||
procedure InstallDedicated(eModPath: String; const UseSteam, Source: Boolean);
|
||||
procedure InstallListen(ePath: String; const Source: Boolean);
|
||||
procedure InstallCustom(ePath: String; eOS: TOS; const Source: Boolean);
|
||||
procedure InstallFTP(OS: TOS; const Source: Boolean; const ModDir: String);
|
||||
|
||||
var StartTime: TDateTime;
|
||||
SteamPath: String;
|
||||
@ -32,7 +32,7 @@ uses UnitfrmMain, UnitfrmProxy, UnitFunctions, UnitPackSystem;
|
||||
|
||||
function InstallTime: String;
|
||||
begin
|
||||
Result := FormatDateTime('HH:MM:SS', Now - StartTime);
|
||||
Result := Copy(FormatDateTime('HH:MM:SS', Now - StartTime), 4, 5);
|
||||
end;
|
||||
|
||||
procedure AddStatus(Text: String; Color: TColor; ShowTime: Boolean = True);
|
||||
@ -218,18 +218,16 @@ end;
|
||||
|
||||
{ Basic Installation }
|
||||
|
||||
procedure BasicInstallation(ePath: String; SteamInstall, ListenInstall: Boolean; OS: TOS);
|
||||
procedure BasicInstallation(ePath: String; SteamInstall, ListenInstall: Boolean; OS: TOS; const Source: Boolean);
|
||||
var eStr: TStringList;
|
||||
i: integer;
|
||||
CopyConfig: Boolean;
|
||||
eFound: Boolean;
|
||||
begin
|
||||
frmMain.ggeAll.MaxValue := 8;
|
||||
frmMain.ggeAll.Progress := 0;
|
||||
frmMain.ggeItem.MaxValue := 1;
|
||||
frmMain.ggeItem.Progress := 0;
|
||||
|
||||
if (GetProcessID('Steam.exe') <> -1) and (SteamInstall) then begin
|
||||
{if (GetProcessID('Steam.exe') <> -1) and (SteamInstall) then begin
|
||||
if MessageBox(frmMain.Handle, 'Steam is still running. It is necersarry to shut it down before you install Metamod:Source. Shut it down now?', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNO) = mrYes then begin
|
||||
AddStatus('Shutting down Steam...', clBlack, False);
|
||||
if GetProcessID('Steam.exe') = -1 then
|
||||
@ -247,13 +245,13 @@ begin
|
||||
Application.Terminate;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;}
|
||||
frmMain.ggeAll.Progress := 1;
|
||||
frmMain.ggeItem.Progress := 1;
|
||||
{ Unpack }
|
||||
frmMain.ggeItem.Progress := 0;
|
||||
AddStatus('Unpacking files...', clBlack);
|
||||
if not Unpack() then begin
|
||||
if not Unpack(Source) then begin
|
||||
AddStatus('No files attached!', clRed);
|
||||
Screen.Cursor := crDefault;
|
||||
exit;
|
||||
@ -265,8 +263,8 @@ begin
|
||||
CopyConfig := True;
|
||||
AddStatus('Creating directories...', clBlack);
|
||||
if DirectoryExists(ePath + 'addons\metamod\bin') then begin
|
||||
case MessageBox(frmMain.Handle, 'A Metamod:Source installation was already detected. If you choose to reinstall, your configuration files will be erased. Click Yes to continue, No to Upgrade, or Cancel to abort the install.', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNOCANCEL) of
|
||||
mrNo: CopyConfig := False;
|
||||
case MessageBox(frmMain.Handle, 'A Metamod:Source installation was already detected. If you choose to reinstall, your configuration files will be erased. Click Yes to upgrade, No to reinstall, or Cancel to abort the installation.', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNOCANCEL) of
|
||||
mrYes: CopyConfig := False;
|
||||
mrCancel: begin
|
||||
Application.Terminate;
|
||||
exit;
|
||||
@ -282,7 +280,7 @@ begin
|
||||
frmMain.ggeItem.Progress := 1;
|
||||
frmMain.ggeAll.Progress := 3;
|
||||
|
||||
{ gameinfo.txt }
|
||||
{ gameinfo.txt for check / create VDF file }
|
||||
if not FileExists(ePath + 'gameinfo.txt') then begin
|
||||
if MessageBox(frmMain.Handle, 'The file "gameinfo.txt" couldn''t be found. Continue installation?', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNO) = mrNo then begin
|
||||
AddStatus('Installation canceled by user!', clRed, False);
|
||||
@ -304,33 +302,32 @@ begin
|
||||
AddSkipped;
|
||||
frmMain.ggeItem.Progress := 1;
|
||||
frmMain.ggeAll.Progress := 4;
|
||||
{ Gameinfo.txt }
|
||||
{ CDF Plugin }
|
||||
frmMain.ggeItem.Progress := 0;
|
||||
eFound := False;
|
||||
AddStatus('Editing gameinfo.txt...', clBlack);
|
||||
eStr.LoadFromFile(ePath + 'gameinfo.txt');
|
||||
for i := 0 to eStr.Count -1 do begin
|
||||
if Trim(LowerCase(eStr[i])) = 'gamebin |gameinfo_path|addons/metamod/bin' then begin
|
||||
eFound := True;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
if not eFound then begin
|
||||
for i := 0 to eStr.Count -1 do begin
|
||||
if Trim(eStr[i]) = 'SearchPaths' then begin
|
||||
eStr.Insert(i +2, ' GameBin |gameinfo_path|addons/metamod/bin');
|
||||
AddStatus('Creating VDF Plugin...', clBlack);
|
||||
if (FileExists(ePath + 'addons\metamod.vdf')) then begin
|
||||
eStr.LoadFromFile(ePath + 'addons\metamod.vdf');
|
||||
if (Pos('server.dll', eStr.Text) <> 0) then
|
||||
AddSkipped
|
||||
else begin
|
||||
eStr.Add('');
|
||||
eStr.Add('"Plugin"');
|
||||
eStr.Add('{');
|
||||
eStr.Add(' "file" "..\' + GetModName(ePath) + '\addons\metamod\bin\server.dll"');
|
||||
eStr.Add('}');
|
||||
eStr.SaveToFile(ePath + 'addons\metamod.vdf');
|
||||
AddDone;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
SetFileAttributes(PChar(ePath + 'gameinfo.txt'), 0);
|
||||
eStr.SaveToFile(ePath + 'gameinfo.txt');
|
||||
SetFileAttributes(PChar(ePath + 'gameinfo.txt'), faReadOnly); // important for listen servers
|
||||
AddDone;
|
||||
end
|
||||
else
|
||||
AddSkipped;
|
||||
else begin
|
||||
eStr.Add('');
|
||||
eStr.Add('"Plugin"');
|
||||
eStr.Add('{');
|
||||
eStr.Add(' "file" "..\' + GetModName(ePath) + '\addons\metamod\bin\server.dll"');
|
||||
eStr.Add('}');
|
||||
eStr.SaveToFile(ePath + 'addons\metamod.vdf');
|
||||
AddDone;
|
||||
end;
|
||||
eStr.Free;
|
||||
frmMain.ggeItem.Progress := 1;
|
||||
frmMain.ggeAll.Progress := 5;
|
||||
@ -342,16 +339,9 @@ begin
|
||||
AddDone;
|
||||
frmMain.ggeItem.Progress := 1;
|
||||
frmMain.ggeAll.Progress := 6;
|
||||
if ListenInstall then begin
|
||||
ePath := ExtractFilePath(Copy(ePath, 1, Length(ePath)-1));
|
||||
AddStatus('Copying hl2launch.exe...', clBlack);
|
||||
CopyFile(PChar(ExtractFilePath(ParamStr(0)) + 'hl2launch.exe'), PChar(ePath + 'hl2launch.exe'), False);
|
||||
AddDone;
|
||||
end;
|
||||
{ Remove files }
|
||||
frmMain.ggeItem.Progress := 0;
|
||||
AddStatus('Removing temporary files...', clBlack);
|
||||
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'hl2launch.exe'));
|
||||
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server.dll'));
|
||||
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server_i486.so'));
|
||||
AddDone;
|
||||
@ -363,44 +353,41 @@ begin
|
||||
frmMain.cmdNext.Enabled := True;
|
||||
frmMain.cmdCancel.Hide;
|
||||
Screen.Cursor := crDefault;
|
||||
|
||||
if ListenInstall then
|
||||
MessageBox(frmMain.Handle, PChar('hl2launch.exe has been copied to ' + ePath + '. You can use it if you want to start your Source game with Metamod:Source enabled.'), PChar(Application.Title), MB_ICONINFORMATION);
|
||||
end;
|
||||
|
||||
{ Dedicated Server }
|
||||
|
||||
procedure InstallDedicated(eModPath: String; UseSteam: Boolean);
|
||||
procedure InstallDedicated(eModPath: String; const UseSteam, Source: Boolean);
|
||||
begin
|
||||
StartTime := Now;
|
||||
Screen.Cursor := crHourGlass;
|
||||
AddStatus('Starting Metamod:Source installation on dedicated server...', clBlack, False);
|
||||
BasicInstallation(eModPath, UseSteam, False, osWindows);
|
||||
BasicInstallation(eModPath, UseSteam, False, osWindows, Source);
|
||||
end;
|
||||
|
||||
{ Listen Server }
|
||||
|
||||
procedure InstallListen(ePath: String);
|
||||
procedure InstallListen(ePath: String; const Source: Boolean);
|
||||
begin
|
||||
StartTime := Now;
|
||||
Screen.Cursor := crHourGlass;
|
||||
AddStatus('Starting Metamod:Source installation on the listen server...', clBlack);
|
||||
BasicInstallation(ePath, True, True, osWindows);
|
||||
BasicInstallation(ePath, True, True, osWindows, Source);
|
||||
end;
|
||||
|
||||
{ Custom mod }
|
||||
|
||||
procedure InstallCustom(ePath: String; eOS: TOS);
|
||||
procedure InstallCustom(ePath: String; eOS: TOS; const Source: Boolean);
|
||||
begin
|
||||
StartTime := Now;
|
||||
Screen.Cursor := crHourGlass;
|
||||
AddStatus('Starting Metamod:Source installation...', clBlack);
|
||||
BasicInstallation(ePath, False, False, eOS);
|
||||
BasicInstallation(ePath, False, False, eOS, Source);
|
||||
end;
|
||||
|
||||
{ FTP }
|
||||
|
||||
procedure InstallFTP(OS: TOS);
|
||||
procedure InstallFTP(OS: TOS; const Source: Boolean; const ModDir: String);
|
||||
function DoReconnect: Boolean;
|
||||
begin
|
||||
Result := False;
|
||||
@ -414,11 +401,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
label CreateAgain;
|
||||
label UploadAgain;
|
||||
|
||||
var eStr: TStringList;
|
||||
i: integer;
|
||||
CopyConfig, eFound: Boolean;
|
||||
CopyConfig, CommentFound: Boolean;
|
||||
i: Integer;
|
||||
begin
|
||||
frmMain.cmdCancel.Show;
|
||||
frmMain.cmdNext.Hide;
|
||||
@ -426,72 +415,27 @@ begin
|
||||
|
||||
frmMain.ggeAll.MaxValue := 6;
|
||||
frmMain.ggeAll.Progress := 0;
|
||||
frmMain.ggeItem.MaxValue := 1;
|
||||
frmMain.ggeItem.MaxValue := 3;
|
||||
frmMain.ggeItem.Progress := 0;
|
||||
|
||||
StartTime := Now;
|
||||
{ Unpack }
|
||||
frmMain.ggeItem.Progress := 0;
|
||||
AddStatus('Unpacking files...', clBlack);
|
||||
if not Unpack() then begin
|
||||
if not Unpack(Source) then begin
|
||||
AddStatus('No files attached!', clRed);
|
||||
Screen.Cursor := crDefault;
|
||||
exit;
|
||||
end;
|
||||
AddDone;
|
||||
frmMain.ggeAll.Progress := 2;
|
||||
frmMain.ggeAll.Progress := 1;
|
||||
frmMain.ggeItem.Progress := 1;
|
||||
{ Check for installation }
|
||||
AddStatus('Editing gameinfo.txt...', clBlack);
|
||||
eStr := TStringList.Create;
|
||||
DownloadFile('gameinfo.txt', ExtractFilePath(ParamStr(0)) + 'gameinfo.txt');
|
||||
eStr.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'gameinfo.txt');
|
||||
|
||||
CopyConfig := True;
|
||||
eFound := False;
|
||||
for i := 0 to eStr.Count -1 do begin
|
||||
if Trim(LowerCase(eStr[i])) = 'gamebin |gameinfo_path|addons/metamod/bin' then begin
|
||||
eFound := True;
|
||||
case MessageBox(frmMain.Handle, 'A Metamod:Source installation was already detected. If you choose to reinstall, your configuration files will be erased. Click Yes to continue, No to Upgrade, or Cancel to abort the install.', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNOCANCEL) of
|
||||
mrNo: CopyConfig := False;
|
||||
mrCancel: begin
|
||||
Application.Terminate;
|
||||
eStr.Free;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
if not eFound then begin
|
||||
for i := 0 to eStr.Count -1 do begin
|
||||
if Trim(eStr[i]) = 'SearchPaths' then begin
|
||||
eStr.Insert(i +2, ' GameBin |gameinfo_path|addons/metamod/bin');
|
||||
AddDone;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
eStr.SaveToFile(ExtractFilePath(ParamStr(0)) + 'gameinfo.txt');
|
||||
UploadFile(ExtractFilePath(ParamStr(0)) + 'gameinfo.txt', 'gameinfo.txt');
|
||||
try
|
||||
AddStatus('Trying to set gameinfo.txt to read-only...', clBlack);
|
||||
frmMain.IdFTP.Site('CHMOD 744 gameinfo.txt');
|
||||
AddDone;
|
||||
except
|
||||
AddStatus('Warning: CHMOD not supported.', clMaroon);
|
||||
end;
|
||||
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'gameinfo.txt'));
|
||||
end
|
||||
else
|
||||
AddSkipped;
|
||||
frmMain.ggeAll.Progress := 3;
|
||||
frmMain.ggeItem.Progress := 1;
|
||||
|
||||
Sleep(250);
|
||||
{ Create directories }
|
||||
frmMain.ggeAll.Progress := 2;
|
||||
frmMain.ggeItem.Progress := 0;
|
||||
frmMain.ggeItem.MaxValue := 3;
|
||||
|
||||
AddStatus('Creating directories...', clBlack);
|
||||
if not eFound then begin
|
||||
try
|
||||
FTPMakeDir('addons');
|
||||
frmMain.IdFTP.ChangeDir('addons');
|
||||
frmMain.ggeItem.Progress := 1;
|
||||
@ -501,24 +445,108 @@ begin
|
||||
FTPMakeDir('bin');
|
||||
frmMain.ggeItem.Progress := 3;
|
||||
AddDone;
|
||||
end
|
||||
else
|
||||
except
|
||||
AddSkipped;
|
||||
frmMain.ggeAll.Progress := 4;
|
||||
end;
|
||||
{ Check VDF Plugin }
|
||||
CopyConfig := True;
|
||||
|
||||
frmMain.ggeAll.Progress := 3;
|
||||
frmMain.ggeItem.Progress := 0;
|
||||
|
||||
AddStatus('Creating VDF Plugin...', clBlack);
|
||||
eStr := TStringList.Create;
|
||||
try
|
||||
frmMain.IdFTP.ChangeDirUp;
|
||||
|
||||
frmMain.ggeItem.Progress := 1;
|
||||
DownloadFile('metamod.vdf', ExtractFilePath(ParamStr(0)) + 'metamod.vdf');
|
||||
eStr.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'metamod.vdf');
|
||||
frmMain.ggeItem.Progress := 2;
|
||||
if (((Pos('server.dll', eStr.Text) <> 0) and (OS = osWindows)) or ((Pos('server_i486.so', eStr.Text) <> 0) and (OS = osLinux))) then begin
|
||||
case MessageBox(frmMain.Handle, 'A Metamod:Source installation was already detected. If you choose to reinstall, your configuration files will be erased. Click Yes to upgrade, No to reinstall, or Cancel to abort the installation.', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNOCANCEL) of
|
||||
mrYes: CopyConfig := False;
|
||||
mrCancel: begin
|
||||
Application.Terminate;
|
||||
eStr.Free;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
except
|
||||
// bacon
|
||||
end;
|
||||
{ Create and Upload plugin here }
|
||||
frmMain.ggeItem.Progress := 2;
|
||||
eStr.Clear;
|
||||
eStr.Add('"Plugin"');
|
||||
eStr.Add('{');
|
||||
if (OS = osWindows) then
|
||||
eStr.Add(' "file" "..\' + ModDir + '\addons\metamod\bin\server.dll"')
|
||||
else
|
||||
eStr.Add(' "file" "../' + ModDir + '/addons/metamod/bin/server_i486.so"');
|
||||
eStr.Add('}');
|
||||
eStr.SaveToFile(ExtractFilePath(ParamStr(0)) + 'metamod.vdf');
|
||||
UploadFile(ExtractFilePath(ParamStr(0)) + 'metamod.vdf', 'metamod.vdf');
|
||||
frmMain.ggeItem.Progress := 3;
|
||||
{ Upload metaplugins.ini }
|
||||
frmMain.ggeAll.Progress := 4;
|
||||
frmMain.ggeItem.MaxValue := 1;
|
||||
frmMain.ggeItem.Progress := 0;
|
||||
AddStatus('Uploading metaplugins.ini...', clBlack);
|
||||
if CopyConfig then begin
|
||||
frmMain.IdFTP.ChangeDir('metamod');
|
||||
if (CopyConfig) then begin
|
||||
eStr.Clear;
|
||||
// see http://svn.alliedmods.net/viewvc.cgi/metamodsource/orangebox/addons/metamod/metaplugins.ini?revision=1099&root=Packages
|
||||
eStr.Add(';List one plugin per line. Each line should contain the path to the plugin''s binary.');
|
||||
eStr.Add(';Any line starting with a '';'' character is a comment line, and is ignored.');
|
||||
eStr.Add(';');
|
||||
eStr.Add(';You do not need to include the _i486.so or .dll part of the file name. Example:');
|
||||
eStr.Add('; addons/sourcemod/bin/sourcemod_mm');
|
||||
eStr.Add(';You may also put an alias in front of the file, for example:');
|
||||
eStr.Add('; sm addons/sourcemod/bin/sourcemod_mm');
|
||||
eStr.Add(';Will allow you to use "meta load sm" from the console.');
|
||||
eStr.Add(';');
|
||||
eStr.Add(';********* LIST PLUGINS BELOW ***********');
|
||||
// end
|
||||
eStr.SaveToFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini');
|
||||
UploadFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini', 'metaplugins.ini');
|
||||
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini'));
|
||||
end
|
||||
else
|
||||
AddSkipped;
|
||||
else if (frmMain.IdFTP.Size('metaplugins.ini') <> -1) then begin
|
||||
DownloadFile('metaplugins.ini', ExtractFilePath(ParamStr(0)) + 'metaplugins.ini');
|
||||
eStr.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini');
|
||||
CommentFound := False;
|
||||
for i := 0 to eStr.Count -1 do begin
|
||||
if (Pos(';', eStr[i]) = 1) then begin
|
||||
CommentFound := True;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
if (CommentFound) then
|
||||
AddSkipped
|
||||
else begin
|
||||
// delete empty lines first
|
||||
for i := eStr.Count -1 downto 0 do begin
|
||||
if (Trim(eStr[i]) = '') then
|
||||
eStr.Delete(i);
|
||||
end;
|
||||
// see http://svn.alliedmods.net/viewvc.cgi/metamodsource/orangebox/addons/metamod/metaplugins.ini?revision=1099&root=Packages
|
||||
eStr.Insert(0, ';List one plugin per line. Each line should contain the path to the plugin''s binary.');
|
||||
eStr.Insert(1, ';Any line starting with a '';'' character is a comment line, and is ignored.');
|
||||
eStr.Insert(2, ';');
|
||||
eStr.Insert(3, ';You do not need to include the _i486.so or .dll part of the file name. Example:');
|
||||
eStr.Insert(4, '; addons/sourcemod/bin/sourcemod_mm');
|
||||
eStr.Insert(5, ';You may also put an alias in front of the file, for example:');
|
||||
eStr.Insert(6, '; sm addons/sourcemod/bin/sourcemod_mm');
|
||||
eStr.Insert(7, ';Will allow you to use "meta load sm" from the console.');
|
||||
eStr.Insert(8, ';');
|
||||
eStr.Insert(9, ';********* LIST PLUGINS BELOW ***********');
|
||||
// end
|
||||
eStr.SaveToFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini');
|
||||
UploadFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini', 'metaplugins.ini');
|
||||
end;
|
||||
end;
|
||||
frmMain.ggeAll.Progress := 5;
|
||||
frmMain.ggeItem.Progress := 1;
|
||||
{ Upload server.dll / server_i486.so }
|
||||
@ -537,9 +565,10 @@ begin
|
||||
end;
|
||||
{ Remove created files }
|
||||
AddStatus('Removing temporary files...', clBlack);
|
||||
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'hl2launch.exe'));
|
||||
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server.dll'));
|
||||
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server_i486.so'));
|
||||
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'metamod.vdf'));
|
||||
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini'));
|
||||
AddDone;
|
||||
{ End }
|
||||
frmMain.IdFTP.Disconnect;
|
||||
|
@ -5,10 +5,10 @@ interface
|
||||
uses SysUtils, Classes, Zlib;
|
||||
|
||||
procedure CompressFiles(Files: TStrings; const Filename: String);
|
||||
function DecompressStream(Stream : TMemoryStream; DestDirectory : String): Boolean;
|
||||
function DecompressStream(Stream: TMemoryStream; DestDirectory: String; const Source: Boolean): Boolean;
|
||||
function AttachToFile(const AFileName: string; MemoryStream: TMemoryStream; Version: String): Boolean;
|
||||
function LoadFromFile(const AFileName: string; MemoryStream: TMemoryStream): Boolean;
|
||||
function Unpack: Boolean;
|
||||
function Unpack(const Source: Boolean): Boolean;
|
||||
function GetVersion: String;
|
||||
|
||||
implementation
|
||||
@ -54,6 +54,8 @@ begin
|
||||
{ append the compressed file to the destination file }
|
||||
tmpFile := TFileStream.Create('tmp',fmOpenRead);
|
||||
try
|
||||
l := tmpFile.Size;
|
||||
outfile.WriteBuffer(l, SizeOf(l));
|
||||
outfile.CopyFrom(tmpFile,0);
|
||||
finally
|
||||
tmpFile.Free;
|
||||
@ -68,12 +70,13 @@ begin
|
||||
DeleteFile('tmp');
|
||||
end;
|
||||
end;
|
||||
function DecompressStream(Stream : TMemoryStream; DestDirectory : String): Boolean;
|
||||
|
||||
function DecompressStream(Stream : TMemoryStream; DestDirectory : String; const Source: Boolean): Boolean;
|
||||
var
|
||||
dest,s : String;
|
||||
decompr : TDecompressionStream;
|
||||
outfile : TFilestream;
|
||||
i,l,c : Integer;
|
||||
i,l,lr,c : Integer;
|
||||
begin
|
||||
// IncludeTrailingPathDelimiter (D6/D7 only)
|
||||
dest := IncludeTrailingPathDelimiter(DestDirectory);
|
||||
@ -82,14 +85,17 @@ begin
|
||||
try
|
||||
{ number of files }
|
||||
Stream.Read(c,SizeOf(c));
|
||||
for i := 1 to c do
|
||||
begin
|
||||
for i := 1 to c do begin
|
||||
{ read filename }
|
||||
Stream.Read(l,SizeOf(l));
|
||||
SetLength(s,l);
|
||||
Stream.Read(s[1],l);
|
||||
{ read filesize }
|
||||
Stream.Read(l,SizeOf(l));
|
||||
Stream.Read(lr,SizeOf(lr));
|
||||
{ check if this is the right file }
|
||||
if ((Pos('.source', s) <> 0) and (Source)) or ((Pos('.orangebox', s) <> 0) and (not Source)) then begin
|
||||
{ remove extension and read filesize }
|
||||
s := ChangeFileExt(s, '');
|
||||
{ decompress the files and store it }
|
||||
s := dest+s; //include the path
|
||||
outfile := TFileStream.Create(s,fmCreate);
|
||||
@ -100,6 +106,9 @@ begin
|
||||
outfile.Free;
|
||||
decompr.Free;
|
||||
end;
|
||||
end
|
||||
else
|
||||
Stream.Position := Stream.Position + lr;
|
||||
end;
|
||||
finally
|
||||
Result := True;
|
||||
@ -114,6 +123,7 @@ begin
|
||||
Result := False;
|
||||
if not FileExists(AFileName) then
|
||||
Exit;
|
||||
|
||||
try
|
||||
aStream := TFileStream.Create(AFileName, fmOpenWrite or fmShareDenyWrite);
|
||||
MemoryStream.Seek(0, soFromBeginning);
|
||||
@ -177,14 +187,14 @@ end;
|
||||
|
||||
{ Unpack function }
|
||||
|
||||
function Unpack: Boolean;
|
||||
function Unpack(const Source: Boolean): Boolean;
|
||||
var eStream: TMemoryStream;
|
||||
begin
|
||||
eStream := TMemoryStream.Create;
|
||||
try
|
||||
// Get ZIP
|
||||
LoadFromFile(ParamStr(0), eStream);
|
||||
DecompressStream(eStream, ExtractFilePath(ParamStr(0))); // Unpack files
|
||||
DecompressStream(eStream, ExtractFilePath(ParamStr(0)), Source); // Unpack files
|
||||
|
||||
Result := True;
|
||||
except
|
||||
|
Binary file not shown.
@ -5,7 +5,7 @@ interface
|
||||
uses
|
||||
SysUtils, Windows, Messages, Classes, Graphics, Controls,
|
||||
StdCtrls, ExtCtrls, Forms, FileCtrl, ComCtrls, ShellCtrls,
|
||||
TFlatComboBoxUnit, TFlatButtonUnit;
|
||||
TFlatComboBoxUnit, TFlatButtonUnit, TFlatCheckBoxUnit;
|
||||
|
||||
type
|
||||
TfrmSelectModPath = class(TForm)
|
||||
@ -14,6 +14,8 @@ type
|
||||
trvDirectory: TShellTreeView;
|
||||
cmdOK: TFlatButton;
|
||||
cmdCancel: TFlatButton;
|
||||
chkUsesOrangebox: TFlatCheckBox;
|
||||
procedure trvDirectoryClick(Sender: TObject);
|
||||
end;
|
||||
|
||||
var
|
||||
@ -23,4 +25,11 @@ implementation
|
||||
|
||||
{$R *.DFM}
|
||||
|
||||
procedure TfrmSelectModPath.trvDirectoryClick(Sender: TObject);
|
||||
begin
|
||||
// !! OrangeBox Check !!
|
||||
if (trvDirectory.Selected <> nil) then
|
||||
chkUsesOrangebox.Checked := (chkUsesOrangebox.Checked) or (trvDirectory.Selected.Text = 'tf');
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -10407,7 +10407,7 @@ object frmMain: TfrmMain
|
||||
Lines.Strings = (
|
||||
'The zlib/libpng License'
|
||||
''
|
||||
'Copyright (c) 2006, AlliedModders'
|
||||
'Copyright (c) 2006-2008, AlliedModders'
|
||||
''
|
||||
|
||||
'This software is provided '#39'as-is'#39', without any express or implie' +
|
||||
@ -10838,12 +10838,12 @@ object frmMain: TfrmMain
|
||||
Height = 13
|
||||
Caption = '2. Connect to server and select the mod directory:'
|
||||
end
|
||||
object lblStep4: TLabel
|
||||
object lblStep5: TLabel
|
||||
Left = 44
|
||||
Top = 296
|
||||
Top = 338
|
||||
Width = 64
|
||||
Height = 13
|
||||
Caption = '4. Click Next.'
|
||||
Caption = '5. Click Next.'
|
||||
end
|
||||
object lblStep3: TLabel
|
||||
Left = 44
|
||||
@ -10852,6 +10852,13 @@ object frmMain: TfrmMain
|
||||
Height = 13
|
||||
Caption = '3. Select the operating system of your server:'
|
||||
end
|
||||
object lblStep4: TLabel
|
||||
Left = 44
|
||||
Top = 296
|
||||
Width = 125
|
||||
Height = 13
|
||||
Caption = '4. Select the engine type:'
|
||||
end
|
||||
object pnlHeader3: TPanel
|
||||
Left = 0
|
||||
Top = 0
|
||||
@ -11130,7 +11137,7 @@ object frmMain: TfrmMain
|
||||
TabStop = True
|
||||
end
|
||||
object optLinux: TFlatRadioButton
|
||||
Left = 173
|
||||
Left = 183
|
||||
Top = 3
|
||||
Width = 82
|
||||
Height = 14
|
||||
@ -11138,7 +11145,7 @@ object frmMain: TfrmMain
|
||||
TabOrder = 1
|
||||
end
|
||||
object FlatRadioButton1: TFlatRadioButton
|
||||
Left = 353
|
||||
Left = 319
|
||||
Top = 3
|
||||
Width = 82
|
||||
Height = 14
|
||||
@ -11147,6 +11154,40 @@ object frmMain: TfrmMain
|
||||
TabOrder = 2
|
||||
end
|
||||
end
|
||||
object pnlEngineType: TPanel
|
||||
Left = 44
|
||||
Top = 312
|
||||
Width = 441
|
||||
Height = 21
|
||||
BevelOuter = bvLowered
|
||||
TabOrder = 5
|
||||
object optAutoDetect: TFlatRadioButton
|
||||
Left = 1
|
||||
Top = 3
|
||||
Width = 154
|
||||
Height = 14
|
||||
Caption = 'Auto-Detect (recommended)'
|
||||
Checked = True
|
||||
TabOrder = 0
|
||||
TabStop = True
|
||||
end
|
||||
object optSource: TFlatRadioButton
|
||||
Left = 183
|
||||
Top = 3
|
||||
Width = 96
|
||||
Height = 15
|
||||
Caption = 'Source'#8482' Engine'
|
||||
TabOrder = 1
|
||||
end
|
||||
object optOrangeBox: TFlatRadioButton
|
||||
Left = 319
|
||||
Top = 3
|
||||
Width = 118
|
||||
Height = 15
|
||||
Caption = 'OrangeBox'#8482' Engine'
|
||||
TabOrder = 2
|
||||
end
|
||||
end
|
||||
end
|
||||
object jspInstallProgress: TJvStandardPage
|
||||
Left = 0
|
||||
@ -11404,8 +11445,8 @@ object frmMain: TfrmMain
|
||||
end
|
||||
end
|
||||
object ilImages: TImageList
|
||||
Left = 154
|
||||
Top = 324
|
||||
Left = 334
|
||||
Top = 8
|
||||
Bitmap = {
|
||||
494C010102000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
|
||||
0000000000003600000028000000400000001000000001002000000000000010
|
||||
@ -11555,23 +11596,23 @@ object frmMain: TfrmMain
|
||||
OnWork = IdFTPWork
|
||||
ProxySettings.ProxyType = fpcmNone
|
||||
ProxySettings.Port = 0
|
||||
Left = 274
|
||||
Top = 324
|
||||
Left = 454
|
||||
Top = 8
|
||||
end
|
||||
object IdAntiFreeze: TIdAntiFreeze
|
||||
IdleTimeOut = 150
|
||||
Left = 244
|
||||
Top = 324
|
||||
Left = 424
|
||||
Top = 8
|
||||
end
|
||||
object tmrSpeed: TTimer
|
||||
Enabled = False
|
||||
OnTimer = tmrSpeedTimer
|
||||
Left = 214
|
||||
Top = 324
|
||||
Left = 394
|
||||
Top = 8
|
||||
end
|
||||
object IdLogFile: TIdLogFile
|
||||
LogTime = False
|
||||
Left = 184
|
||||
Top = 324
|
||||
Left = 364
|
||||
Top = 8
|
||||
end
|
||||
end
|
||||
|
@ -63,7 +63,7 @@ type
|
||||
cmdConnect: TFlatButton;
|
||||
pnlDirectory: TPanel;
|
||||
trvDirectories: TTreeView;
|
||||
lblStep4: TLabel;
|
||||
lblStep5: TLabel;
|
||||
jspInstallProgress: TJvStandardPage;
|
||||
pnlHeader5: TPanel;
|
||||
imgIcon4: TImage;
|
||||
@ -101,6 +101,11 @@ type
|
||||
shpMods: TShape;
|
||||
trvMods: TTreeView;
|
||||
FlatRadioButton1: TFlatRadioButton;
|
||||
pnlEngineType: TPanel;
|
||||
optAutoDetect: TFlatRadioButton;
|
||||
optSource: TFlatRadioButton;
|
||||
optOrangeBox: TFlatRadioButton;
|
||||
lblStep4: TLabel;
|
||||
procedure jvwStepsCancelButtonClick(Sender: TObject);
|
||||
procedure cmdCancelClick(Sender: TObject);
|
||||
procedure cmdNextClick(Sender: TObject);
|
||||
@ -136,6 +141,9 @@ var
|
||||
|
||||
var VERSION: String = '<none>';
|
||||
|
||||
const NormalHeight = 382;
|
||||
FTPHeight = 422;
|
||||
|
||||
implementation
|
||||
|
||||
uses UnitFunctions, UnitfrmProxy, UnitInstall, UnitSelectModPath;
|
||||
@ -159,10 +167,11 @@ var ePath: String;
|
||||
CurNode: TTreeNode;
|
||||
eOS: TOS;
|
||||
i: integer;
|
||||
Source: Boolean;
|
||||
begin
|
||||
{ FTP }
|
||||
if jplWizard.ActivePage = jspFTP then begin
|
||||
if not IdFTP.Connected then
|
||||
if (jplWizard.ActivePage = jspFTP) then begin
|
||||
if (not IdFTP.Connected) then
|
||||
IdFTP.Connect;
|
||||
eStr := TStringList.Create;
|
||||
ePath := '/';
|
||||
@ -175,14 +184,22 @@ begin
|
||||
end;
|
||||
IdFTP.ChangeDir(ePath);
|
||||
IdFTP.List(eStr, '', False);
|
||||
if eStr.IndexOf('gameinfo.txt') = -1 then begin
|
||||
eStr.CaseSensitive := False;
|
||||
// check if gameinfo.txt is in the directory -> valid installation
|
||||
if (eStr.IndexOf('gameinfo.txt') = -1) then begin
|
||||
MessageBox(Handle, 'Invalid directory. Please select your mod directory and try again.', PChar(Application.Title), MB_ICONWARNING);
|
||||
eStr.Free;
|
||||
exit;
|
||||
end
|
||||
else
|
||||
eStr.Free;
|
||||
|
||||
// check for orangebox directory (!! OrangeBox Check !!)
|
||||
if (optAutoDetect.Checked) then
|
||||
Source := not ((AnsiSameText(trvDirectories.Selected.Text, 'tf')) or (Pos('orangebox', LowerCase(ePath)) <> 0))
|
||||
else if (optSource.Checked) then
|
||||
Source := True
|
||||
else
|
||||
Source := False;
|
||||
// design stuff
|
||||
trvDirectories.Enabled := False;
|
||||
cmdConnect.Enabled := False;
|
||||
@ -190,45 +207,86 @@ begin
|
||||
optLinux.Enabled := False;
|
||||
Screen.Cursor := crHourGlass;
|
||||
|
||||
if optWindows.Checked then
|
||||
eOS := osWindows
|
||||
if (optWindows.Checked) then begin
|
||||
eOS := osWindows;
|
||||
if (Source) then
|
||||
rtfDetails.Lines.Text := '* Installing Source binaries for Windows' + #13#10 + #13#10
|
||||
else
|
||||
rtfDetails.Lines.Text := '* Installing OrangeBox binaries for Windows' + #13#10 + #13#10
|
||||
end
|
||||
else begin
|
||||
eOS := osLinux;
|
||||
|
||||
if (Source) then
|
||||
rtfDetails.Lines.Text := '* Installing Source binaries for Linux' + #13#10 + #13#10
|
||||
else
|
||||
rtfDetails.Lines.Text := '* Installing OrangeBox binaries for Linux' + #13#10 + #13#10
|
||||
end;
|
||||
jspInstallProgress.Show;
|
||||
// installation
|
||||
Screen.Cursor := crAppStart;
|
||||
InstallFTP(eOS);
|
||||
InstallFTP(eOS, Source, trvDirectories.Selected.Text);
|
||||
end
|
||||
else if jplWizard.ActivePage = jspInstallProgress then
|
||||
else if (jplWizard.ActivePage = jspInstallProgress) then
|
||||
Close
|
||||
else if jplWizard.ActivePage = jspSelectMod then begin
|
||||
else if (jplWizard.ActivePage = jspSelectMod) then begin
|
||||
{ Dedicated Server }
|
||||
if (frbDedicatedServer.Checked) or (frbStandaloneServer.Checked) then begin
|
||||
ePath := trvMods.Selected.Text;
|
||||
if ePath = 'Counter-Strike:Source' then
|
||||
ePath := 'cstrike'
|
||||
else if ePath = 'Day of Defeat:Source' then
|
||||
ePath := 'dod'
|
||||
else
|
||||
ePath := 'hl2mp';
|
||||
ePath := 'SteamApps\' + trvMods.Selected.Parent.Text + '\source dedicated server\' + ePath;
|
||||
// install it
|
||||
if frbDedicatedServer.Checked then begin
|
||||
if DirectoryExists(SteamPath + ePath) then begin
|
||||
Source := True;
|
||||
ePath := trvMods.Selected.Text;
|
||||
if (ePath = 'Counter-Strike:Source') then
|
||||
ePath := trvMods.Selected.Parent.Text + '\source dedicated server\cstrike'
|
||||
else if (ePath = 'Day of Defeat:Source') then
|
||||
ePath := trvMods.Selected.Parent.Text + '\source dedicated server\dod'
|
||||
else if (ePath = 'Half-Life 2 Deathmatch') then
|
||||
ePath := trvMods.Selected.Parent.Text + '\source dedicated server\hl2mp'
|
||||
else begin
|
||||
{ get games }
|
||||
if (ePath = 'Team Fortress 2') then
|
||||
ePath := trvMods.Selected.Parent.Text + '\source 2007 dedicated server\tf';
|
||||
{ ask user, just in case }
|
||||
case MessageBox(Handle, 'It looks like your server is using the OrangeBox engine. Would you like to install the appropriate binaries for it?', PChar(Application.Title), MB_ICONQUESTION + MB_YESNOCANCEL) of
|
||||
mrYes: Source := False;
|
||||
mrNo: Source := True;
|
||||
mrCancel: exit;
|
||||
end;
|
||||
end;
|
||||
SteamPath := IncludeTrailingPathDelimiter(SteamPath) + 'steamapps\';
|
||||
// install it
|
||||
if (DirectoryExists(SteamPath + ePath)) then begin
|
||||
jspInstallProgress.Show;
|
||||
InstallDedicated(IncludeTrailingPathDelimiter(SteamPath + ePath), True);
|
||||
InstallDedicated(IncludeTrailingPathDelimiter(SteamPath + ePath), True, Source);
|
||||
end
|
||||
else begin
|
||||
MessageBox(Handle, 'Error: The directory of the mod you selected doesn''t exist any more. Run Dedicated Server with the chosen mod and try again.', PChar(Application.Title), MB_ICONERROR);
|
||||
jspSelectMod.Show;
|
||||
exit;
|
||||
end;
|
||||
end
|
||||
end;
|
||||
{ Standalone Server }
|
||||
if (frbStandaloneServer.Checked) then begin
|
||||
Source := True;
|
||||
ePath := trvMods.Selected.Text;
|
||||
if ePath = 'Counter-Strike:Source' then
|
||||
ePath := 'cstrike'
|
||||
else if ePath = 'Day of Defeat:Source' then
|
||||
ePath := 'dod'
|
||||
else if ePath = 'Half-Life 2 Deathmatch' then
|
||||
ePath := 'hl2mp'
|
||||
else begin
|
||||
if DirectoryExists(StandaloneServer + ePath) then begin
|
||||
{ get games }
|
||||
if (ePath = 'Team Fortress 2') then
|
||||
ePath := 'orangebox\tf';
|
||||
{ ask user, just in case }
|
||||
case MessageBox(Handle, 'It looks like your server is using the OrangeBox engine. Would you like to install the appropriate binaries for it?', PChar(Application.Title), MB_ICONQUESTION + MB_YESNOCANCEL) of
|
||||
mrYes: Source := False;
|
||||
mrNo: Source := True;
|
||||
mrCancel: exit;
|
||||
end;
|
||||
end;
|
||||
// install it
|
||||
if (DirectoryExists(StandaloneServer + ePath)) then begin
|
||||
jspInstallProgress.Show;
|
||||
InstallDedicated(IncludeTrailingPathDelimiter(StandaloneServer + ePath), False)
|
||||
InstallDedicated(IncludeTrailingPathDelimiter(StandaloneServer + ePath), False, Source)
|
||||
end
|
||||
else begin
|
||||
MessageBox(Handle, 'Error: The directory of the mod you selected doesn''t exist (any more). Run Half-Life Dedicated Server with the chosen mod again and restart.', PChar(Application.Title), MB_ICONERROR);
|
||||
@ -236,35 +294,44 @@ begin
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
{ Listen Server }
|
||||
if frbListenServer.Checked then begin
|
||||
if (frbListenServer.Checked) then begin
|
||||
Source := True;
|
||||
ePath := trvMods.Selected.Text;
|
||||
if ePath = 'Counter-Strike:Source' then
|
||||
if (ePath = 'Counter-Strike:Source') then
|
||||
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\counter-strike source\cstrike'
|
||||
else if ePath = 'Half-Life 2 Deathmatch' then
|
||||
else if (ePath = 'Half-Life 2 Deathmatch') then
|
||||
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\half-life 2 deathmatch\hl2mp'
|
||||
else
|
||||
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\day of defeat source\dod';
|
||||
else if ePath = 'Day of Defeat:Source' then
|
||||
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\day of defeat source\dod'
|
||||
else begin
|
||||
{ get games }
|
||||
if (ePath = 'Team Fortress 2') then
|
||||
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\team fortress 2\tf';
|
||||
{ ask user, just in case }
|
||||
case MessageBox(Handle, 'It looks like your server is using the OrangeBox engine. Would you like to install the appropriate binaries for it?', PChar(Application.Title), MB_ICONQUESTION + MB_YESNOCANCEL) of
|
||||
mrYes: Source := False;
|
||||
mrNo: Source := True;
|
||||
mrCancel: exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
if Pos(SteamPath, ePath) = 0 then
|
||||
if (Pos(SteamPath, ePath) = 0) then
|
||||
MessageBox(Handle, 'An error occured. Please report this bug to the Metamod:Source team and post a new thread on the forums of www.amxmodx.org.', PChar(Application.Title), MB_ICONSTOP)
|
||||
else begin
|
||||
if not FileExists(ePath + '\gameinfo.txt') then begin
|
||||
if (not FileExists(ePath + '\gameinfo.txt')) then begin
|
||||
MessageBox(Handle, 'You have to play this game once before installing Metamod:Source. Do that and try again.', PChar(Application.Title), MB_ICONWARNING);
|
||||
exit;
|
||||
end;
|
||||
|
||||
jspInstallProgress.Show;
|
||||
InstallListen(IncludeTrailingPathDelimiter(ePath));
|
||||
InstallListen(IncludeTrailingPathDelimiter(ePath), Source);
|
||||
end;
|
||||
end;
|
||||
{ Custom mod below }
|
||||
end
|
||||
else if jplWizard.ActivePage <> jspInstallMethod then
|
||||
jplWizard.NextPage
|
||||
else begin
|
||||
if frbDedicatedServer.Checked then begin // Dedicated Server
|
||||
else if (jplWizard.ActivePage = jspInstallMethod) then begin
|
||||
if (frbDedicatedServer.Checked) then begin // Dedicated Server
|
||||
eRegistry := TRegistry.Create(KEY_READ);
|
||||
try
|
||||
eRegistry.RootKey := HKEY_CURRENT_USER;
|
||||
@ -274,19 +341,21 @@ begin
|
||||
SteamPath := ePath;
|
||||
|
||||
ePath := ePath + 'SteamApps\';
|
||||
if DirectoryExists(ePath) then begin
|
||||
if (DirectoryExists(ePath)) then begin
|
||||
trvMods.Items.Clear;
|
||||
// Check Mods
|
||||
eStr := GetAllFiles(ePath + '*.*', faDirectory, False, True, False);
|
||||
for i := 0 to eStr.Count -1 do begin
|
||||
CurNode := trvMods.Items.Add(nil, eStr[i]);
|
||||
|
||||
if DirectoryExists(ePath + eStr[i] + '\source dedicated server\cstrike') then
|
||||
if (DirectoryExists(ePath + eStr[i] + '\source dedicated server\cstrike')) then
|
||||
trvMods.Items.AddChild(CurNode, 'Counter-Strike:Source');
|
||||
if DirectoryExists(ePath + eStr[i] + '\source dedicated server\dod') then
|
||||
if (DirectoryExists(ePath + eStr[i] + '\source dedicated server\dod')) then
|
||||
trvMods.Items.AddChild(CurNode, 'Day of Defeat:Source');
|
||||
if DirectoryExists(ePath + eStr[i] + '\source dedicated server\hl2mp') then
|
||||
if (DirectoryExists(ePath + eStr[i] + '\source dedicated server\hl2mp')) then
|
||||
trvMods.Items.AddChild(CurNode, 'Half-Life 2 Deatmatch');
|
||||
if (DirectoryExists(ePath + eStr[i] + '\source 2007 dedicated server\tf')) then
|
||||
trvMods.Items.AddChild(CurNode, 'Team Fortress 2');
|
||||
|
||||
if CurNode.Count = 0 then
|
||||
CurNode.Free
|
||||
@ -307,11 +376,11 @@ begin
|
||||
eRegistry.Free;
|
||||
end;
|
||||
end
|
||||
else if frbListenServer.Checked then begin // Listen Server
|
||||
else if (frbListenServer.Checked) then begin // Listen Server
|
||||
eRegistry := TRegistry.Create(KEY_READ);
|
||||
try
|
||||
eRegistry.RootKey := HKEY_CURRENT_USER;
|
||||
if eRegistry.OpenKey('Software\Valve\Steam', False) then begin
|
||||
if (eRegistry.OpenKey('Software\Valve\Steam', False)) then begin
|
||||
ePath := eRegistry.ReadString('SteamPath');
|
||||
ePath := IncludeTrailingPathDelimiter(StringReplace(ePath, '/', '\', [rfReplaceAll]));
|
||||
SteamPath := ePath;
|
||||
@ -330,6 +399,8 @@ begin
|
||||
trvMods.Items.AddChild(CurNode, 'Day of Defeat:Source');
|
||||
if DirectoryExists(ePath + eStr[i] + '\half-life 2 deathmatch') then
|
||||
trvMods.Items.AddChild(CurNode, 'Half-Life 2 Deatmatch');
|
||||
if DirectoryExists(ePath + eStr[i] + '\team fortress 2') then
|
||||
trvMods.Items.AddChild(CurNode, 'Team Fortress 2');
|
||||
|
||||
if CurNode.Count = 0 then
|
||||
CurNode.Free
|
||||
@ -350,7 +421,7 @@ begin
|
||||
eRegistry.Free;
|
||||
end;
|
||||
end
|
||||
else if frbStandaloneServer.Checked then begin // Standalone Server
|
||||
else if (frbStandaloneServer.Checked) then begin // Standalone Server
|
||||
eRegistry := TRegistry.Create;
|
||||
try
|
||||
eRegistry.RootKey := HKEY_CURRENT_USER;
|
||||
@ -362,6 +433,8 @@ begin
|
||||
trvMods.Items.Add(nil, 'Day of Defeat:Source');
|
||||
if DirectoryExists(StandaloneServer + 'hl2mp') then
|
||||
trvMods.Items.Add(nil, 'Half-Life 2 Deatmatch');
|
||||
if DirectoryExists(StandaloneServer + 'orangebox\tf') then
|
||||
trvMods.Items.Add(nil, 'Team Fortress 2');
|
||||
jspSelectMod.Show;
|
||||
cmdNext.Enabled := False;
|
||||
end
|
||||
@ -371,16 +444,22 @@ begin
|
||||
eRegistry.Free;
|
||||
end;
|
||||
end
|
||||
else if frbSelectMod.Checked then begin
|
||||
else if (frbSelectMod.Checked) then begin
|
||||
{ Custom mod }
|
||||
if frmSelectModPath.ShowModal = mrOk then begin
|
||||
ePath := frmSelectModPath.trvDirectory.SelectedFolder.PathName;
|
||||
{ install now }
|
||||
jspInstallProgress.Show;
|
||||
InstallCustom(IncludeTrailingPathDelimiter(frmSelectModPath.trvDirectory.SelectedFolder.PathName), osWindows);
|
||||
InstallCustom(IncludeTrailingPathDelimiter(ePath), osWindows, not frmSelectModPath.chkUsesOrangebox.Checked);
|
||||
end;
|
||||
end
|
||||
else if frbFTP.Checked then // FTP
|
||||
else if (frbFTP.Checked) then begin // FTP
|
||||
Height := FTPHeight;
|
||||
jspFTP.Show;
|
||||
end;
|
||||
end
|
||||
else
|
||||
jplWizard.NextPage
|
||||
end;
|
||||
|
||||
procedure TfrmMain.CheckNext(Sender: TObject);
|
||||
@ -390,8 +469,10 @@ end;
|
||||
|
||||
procedure TfrmMain.cmdBackClick(Sender: TObject);
|
||||
begin
|
||||
if jplWizard.ActivePage = jspFTP then
|
||||
jspInstallMethod.Show
|
||||
if jplWizard.ActivePage = jspFTP then begin
|
||||
Height := NormalHeight;
|
||||
jspInstallMethod.Show;
|
||||
end
|
||||
else begin
|
||||
jplWizard.PrevPage;
|
||||
cmdBack.Visible := jplWizard.ActivePageIndex <> 0;
|
||||
@ -399,9 +480,9 @@ begin
|
||||
end;
|
||||
|
||||
procedure TfrmMain.cmdConnectClick(Sender: TObject);
|
||||
var i: integer;
|
||||
var i, k: integer;
|
||||
eStr: TStringList;
|
||||
CurNode: TTreeNode;
|
||||
CurNode, CurNode2: TTreeNode;
|
||||
Path: String;
|
||||
begin
|
||||
if (Trim(txtHost.Text) = '') or (Trim(txtUsername.Text) = '') then
|
||||
@ -432,7 +513,7 @@ begin
|
||||
eStr := TStringList.Create;
|
||||
eStr.Text := StringReplace(Path, '/', #13, [rfReplaceAll]);
|
||||
for i := eStr.Count -1 downto 0 do begin
|
||||
if eStr[i] = '' then
|
||||
if (eStr[i] = '') then
|
||||
eStr.Delete(i);
|
||||
end;
|
||||
if (Copy(Path, Length(Path) -1, 1) <> '/') then
|
||||
@ -441,47 +522,39 @@ begin
|
||||
trvDirectories.Enabled := True;
|
||||
cmdConnect.Enabled := True;
|
||||
cmdConnect.Caption := 'Disconnect';
|
||||
// ... change to / and create all the directories ...
|
||||
CurNode := nil;
|
||||
if (Path <> '/') then begin
|
||||
try
|
||||
IdFTP.ChangeDir('/');
|
||||
with GetAllDirs do begin
|
||||
for i := 0 to Count -1 do begin
|
||||
if (Assigned(CurNode)) then
|
||||
trvDirectories.Items.AddChild(trvDirectories.Items.Add(nil, Strings[i]), 'Scanning...')
|
||||
else begin
|
||||
CurNode := trvDirectories.Items.Add(nil, Strings[i]);
|
||||
trvDirectories.Items.AddChild(CurNode, 'Scanning...');
|
||||
if (Pos('/' + CurNode.Text + '/', Path) = 0) then
|
||||
CurNode := nil;
|
||||
end
|
||||
end;
|
||||
Free;
|
||||
end;
|
||||
IdFTP.ChangeDir(Path);
|
||||
except
|
||||
if (IdFTP.Connected) then
|
||||
IdFTP.ChangeDir(Path)
|
||||
else
|
||||
IdFTP.Connect;
|
||||
end;
|
||||
end;
|
||||
// ... find directories in start path ...
|
||||
if eStr.Count <> 0 then begin
|
||||
for i := 0 to eStr.Count -1 do begin
|
||||
if (not ((i = 0) and (Assigned(CurNode)))) then
|
||||
CurNode := trvDirectories.Items.AddChild(CurNode, eStr[i]);
|
||||
end;
|
||||
end;
|
||||
trvDirectories.Selected := CurNode;
|
||||
eStr.Free;
|
||||
// ... scan for directories ...
|
||||
CurNode := nil;
|
||||
CurNode2 := nil;
|
||||
if (eStr.Count <> 0) then begin
|
||||
IdFTP.ChangeDir('/');
|
||||
for i := 0 to eStr.Count do begin
|
||||
try
|
||||
with GetAllDirs do begin
|
||||
for i := 0 to Count -1 do
|
||||
trvDirectories.Items.AddChild(trvDirectories.Items.AddChild(CurNode, Strings[i]), 'Scanning...');
|
||||
Free;
|
||||
for k := 0 to Count -1 do begin
|
||||
if (i = eStr.Count) or (Strings[k] <> eStr[i]) then
|
||||
trvDirectories.Items.AddChild(trvDirectories.Items.AddChild(CurNode, Strings[k]), 'Scanning...')
|
||||
else
|
||||
CurNode2 := trvDirectories.Items.AddChild(CurNode, Strings[k]);
|
||||
end;
|
||||
Free;
|
||||
|
||||
CurNode := CurNode2;
|
||||
trvDirectories.Selected := CurNode;
|
||||
Repaint;
|
||||
Application.ProcessMessages;
|
||||
end;
|
||||
|
||||
if (i <> eStr.Count) then
|
||||
IdFTP.ChangeDir(eStr[i]);
|
||||
except
|
||||
IdFTP.CheckForDisconnect(False);
|
||||
if (not IdFTP.Connected) then
|
||||
IdFTP.Disconnect;
|
||||
CurNode := trvDirectories.Items.AddChild(CurNode, eStr.Strings[i])
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
eStr.Free;
|
||||
|
||||
if Assigned(CurNode) then
|
||||
CurNode.Expand(False);
|
||||
|
@ -1,7 +1,8 @@
|
||||
In this folder should be server.dll and server_i486.so.
|
||||
Every MM:S library should be located in this directory.
|
||||
|
||||
How you prepare a release:
|
||||
1) Copy the latest MM:S dlls and hl2launch.exe into this folder
|
||||
2) Run Attach.exe
|
||||
3) Test MMS_Installer.exe once (should work but nobody wants bug releases, especially not in the installer)
|
||||
4) If everything worked fine, release it, otherwise pm me (Basic-Master)
|
||||
How to prepare a release:
|
||||
1) Copy the latest MM:S dlls into this folder
|
||||
2) Append .source to the Source binaries and .orangebox to the OrangeBox binaries
|
||||
3) Run Attach.exe
|
||||
4) Test MMS_Installer.exe once (recommended)
|
||||
5) Release it or e-Mail me if you find a bug
|
@ -1,7 +1,7 @@
|
||||
[PRODUCT]
|
||||
major = 1
|
||||
minor = 4
|
||||
revision = 0
|
||||
revision = 4
|
||||
|
||||
[sourcemm]
|
||||
folder = sourcemm
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceHook ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceHook ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceHook ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceHook ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceHook ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceHook ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -153,6 +153,30 @@ public:
|
||||
return npos;
|
||||
}
|
||||
|
||||
int find_last_of(const char c, int index = npos) const
|
||||
{
|
||||
int len = static_cast<int>(size());
|
||||
if (len < 1)
|
||||
return npos;
|
||||
if (index >= len || index < npos)
|
||||
return npos;
|
||||
int i;
|
||||
if (index == npos)
|
||||
i = len - 1;
|
||||
else
|
||||
i = index;
|
||||
|
||||
for (; i>=0; i--)
|
||||
{
|
||||
if (v[i] == c)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return npos;
|
||||
}
|
||||
|
||||
bool is_space(int c) const
|
||||
{
|
||||
if (c == '\f' || c == '\n' ||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -19,39 +19,58 @@ namespace SourceHook
|
||||
// Vector
|
||||
template <class T> class CVector
|
||||
{
|
||||
bool Grow()
|
||||
bool Grow(size_t amount)
|
||||
{
|
||||
// automatic grow
|
||||
size_t newSize = m_Size * 2;
|
||||
|
||||
if (newSize == 0)
|
||||
newSize = 8; // a good init value
|
||||
{
|
||||
newSize = 8;
|
||||
}
|
||||
|
||||
while (m_CurrentUsedSize + amount > newSize)
|
||||
{
|
||||
newSize *= 2;
|
||||
}
|
||||
|
||||
T *newData = new T[newSize];
|
||||
if (!newData)
|
||||
return false;
|
||||
|
||||
if (m_Data)
|
||||
{
|
||||
for (size_t i=0; i<m_CurrentUsedSize; i++)
|
||||
{
|
||||
newData[i] = m_Data[i];
|
||||
}
|
||||
|
||||
delete [] m_Data;
|
||||
}
|
||||
|
||||
m_Data = newData;
|
||||
m_Size = newSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrowIfNeeded()
|
||||
bool GrowIfNeeded(size_t amount)
|
||||
{
|
||||
if (m_CurrentUsedSize >= m_Size)
|
||||
return Grow();
|
||||
if (m_CurrentUsedSize + amount >= m_Size)
|
||||
{
|
||||
return Grow(amount);
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ChangeSize(size_t size)
|
||||
{
|
||||
// change size
|
||||
if (size == m_Size)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!size)
|
||||
{
|
||||
@ -65,19 +84,24 @@ template <class T> class CVector
|
||||
}
|
||||
|
||||
T *newData = new T[size];
|
||||
if (!newData)
|
||||
return false;
|
||||
|
||||
if (m_Data)
|
||||
{
|
||||
size_t end = (m_CurrentUsedSize < size) ? (m_CurrentUsedSize) : size;
|
||||
for (size_t i=0; i<end; i++)
|
||||
{
|
||||
newData[i] = m_Data[i];
|
||||
}
|
||||
|
||||
delete [] m_Data;
|
||||
}
|
||||
m_Data = newData;
|
||||
m_Size = size;
|
||||
|
||||
if (m_CurrentUsedSize > m_Size)
|
||||
{
|
||||
m_CurrentUsedSize = m_Size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -85,7 +109,9 @@ template <class T> class CVector
|
||||
void FreeMemIfPossible()
|
||||
{
|
||||
if (!m_Data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_CurrentUsedSize)
|
||||
{
|
||||
@ -95,11 +121,15 @@ template <class T> class CVector
|
||||
|
||||
size_t newSize = m_Size;
|
||||
while (m_CurrentUsedSize <= newSize / 2)
|
||||
{
|
||||
newSize /= 2;
|
||||
}
|
||||
|
||||
if (newSize != m_Size)
|
||||
{
|
||||
ChangeSize(newSize);
|
||||
}
|
||||
}
|
||||
protected:
|
||||
T *m_Data;
|
||||
size_t m_Size;
|
||||
@ -321,14 +351,13 @@ public:
|
||||
|
||||
bool push_back(const T & elem)
|
||||
{
|
||||
++m_CurrentUsedSize;
|
||||
if (!GrowIfNeeded())
|
||||
if (!GrowIfNeeded(1))
|
||||
{
|
||||
--m_CurrentUsedSize;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Data[m_CurrentUsedSize - 1] = elem;
|
||||
m_Data[m_CurrentUsedSize++] = elem;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -433,13 +462,13 @@ public:
|
||||
|
||||
size_t ofs = where - begin();
|
||||
|
||||
++m_CurrentUsedSize;
|
||||
if (!GrowIfNeeded())
|
||||
if (!GrowIfNeeded(1))
|
||||
{
|
||||
--m_CurrentUsedSize;
|
||||
return false;
|
||||
}
|
||||
|
||||
++m_CurrentUsedSize;
|
||||
|
||||
where = begin() + ofs;
|
||||
|
||||
// Move subsequent entries
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceHook ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -752,11 +752,6 @@ namespace SourceHook
|
||||
|
||||
bool CSourceHookImpl::ShouldContinue()
|
||||
{
|
||||
// If recall is true, we shall not continue either.
|
||||
// This is because, if it's true and ShouldContinue is called, it suggests that the
|
||||
// actual recall is done and that we are back in the original handler which shall return
|
||||
// immediately.
|
||||
|
||||
// Post-recalls:
|
||||
// The second element on the stack has recall set to Recall_Post1.
|
||||
// This means that we want to skip this part and the original function calling thing, so
|
||||
@ -778,7 +773,21 @@ namespace SourceHook
|
||||
return m_HLIStack.front().shouldContinue;
|
||||
}
|
||||
}
|
||||
return m_HLIStack.front().shouldContinue && !m_HLIStack.front().recall;
|
||||
|
||||
// 16.01.2008: We used to return false for recalls here.
|
||||
// This caused the hook funcs to think that the whole iface has been destroyed
|
||||
// (the original purpose of shouldcontinue was to notify the hookfuncs that everything has been
|
||||
// invalidated by RemoveHook) so they did not release their iterator. -> Leaks
|
||||
// Now, GetIter sets the iterator to END so it still gets released but the hooks don't continue.
|
||||
|
||||
// But: we have to return false in the post phase of pre recalls (ie. a pre hook made a recall).
|
||||
if (m_HLIStack.front().recall == HookLoopInfo::Recall_Pre &&
|
||||
static_cast<CIface*>(m_HLIStack.front().pCurIface)->m_PreHooks.RelFlagGet())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_HLIStack.front().shouldContinue;
|
||||
}
|
||||
|
||||
void CSourceHookImpl::DoRecall()
|
||||
@ -994,6 +1003,9 @@ namespace SourceHook
|
||||
ret->Set(m_UsedIters); // m_UsedIters is the last returned and not released iterator
|
||||
ret->Next(); // Use next instead of directly incrementing its m_Iter:
|
||||
// skips paused plugins
|
||||
|
||||
// Set the last iterator to END!
|
||||
m_UsedIters->GoToEnd();
|
||||
}
|
||||
|
||||
ret->m_pNext = m_UsedIters;
|
||||
@ -1008,6 +1020,8 @@ namespace SourceHook
|
||||
}
|
||||
void CSourceHookImpl::CHookList::ReleaseIter(IIter *pIter)
|
||||
{
|
||||
m_RelFlag = true;
|
||||
|
||||
CIter *pIter2 = static_cast<CIter*>(pIter);
|
||||
|
||||
// Unlink from m_UsedIters
|
||||
@ -1017,7 +1031,7 @@ namespace SourceHook
|
||||
if (pIter2->m_pPrev)
|
||||
pIter2->m_pPrev->m_pNext = pIter2->m_pNext;
|
||||
if (pIter2 == m_UsedIters)
|
||||
m_UsedIters = NULL;
|
||||
m_UsedIters = m_UsedIters->m_pNext;
|
||||
|
||||
// Link to m_FreeIters
|
||||
|
||||
@ -1048,6 +1062,11 @@ namespace SourceHook
|
||||
SkipPaused();
|
||||
}
|
||||
|
||||
void CSourceHookImpl::CHookList::CIter::GoToEnd()
|
||||
{
|
||||
m_Iter = m_pList->m_List.end();
|
||||
}
|
||||
|
||||
bool CSourceHookImpl::CHookList::CIter::End()
|
||||
{
|
||||
if (!m_pList)
|
||||
@ -1056,7 +1075,7 @@ namespace SourceHook
|
||||
}
|
||||
void CSourceHookImpl::CHookList::CIter::Next()
|
||||
{
|
||||
if (!m_pList)
|
||||
if (!m_pList || m_Iter == m_pList->m_List.end())
|
||||
return;
|
||||
++m_Iter;
|
||||
SkipPaused();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceHook ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceHook ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -257,6 +257,7 @@ namespace SourceHook
|
||||
virtual ~CIter();
|
||||
|
||||
void GoToBegin();
|
||||
void GoToEnd();
|
||||
void Set(CIter *pOther);
|
||||
|
||||
bool End();
|
||||
@ -276,6 +277,7 @@ namespace SourceHook
|
||||
// For recalls
|
||||
bool m_Recall;
|
||||
bool m_RQFlag;
|
||||
bool m_RelFlag;
|
||||
|
||||
void SetRecallState(); // Sets the list into a state where the next returned
|
||||
// iterator (from GetIter) will be a copy of the last
|
||||
@ -283,8 +285,9 @@ namespace SourceHook
|
||||
// The hook resets this state automatically on:
|
||||
// GetIter, ReleaseIter
|
||||
|
||||
void RQFlagReset() { m_RQFlag = false; }
|
||||
void RQFlagReset() { m_RQFlag = false; m_RelFlag = false; }
|
||||
bool RQFlagGet() { return m_RQFlag; }
|
||||
bool RelFlagGet() { return m_RelFlag; }
|
||||
CHookList();
|
||||
CHookList(const CHookList &other);
|
||||
virtual ~CHookList();
|
||||
|
@ -1,4 +1,4 @@
|
||||
#(C)2004-2007 SourceMM Development Team
|
||||
#(C)2004-2008 SourceMM Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson and Pavol Marko
|
||||
|
||||
OPT_FLAGS = -O3 -funroll-loops -s -pipe
|
||||
|
@ -289,6 +289,9 @@
|
||||
<File
|
||||
RelativePath="..\testref.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\testrefret.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
|
@ -109,6 +109,10 @@ bool TestBail(std::string &error)
|
||||
new State_EatYams_Return(6),
|
||||
NULL), "Part 6");
|
||||
|
||||
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
|
||||
|
||||
UntestBail2();
|
||||
|
||||
delete g_Gabgab;
|
||||
|
||||
return true;
|
||||
|
@ -28,6 +28,7 @@ namespace N_TestBail
|
||||
extern IGaben *g_Gabgab;
|
||||
|
||||
bool TestBail2(std::string &error);
|
||||
void UntestBail2();
|
||||
}
|
||||
|
||||
using namespace N_TestBail;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "sourcehook_test.h"
|
||||
#include "testbail.h"
|
||||
|
||||
static unsigned int n_calls = 0;
|
||||
|
||||
int EatYams_Handler2(int a)
|
||||
{
|
||||
@ -31,6 +32,18 @@ namespace N_TestBail
|
||||
|
||||
CHECK_COND(ret == 6, "Part 2.1");
|
||||
|
||||
n_calls++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UntestBail2()
|
||||
{
|
||||
while (n_calls)
|
||||
{
|
||||
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler3, false);
|
||||
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler2, false);
|
||||
n_calls--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceHook ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -94,9 +94,9 @@ bool TestMulti(std::string &error)
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i=1; i<10; i++)
|
||||
for (unsigned int i=0; i<10; i++)
|
||||
{
|
||||
SH_REMOVE_HOOK_STATICFUNC(VMultiTest, HookTarget, pv[1], HookFunction, false);
|
||||
SH_REMOVE_HOOK_STATICFUNC(VMultiTest, HookTarget, pv[i], HookFunction, false);
|
||||
delete pv[i];
|
||||
}
|
||||
|
||||
@ -104,3 +104,4 @@ bool TestMulti(std::string &error)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -222,5 +222,11 @@ bool TestRecall(std::string &error)
|
||||
|
||||
CHECK_COND(a == 0xDEADFC, "Part 5.1");
|
||||
|
||||
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost_Func2, true);
|
||||
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, Handler2_Func2, false);
|
||||
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, Handler1_Func22, false);
|
||||
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost1_Func22, true);
|
||||
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost2_Func22, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -159,5 +159,7 @@ bool TestRef(std::string &error)
|
||||
new State_Result(12),
|
||||
NULL), "Part 4");
|
||||
|
||||
SH_REMOVE_HOOK_MEMFUNC(CHello, Func, &hello, &hook, &CHook::Func, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -196,5 +196,13 @@ bool TestRefRet(std::string &error)
|
||||
new State_Func2_Ret(&hook.m_Var), // really returned hook.m_Var
|
||||
NULL), "Part 7");
|
||||
|
||||
SH_REMOVE_HOOK_MEMFUNC(Test, Func2, &test, &hook, &CHook::Func2_Post1, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(Test, Func2, &test, &hook, &CHook::Func2_Pre1, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Pre1, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Post1, true);
|
||||
SH_REMOVE_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Pre2, false);
|
||||
SH_REMOVE_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Post2, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -12,6 +12,7 @@
|
||||
#include "CSmmAPI.h"
|
||||
#include "sourcemm.h"
|
||||
#include "concommands.h"
|
||||
#include "vsp_listener.h"
|
||||
|
||||
/**
|
||||
* @brief Implements functions from CPlugin.h
|
||||
@ -22,14 +23,14 @@ using namespace SourceMM;
|
||||
|
||||
#define ITER_PLEVENT(evn, plid) \
|
||||
CPluginManager::CPlugin *_Xpl; \
|
||||
SourceHook::List<IMetamodListener *>::iterator event; \
|
||||
SourceHook::List<CPluginEventHandler>::iterator event; \
|
||||
IMetamodListener *api; \
|
||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
||||
_Xpl = (*iter); \
|
||||
if (_Xpl->m_Id == plid) \
|
||||
continue; \
|
||||
for (event=_Xpl->m_Events.begin(); event!=_Xpl->m_Events.end(); event++) { \
|
||||
api = (*event); \
|
||||
api = (*event).event; \
|
||||
api->evn(plid); \
|
||||
} \
|
||||
}
|
||||
@ -182,6 +183,38 @@ void CPluginManager::SetAllLoaded()
|
||||
}
|
||||
}
|
||||
|
||||
void CPluginManager::SetVSPAsLoaded()
|
||||
{
|
||||
PluginIter i;
|
||||
CPlugin *pPlugin;
|
||||
SourceHook::List<CPluginEventHandler>::iterator event;
|
||||
|
||||
for (i = m_Plugins.begin(); i != m_Plugins.end(); i++)
|
||||
{
|
||||
pPlugin = (*i);
|
||||
if (pPlugin->m_Status < Pl_Paused)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* Only valid for plugins >= 10 (v1:5, SourceMM 1.4) */
|
||||
if (pPlugin->m_API->GetApiVersion() < 10)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (event = pPlugin->m_Events.begin();
|
||||
event != pPlugin->m_Events.end();
|
||||
event++)
|
||||
{
|
||||
if ((*event).got_vsp)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
(*event).got_vsp = true;
|
||||
(*event).event->OnVSPListening(&g_VspListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CPluginManager::Pause(PluginId id, char *error, size_t maxlen)
|
||||
{
|
||||
CPlugin *pl = FindById(id);
|
||||
@ -335,7 +368,7 @@ CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source
|
||||
if (!pl->m_Lib)
|
||||
{
|
||||
if (error)
|
||||
UTIL_Format(error, maxlen, "%s", dlerror());
|
||||
UTIL_Format(error, maxlen, "[%d]", GetLastError());
|
||||
pl->m_Status = Pl_Error;
|
||||
} else {
|
||||
CreateInterfaceFn pfn = (CreateInterfaceFn)(dlsym(pl->m_Lib, PL_EXPOSURE_C));
|
||||
@ -373,6 +406,22 @@ CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source
|
||||
//if (pl->m_API->GetApiVersion() >= 4)
|
||||
pl->m_API->AllPluginsLoaded();
|
||||
}
|
||||
if (g_VspListener.IsRootLoadMethod()
|
||||
|| (g_VspListener.IsLoaded() && g_SmmAPI.VSPEnabled()))
|
||||
{
|
||||
SourceHook::List<CPluginEventHandler>::iterator event;
|
||||
for (event = pl->m_Events.begin();
|
||||
event != pl->m_Events.end();
|
||||
event++)
|
||||
{
|
||||
if (pl->m_API->GetApiVersion() < 10 || (*event).got_vsp)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
(*event).got_vsp = true;
|
||||
(*event).event->OnVSPListening(&g_VspListener);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pl->m_Status = Pl_Refused;
|
||||
}
|
||||
@ -496,22 +545,16 @@ bool CPluginManager::UnloadAll()
|
||||
{
|
||||
PluginIter i;
|
||||
|
||||
SourceHook::List<SourceMM::CPluginManager::CPlugin *> remqueue;
|
||||
|
||||
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
|
||||
remqueue.push_back( (*i) );
|
||||
|
||||
char error[128];
|
||||
bool status = true;
|
||||
|
||||
for (i=remqueue.begin(); i!=remqueue.end(); i++)
|
||||
while ((i = m_Plugins.begin()) != m_Plugins.end())
|
||||
{
|
||||
if ( !_Unload( (*i), true, error, sizeof(error)) )
|
||||
{
|
||||
status = false;
|
||||
}
|
||||
|
||||
m_Plugins.clear();
|
||||
remqueue.clear();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -622,3 +665,34 @@ void CPluginManager::UnregAllConCmds(CPlugin *pl)
|
||||
|
||||
pl->m_Cmds.clear();
|
||||
}
|
||||
|
||||
const char *CPluginManager::GetStatusText(CPlugin *pl)
|
||||
{
|
||||
switch (pl->m_Status)
|
||||
{
|
||||
case Pl_NotFound:
|
||||
return "NOFILE";
|
||||
case Pl_Error:
|
||||
return "ERROR";
|
||||
case Pl_Refused:
|
||||
return "FAILED";
|
||||
case Pl_Paused:
|
||||
return "PAUSED";
|
||||
case Pl_Running:
|
||||
{
|
||||
if (pl->m_API && pl->m_API->QueryRunning(NULL, 0))
|
||||
{
|
||||
return "STOPPED";
|
||||
} else {
|
||||
return "RUNNING";
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "-";
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CPluginManager::GetPluginCount()
|
||||
{
|
||||
return (unsigned int)m_Plugins.size();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -50,6 +50,13 @@ namespace SourceMM
|
||||
SourceHook::String alias;
|
||||
SourceHook::String value;
|
||||
};
|
||||
|
||||
struct CPluginEventHandler
|
||||
{
|
||||
bool got_vsp;
|
||||
IMetamodListener *event;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implements Plugin Manager API
|
||||
*/
|
||||
@ -72,7 +79,7 @@ namespace SourceMM
|
||||
HINSTANCE m_Lib;
|
||||
SourceHook::List<ConCommandBase *> m_Cvars;
|
||||
SourceHook::List<ConCommandBase *> m_Cmds;
|
||||
SourceHook::List<IMetamodListener *> m_Events;
|
||||
SourceHook::List<CPluginEventHandler> m_Events;
|
||||
};
|
||||
public:
|
||||
CPluginManager();
|
||||
@ -123,6 +130,10 @@ namespace SourceMM
|
||||
//Internal iterators
|
||||
SourceHook::List<SourceMM::CPluginManager::CPlugin *>::iterator _begin();
|
||||
SourceHook::List<SourceMM::CPluginManager::CPlugin *>::iterator _end();
|
||||
|
||||
void SetVSPAsLoaded();
|
||||
unsigned int GetPluginCount();
|
||||
const char *GetStatusText(CPlugin *pl);
|
||||
private:
|
||||
//These are identical internal functions for the wrappers above.
|
||||
CPlugin *_Load(const char *file, PluginId source, char *error, size_t maxlen);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -141,8 +141,12 @@ void CSmmAPI::ConPrintf(const char *fmt, ...)
|
||||
void CSmmAPI::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener)
|
||||
{
|
||||
CPluginManager::CPlugin *pl = g_PluginMngr.FindByAPI(plugin);
|
||||
CPluginEventHandler cpeh;
|
||||
|
||||
pl->m_Events.push_back(pListener);
|
||||
cpeh.event = pListener;
|
||||
cpeh.got_vsp = false;
|
||||
|
||||
pl->m_Events.push_back(cpeh);
|
||||
}
|
||||
|
||||
void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
|
||||
@ -174,7 +178,7 @@ void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
|
||||
}
|
||||
|
||||
CPluginManager::CPlugin *pl;
|
||||
SourceHook::List<IMetamodListener *>::iterator event;
|
||||
SourceHook::List<CPluginEventHandler>::iterator event;
|
||||
IMetamodListener *api;
|
||||
int ret = 0;
|
||||
void *val = NULL;
|
||||
@ -184,7 +188,7 @@ void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
|
||||
pl = (*iter);
|
||||
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++)
|
||||
{
|
||||
api = (*event);
|
||||
api = (*event).event;
|
||||
ret = IFACE_FAILED;
|
||||
if ( (val=api->OnMetamodQuery(iface, &ret)) != NULL )
|
||||
{
|
||||
@ -221,22 +225,6 @@ void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
|
||||
#define ENGINEW32_OFFS 38
|
||||
#define IA32_CALL 0xE8
|
||||
|
||||
bool vcmp(const void *_addr1, const void *_addr2, size_t len)
|
||||
{
|
||||
unsigned char *addr1 = (unsigned char *)_addr1;
|
||||
unsigned char *addr2 = (unsigned char *)_addr2;
|
||||
|
||||
for (size_t i=0; i<len; i++)
|
||||
{
|
||||
if (addr2[i] == '*')
|
||||
continue;
|
||||
if (addr1[i] != addr2[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//Thanks to fysh for the idea of extracting info from "echo" and for
|
||||
// having the original offsets at hand!
|
||||
bool CSmmAPI::CacheCmds()
|
||||
@ -256,20 +244,20 @@ bool CSmmAPI::CacheCmds()
|
||||
callback = ((ConCommand *)pBase)->GetCallback();
|
||||
ptr = (unsigned char *)callback;
|
||||
#ifdef OS_LINUX
|
||||
if (vcmp(ptr, ENGINE486_SIG, SIGLEN))
|
||||
if (UTIL_VerifySignature(ptr, ENGINE486_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINE486_OFFS;
|
||||
}
|
||||
else if (vcmp(ptr, ENGINE686_SIG, SIGLEN))
|
||||
else if (UTIL_VerifySignature(ptr, ENGINE686_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINE686_OFFS;
|
||||
}
|
||||
else if (vcmp(ptr, ENGINEAMD_SIG, SIGLEN))
|
||||
else if (UTIL_VerifySignature(ptr, ENGINEAMD_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINEAMD_OFFS;
|
||||
}
|
||||
#elif defined OS_WIN32 // Only one Windows engine binary so far...
|
||||
if (vcmp(ptr, ENGINEW32_SIG, SIGLEN))
|
||||
if (UTIL_VerifySignature(ptr, ENGINEW32_SIG, SIGLEN))
|
||||
{
|
||||
offs = ENGINEW32_OFFS;
|
||||
}
|
||||
@ -454,16 +442,40 @@ void CSmmAPI::ClientConPrintf(edict_t *client, const char *fmt, ...)
|
||||
|
||||
void CSmmAPI::LoadAsVSP()
|
||||
{
|
||||
char command[350];
|
||||
size_t len;
|
||||
char engine_file[PATH_SIZE];
|
||||
char rel_path[PATH_SIZE * 2];
|
||||
|
||||
GetFileOfAddress(g_Engine.engine, engine_file, sizeof(engine_file));
|
||||
|
||||
/* Chop off the "engine" file part */
|
||||
len = strlen(engine_file);
|
||||
for (size_t i = len - 1; i >= 0 && i < len; i--)
|
||||
{
|
||||
if (engine_file[i] == '/'
|
||||
|| engine_file[i] == '\\')
|
||||
{
|
||||
engine_file[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *usepath = g_SmmPath.c_str();
|
||||
if (UTIL_Relatize(rel_path, sizeof(rel_path), engine_file, g_SmmPath.c_str()))
|
||||
{
|
||||
usepath = rel_path;
|
||||
}
|
||||
|
||||
char command[PATH_SIZE * 2];
|
||||
g_VspListener.SetLoadable(true);
|
||||
UTIL_Format(command, sizeof(command), "plugin_load \"%s\"\n", g_SmmPath.c_str());
|
||||
UTIL_Format(command, sizeof(command), "plugin_load \"%s\"\n", usepath);
|
||||
g_Engine.engine->ServerCommand(command);
|
||||
}
|
||||
|
||||
void CSmmAPI::EnableVSPListener()
|
||||
{
|
||||
/* If GameInit already passed and we're not already enabled or loaded, go ahead and LoadAsVSP load */
|
||||
if (bGameInit && !m_VSP && !g_VspListener.IsLoaded())
|
||||
if (bGameInit && !m_VSP && !g_VspListener.IsLoaded() && !g_VspListener.IsRootLoadMethod())
|
||||
{
|
||||
LoadAsVSP();
|
||||
}
|
||||
@ -492,6 +504,11 @@ int CSmmAPI::GetGameDLLVersion()
|
||||
#define MSGCLASS2_SIGLEN 16
|
||||
#define MSGCLASS2_SIG "\x56\x8B\x74\x24\x2A\x85\xF6\x7C\x2A\x3B\x35\x2A\x2A\x2A\x2A\x7D"
|
||||
#define MSGCLASS2_OFFS 11
|
||||
|
||||
/* Windows frame pointer sig */
|
||||
#define MSGCLASS3_SIGLEN 18
|
||||
#define MSGCLASS3_SIG "\x55\x8B\xEC\x51\x89\x2A\x2A\x8B\x2A\x2A\x50\x8B\x0D\x2A\x2A\x2A\x2A\xE8"
|
||||
#define MSGCLASS3_OFFS 13
|
||||
#elif defined OS_LINUX
|
||||
/* No frame pointer sig */
|
||||
#define MSGCLASS_SIGLEN 14
|
||||
@ -508,45 +525,22 @@ int CSmmAPI::GetGameDLLVersion()
|
||||
/* :TODO: Make this prettier */
|
||||
bool CSmmAPI::CacheUserMessages()
|
||||
{
|
||||
SourceHook::MemFuncInfo info = {true, -1, 0, 0};
|
||||
SourceHook::GetFuncInfo(&IServerGameDLL::GetUserMessageInfo, info);
|
||||
|
||||
/* Get address of original GetUserMessageInfo() */
|
||||
char *vfunc = reinterpret_cast<char *>(g_GameDllPatch->GetOrigFunc(info.vtbloffs, info.vtblindex));
|
||||
|
||||
/* If we can't get original function, that means there's no hook */
|
||||
if (vfunc == NULL)
|
||||
{
|
||||
/* Get virtual function address 'manually' then */
|
||||
char *adjustedptr = reinterpret_cast<char *>(g_GameDll.pGameDLL) + info.thisptroffs + info.vtbloffs;
|
||||
char **vtable = *reinterpret_cast<char ***>(adjustedptr);
|
||||
|
||||
vfunc = vtable[info.vtblindex];
|
||||
}
|
||||
|
||||
/* Oh dear, we have a relative jump on our hands
|
||||
* PVK II on Windows made me do this, but I suppose it doesn't hurt to check this on Linux too...
|
||||
*/
|
||||
if (*vfunc == '\xE9')
|
||||
{
|
||||
/* Get address from displacement...
|
||||
*
|
||||
* Add 5 because it's relative to next instruction:
|
||||
* Opcode <1 byte> + 32-bit displacement <4 bytes>
|
||||
*/
|
||||
vfunc = vfunc + *reinterpret_cast<int *>(vfunc + 1) + 5;
|
||||
}
|
||||
|
||||
UserMsgDict *dict = NULL;
|
||||
char *vfunc = UTIL_GetOrigFunction(&IServerGameDLL::GetUserMessageInfo, g_GameDll.pGameDLL, g_GameDllPatch);
|
||||
|
||||
if (vcmp(vfunc, MSGCLASS_SIG, MSGCLASS_SIGLEN))
|
||||
if (!vfunc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (UTIL_VerifySignature(vfunc, MSGCLASS_SIG, MSGCLASS_SIGLEN))
|
||||
{
|
||||
/* Get address of CUserMessages instance */
|
||||
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS_OFFS);
|
||||
|
||||
/* Get address of CUserMessages::m_UserMessages */
|
||||
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
|
||||
} else if (vcmp(vfunc, MSGCLASS2_SIG, MSGCLASS2_SIGLEN)) {
|
||||
} else if (UTIL_VerifySignature(vfunc, MSGCLASS2_SIG, MSGCLASS2_SIGLEN)) {
|
||||
#ifdef OS_WIN32
|
||||
/* If we get here, the code is possibly inlined like in Dystopia */
|
||||
|
||||
@ -562,6 +556,14 @@ bool CSmmAPI::CacheUserMessages()
|
||||
/* Get address of CUserMessages::m_UserMessages */
|
||||
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
|
||||
#endif
|
||||
#ifdef OS_WIN32
|
||||
} else if (UTIL_VerifySignature(vfunc, MSGCLASS3_SIG, MSGCLASS3_SIGLEN)) {
|
||||
/* Get address of CUserMessages instance */
|
||||
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS3_OFFS);
|
||||
|
||||
/* Get address of CUserMessages::m_UserMessages */
|
||||
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (dict)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,4 +1,4 @@
|
||||
The software is Copyright (C) 2004-2007, Metamod:Source Development Team.
|
||||
The software is Copyright (C) 2004-2008, Metamod:Source Development Team.
|
||||
|
||||
Metamod:Source is distributed under the "zLib/libpng" license, which is reproduced
|
||||
below:
|
||||
|
@ -1,4 +1,4 @@
|
||||
#(C)2004-2007 SourceMM Development Team
|
||||
#(C)2004-2008 SourceMM Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
HL2SDK = ../../hl2sdk
|
||||
@ -34,7 +34,10 @@ endif
|
||||
|
||||
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
||||
|
||||
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
|
||||
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \
|
||||
-Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca \
|
||||
-Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Wno-uninitialized -Werror -fPIC \
|
||||
-fno-exceptions -fno-rtti -msse -m32
|
||||
|
||||
ifeq "$(GCC_VERSION)" "4"
|
||||
CFLAGS += $(GCC4_FLAGS)
|
||||
@ -55,7 +58,7 @@ all:
|
||||
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
|
||||
|
||||
sourcemm: $(OBJ_LINUX)
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
$(CPP) $(INCLUDE) -m32 $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
|
||||
debug:
|
||||
$(MAKE) all DEBUG=true
|
||||
|
@ -1,3 +1,35 @@
|
||||
2008/??/?? 1.4.5:
|
||||
- Fixed amb1952: Crash when first plugin listed in metaplugins.ini had an alias
|
||||
and was not on the first line of the file.
|
||||
|
||||
2008/07/26 1.4.4:
|
||||
- Fixed a bug where loading plugins built for MM:S 1.3 or older (API ver <= 9)
|
||||
would cause a crash.
|
||||
- Fixed a bug where loading plugins using VDF files caused Metamod:Source
|
||||
to crash on The Ship. (bug 1523)
|
||||
- Fixed a class of crashes caused by improper cvar removal handling. (bug 1416)
|
||||
- Fixed a bug where VDF files were opened by MM:S even if the .vdf extension
|
||||
was not at the very end of the filename. For example, "plugin.vdf.disabled"
|
||||
would have been opened in previous versions. (bug 1534)
|
||||
- Removed FCVAR_REPLICATED from MM:S convars. (bug 1479)
|
||||
|
||||
2008/01/23 1.4.3:
|
||||
- Metamod:Source can now be loaded via a .vdf instead of gameinfo.txt.
|
||||
- Added new plugin loading mechanism via .vdf files in the metamod folder.
|
||||
- Changed "meta list" output to look similar to Metamod:Source 1.6.
|
||||
- Plugins which need a VSP pointer can now receive it on late load.
|
||||
- Fixed a small memory leak when using recalls (RETURN_META_NEWPARAMS).
|
||||
- Fixed a rare memory corruption bug in the CVector class.
|
||||
|
||||
2007/06/26 1.4.2:
|
||||
- Fixed a bug where unloading all plugins could crash if one plugin had child plugins.
|
||||
|
||||
2007/05/16 1.4.1:
|
||||
- The client version of the "meta" command should now work with games using the latest
|
||||
Source beta (srcds0407).
|
||||
- Fixed amb233 (VSP listener didn't work with Steam dedicated version).
|
||||
- Fixed amb277 (failed to get user message list in Kreedz Climbing).
|
||||
|
||||
2007/04/05 1.4.0:
|
||||
- Added API functions for retrieving User Message info without potentially crashing.
|
||||
- Added API functions for letting SourceMM plugins use Valve Server Plugin callbacks.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -9,27 +9,34 @@
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "convar_smm.h"
|
||||
#include "CSmmAPI.h"
|
||||
#include "concommands.h"
|
||||
#include "CPlugin.h"
|
||||
#include "sh_string.h"
|
||||
#include "sh_list.h"
|
||||
#include "vsp_listener.h"
|
||||
|
||||
/**
|
||||
* @brief Console Command Implementations
|
||||
* @file concommands.cpp
|
||||
*/
|
||||
|
||||
CAlwaysRegisterableCommand g_EternalCommand;
|
||||
SMConVarAccessor g_SMConVarAccessor;
|
||||
|
||||
SMConVarAccessor::SMConVarAccessor()
|
||||
{
|
||||
m_TopConCommandBase = NULL;
|
||||
}
|
||||
|
||||
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
|
||||
{
|
||||
// Add the FCVAR_GAMEDLL flag
|
||||
// => No crash on exit!
|
||||
// UPDATE: Do _not_ add the FCVAR_GAMEDLL flag here, as it
|
||||
// causes the command to be unusable on listenservers until you load a map
|
||||
// We will set the FCVAR_GAMEDLL flag on all commands we have registered once we are being unloaded
|
||||
/* Add the FCVAR_GAMEDLL flag
|
||||
* => No crash on exit!
|
||||
* UPDATE: Do _not_ add the FCVAR_GAMEDLL flag here, as it
|
||||
* causes the command to be unusable on listen servers until you load a map
|
||||
* We will set the FCVAR_GAMEDLL flag on all commands we have registered once we are being unloaded
|
||||
*/
|
||||
// pCommand->AddFlags(FCVAR_GAMEDLL);
|
||||
m_RegisteredCommands.push_back(pCommand);
|
||||
|
||||
@ -41,7 +48,7 @@ bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
|
||||
|
||||
bool SMConVarAccessor::Register(ConCommandBase *pCommand)
|
||||
{
|
||||
//simple, don't mark as part of sourcemm!
|
||||
/* Simple, don't mark as part of sourcemm! */
|
||||
pCommand->SetNext(NULL);
|
||||
g_Engine.icvar->RegisterConCommandBase(pCommand);
|
||||
|
||||
@ -59,67 +66,52 @@ void SMConVarAccessor::MarkCommandsAsGameDLL()
|
||||
|
||||
void SMConVarAccessor::Unregister(ConCommandBase *pCommand)
|
||||
{
|
||||
ICvar *cv = g_Engine.icvar;
|
||||
ConCommandBase *ptr = cv->GetCommands();
|
||||
|
||||
if (ptr == pCommand)
|
||||
{
|
||||
//first in list
|
||||
g_EternalCommand.BringToFront();
|
||||
g_EternalCommand.SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
|
||||
} else {
|
||||
//find us and unregister us
|
||||
ConCommandBase *pCur = NULL;
|
||||
ConCommandBase *pPrev = NULL;
|
||||
while (ptr)
|
||||
|
||||
if (!pCommand || !pCommand->IsRegistered())
|
||||
{
|
||||
if (ptr == pCommand)
|
||||
break;
|
||||
pPrev = ptr;
|
||||
ptr = const_cast<ConCommandBase *>(ptr->GetNext());
|
||||
return;
|
||||
}
|
||||
if (pPrev && ptr == pCommand)
|
||||
|
||||
pCur = g_Engine.icvar->GetCommands();
|
||||
pCommand->SetRegistered(false);
|
||||
|
||||
if (!m_TopConCommandBase || !pCur)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pCur == pCommand)
|
||||
{
|
||||
*m_TopConCommandBase = const_cast<ConCommandBase *>(pCommand->GetNext());
|
||||
pCommand->SetNext(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
pPrev = pCur;
|
||||
pCur = const_cast<ConCommandBase *>(pCur->GetNext());
|
||||
|
||||
while (pCur)
|
||||
{
|
||||
if (pCur == pCommand)
|
||||
{
|
||||
pPrev->SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
|
||||
pCommand->SetNext(NULL);
|
||||
}
|
||||
|
||||
pPrev = pCur;
|
||||
pCur = const_cast<ConCommandBase *>(pCur->GetNext());
|
||||
}
|
||||
}
|
||||
|
||||
void SMConVarAccessor::UnregisterGameDLLCommands()
|
||||
{
|
||||
ConCommandBase *begin = g_Engine.icvar->GetCommands();
|
||||
ConCommandBase *iter = begin;
|
||||
ConCommandBase *prev = NULL;
|
||||
while (iter)
|
||||
{
|
||||
// watch out for the ETERNAL COMMAND!
|
||||
if (iter != &g_EternalCommand && iter->IsBitSet(FCVAR_GAMEDLL))
|
||||
{
|
||||
// Remove it!
|
||||
if (iter == begin)
|
||||
{
|
||||
g_EternalCommand.BringToFront();
|
||||
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
||||
g_EternalCommand.SetNext(iter);
|
||||
prev = &g_EternalCommand;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
||||
prev->SetNext(iter);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
prev = iter;
|
||||
iter = const_cast<ConCommandBase*>(iter->GetNext());
|
||||
}
|
||||
}
|
||||
|
||||
ConVar metamod_version("metamod_version", SOURCEMM_VERSION, FCVAR_REPLICATED | FCVAR_SPONLY | FCVAR_NOTIFY, "Metamod:Source Version");
|
||||
#if defined WIN32 || defined _WIN32
|
||||
ConVar metamod_version("metamod_version", SOURCEMM_VERSION, FCVAR_SPONLY | FCVAR_NOTIFY, "Metamod:Source Version");
|
||||
#ifdef OS_WIN32
|
||||
ConVar mm_pluginsfile("mm_pluginsfile", "addons\\metamod\\metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File");
|
||||
ConVar mm_basedir("mm_basedir", "addons\\metamod", FCVAR_SPONLY, "Metamod:Source base folder");
|
||||
#else
|
||||
ConVar mm_pluginsfile("mm_pluginsfile", "addons/metamod/metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File");
|
||||
ConVar mm_basedir("mm_basedir", "addons/metamod", FCVAR_SPONLY, "Metamod:Source base folder");
|
||||
#endif
|
||||
|
||||
CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
@ -128,6 +120,12 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
|
||||
int args = e->Cmd_Argc();
|
||||
|
||||
if (g_VspListener.IsRootLoadMethod() && !g_bLevelChanged)
|
||||
{
|
||||
CONMSG("WARNING: You must change the map to activate Metamod:Source.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args >= 2)
|
||||
{
|
||||
const char *command = e->Cmd_Argv(1);
|
||||
@ -138,15 +136,23 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
CONMSG(" GameDLL/Plugins: David \"BAILOPAN\" Anderson\n");
|
||||
CONMSG(" GameDLL: Scott \"Damaged Soul\" Ehlert\n");
|
||||
CONMSG("For more information, see the official website\n");
|
||||
CONMSG("http://www.sourcemm.net/\n");
|
||||
CONMSG("http://www.metamodsource.net/\n");
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "version") == 0) {
|
||||
CONMSG("Metamod:Source version %s\n", SOURCEMM_VERSION);
|
||||
if (g_VspListener.IsRootLoadMethod())
|
||||
{
|
||||
CONMSG("Loaded As: Valve Server Plugin\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Loaded As: GameDLL (gameinfo.txt)\n");
|
||||
}
|
||||
CONMSG("Compiled on: %s\n", SOURCEMM_DATE);
|
||||
CONMSG("Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION);
|
||||
CONMSG("SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
|
||||
CONMSG("http://www.sourcemm.net/\n");
|
||||
CONMSG("http://www.metamodsource.net/\n");
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "game") == 0) {
|
||||
@ -191,58 +197,62 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "list") == 0) {
|
||||
SourceMM::CPluginManager::CPlugin *pl;
|
||||
size_t len;
|
||||
PluginIter i;
|
||||
const char *status="";
|
||||
const char *version=NULL;
|
||||
const char *name=NULL;
|
||||
const char *author=NULL;
|
||||
char buffer[255];
|
||||
ISmmPlugin *plapi;
|
||||
const char *plname;
|
||||
SourceMM::CPluginManager::CPlugin *pl;
|
||||
unsigned int plnum = g_PluginMngr.GetPluginCount();
|
||||
|
||||
#define IS_STR_FILLED(var) (var != NULL && var[0] != '\0')
|
||||
|
||||
if (!plnum)
|
||||
{
|
||||
CONMSG("No plugins loaded.\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONMSG("Listing %d plugin%s:\n", plnum, (plnum > 1) ? "s" : "");
|
||||
}
|
||||
|
||||
CONMSG("-Id- %-20.19s %-10.9s %-20.19s %-8.7s\n", "Name", "Version", "Author", "Status");
|
||||
for (i=g_PluginMngr._begin(); i!=g_PluginMngr._end(); i++)
|
||||
{
|
||||
pl = (*i);
|
||||
if (!pl)
|
||||
{
|
||||
break;
|
||||
if (pl->m_Status == Pl_Paused)
|
||||
}
|
||||
|
||||
len = 0;
|
||||
|
||||
if (pl->m_Status != Pl_Running)
|
||||
{
|
||||
status = "PAUSE";
|
||||
} else if (pl->m_Status == Pl_Running) {
|
||||
if (pl->m_API && pl->m_API->QueryRunning(NULL, 0))
|
||||
status = "RUN";
|
||||
len += UTIL_Format(buffer, sizeof(buffer), " [%02d] <%s>", pl->m_Id, g_PluginMngr.GetStatusText(pl));
|
||||
}
|
||||
else
|
||||
status = "STOPPED";
|
||||
} else if (pl->m_Status == Pl_Refused) {
|
||||
status = "FAIL";
|
||||
} else if (pl->m_Status == Pl_Error) {
|
||||
status = "ERROR";
|
||||
} else if (pl->m_Status == Pl_NotFound) {
|
||||
status = "NOFILE";
|
||||
}
|
||||
|
||||
if (pl->m_API)
|
||||
{
|
||||
version = pl->m_API->GetVersion();
|
||||
author = pl->m_API->GetAuthor();
|
||||
name = pl->m_API->GetName();
|
||||
} else {
|
||||
version = "-";
|
||||
author = "-";
|
||||
name = "-";
|
||||
len += UTIL_Format(buffer, sizeof(buffer), " [%02d]", pl->m_Id);
|
||||
}
|
||||
|
||||
if (!version)
|
||||
version = "-";
|
||||
if (!author)
|
||||
author = "-";
|
||||
if (!name)
|
||||
name = pl->m_File.c_str();
|
||||
if ((plapi = pl->m_API))
|
||||
{
|
||||
plname = IS_STR_FILLED(plapi->GetName()) ? plapi->GetName() : pl->m_File.c_str();
|
||||
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " %s", plname);
|
||||
|
||||
|
||||
CONMSG("[%02d] %-20.19s %-10.9s %-20.19s %-8.7s\n", pl->m_Id, name, version, author, status);
|
||||
if (IS_STR_FILLED(plapi->GetVersion()))
|
||||
{
|
||||
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", plapi->GetVersion());
|
||||
}
|
||||
if (IS_STR_FILLED(plapi->GetAuthor()))
|
||||
{
|
||||
UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", plapi->GetAuthor());
|
||||
}
|
||||
}
|
||||
|
||||
//CONMSG("\n");
|
||||
CONMSG("%s\n", buffer);
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (strcmp(command, "cmds") == 0) {
|
||||
@ -625,53 +635,6 @@ CON_COMMAND(meta, "Metamod:Source Menu")
|
||||
CONMSG(" version - Version information\n");
|
||||
}
|
||||
|
||||
CAlwaysRegisterableCommand::CAlwaysRegisterableCommand()
|
||||
{
|
||||
Create("", NULL, FCVAR_UNREGISTERED|FCVAR_GAMEDLL);
|
||||
m_pICvar = NULL;
|
||||
}
|
||||
|
||||
bool CAlwaysRegisterableCommand::IsRegistered( void ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CAlwaysRegisterableCommand::BringToFront()
|
||||
{
|
||||
if (!m_pICvar)
|
||||
m_pICvar = g_Engine.icvar;
|
||||
|
||||
// First, let's try to find us!
|
||||
ConCommandBase *pPtr = m_pICvar->GetCommands();
|
||||
|
||||
if (pPtr == this)
|
||||
{
|
||||
// We are already at the beginning; Nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
while (pPtr)
|
||||
{
|
||||
if (pPtr == this && pPtr->IsCommand() && stricmp(GetName(), pPtr->GetName()) == 0)
|
||||
break;
|
||||
ConCommandBase *pPrev = NULL;
|
||||
while (pPtr)
|
||||
{
|
||||
if (pPtr == this)
|
||||
break;
|
||||
pPrev = pPtr;
|
||||
pPtr = const_cast<ConCommandBase*>(pPtr->GetNext());
|
||||
}
|
||||
if (pPrev && pPtr == this)
|
||||
{
|
||||
pPrev->SetNext(m_pNext); // Remove us from the list
|
||||
}
|
||||
// Now, register us
|
||||
SetNext(NULL);
|
||||
m_pICvar->RegisterConCommandBase(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientCommand_handler(edict_t *client)
|
||||
{
|
||||
IVEngineServer *e = g_Engine.engine;
|
||||
@ -688,10 +651,10 @@ void ClientCommand_handler(edict_t *client)
|
||||
{
|
||||
CLIENT_CONMSG(client, "Metamod:Source was developed by:\n");
|
||||
CLIENT_CONMSG(client, " SourceHook: Pavol \"PM OnoTo\" Marko\n");
|
||||
CLIENT_CONMSG(client, " GameDLL/Plugins: David \"BAILOPAN\" Anderson\n");
|
||||
CLIENT_CONMSG(client, " GameDLL: Scott \"Damaged Soul\" Ehlert\n");
|
||||
CLIENT_CONMSG(client, " Core: David \"BAILOPAN\" Anderson\n");
|
||||
CLIENT_CONMSG(client, " Core: Scott \"Damaged Soul\" Ehlert\n");
|
||||
CLIENT_CONMSG(client, "For more information, see the official website\n");
|
||||
CLIENT_CONMSG(client, "http://www.sourcemm.net/\n");
|
||||
CLIENT_CONMSG(client, "http://www.metamodsource.net/\n");
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
} else if(strcmp(subcmd, "version") == 0) {
|
||||
@ -699,49 +662,53 @@ void ClientCommand_handler(edict_t *client)
|
||||
CLIENT_CONMSG(client, "Compiled on: %s\n", SOURCEMM_DATE);
|
||||
CLIENT_CONMSG(client, "Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION);
|
||||
CLIENT_CONMSG(client, "SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
|
||||
CLIENT_CONMSG(client, "http://www.sourcemm.net/\n");
|
||||
CLIENT_CONMSG(client, "http://www.metamodsource.net/\n");
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
} else if(strcmp(subcmd, "list") == 0) {
|
||||
SourceMM::CPluginManager::CPlugin *pl;
|
||||
Pl_Status st;
|
||||
ISmmPlugin *plapi;
|
||||
const char *plname;
|
||||
PluginIter i;
|
||||
const char *version = NULL;
|
||||
const char *name = NULL;
|
||||
const char *author = NULL;
|
||||
const char *status = NULL;
|
||||
char buffer[256];
|
||||
int len = 0;
|
||||
int plnum = 0;
|
||||
|
||||
CLIENT_CONMSG(client, "-Id- %-20.19s %-10.9s %-20.19s %6s\n", "Name", "Version", "Author", "Status");
|
||||
|
||||
for (i=g_PluginMngr._begin(); i!=g_PluginMngr._end(); i++)
|
||||
for (i = g_PluginMngr._begin(); i != g_PluginMngr._end(); i++, len=0)
|
||||
{
|
||||
pl = (*i);
|
||||
if (!pl)
|
||||
break;
|
||||
|
||||
st = pl->m_Status;
|
||||
|
||||
/* Only show plugins that are running or paused */
|
||||
if (pl->m_API && (st == Pl_Running || st == Pl_Paused))
|
||||
if (pl && pl->m_Status == Pl_Running)
|
||||
{
|
||||
version = pl->m_API->GetVersion();
|
||||
author = pl->m_API->GetAuthor();
|
||||
name = pl->m_API->GetName();
|
||||
|
||||
if (st == Pl_Running && pl->m_API->QueryRunning(NULL, 0))
|
||||
plapi = pl->m_API;
|
||||
if (!plapi || !plapi->QueryRunning(NULL, 0))
|
||||
{
|
||||
status = "RUN";
|
||||
} else {
|
||||
status = "PAUSE";
|
||||
continue;
|
||||
}
|
||||
plnum++;
|
||||
|
||||
len += UTIL_Format(buffer, sizeof(buffer), " [%02d]", plnum);
|
||||
|
||||
plname = IS_STR_FILLED(plapi->GetName()) ? plapi->GetName() : pl->m_File.c_str();
|
||||
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " %s", plname);
|
||||
|
||||
if (IS_STR_FILLED(plapi->GetVersion()))
|
||||
{
|
||||
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", plapi->GetVersion());
|
||||
}
|
||||
if (IS_STR_FILLED(plapi->GetAuthor()))
|
||||
{
|
||||
UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", plapi->GetAuthor());
|
||||
}
|
||||
|
||||
if (!version || !author || !name)
|
||||
break;
|
||||
|
||||
CLIENT_CONMSG(client, "[%02d] %-20.19s %-10.9s %-20.19s %6s\n", pl->m_Id, name, version, author, status);
|
||||
CLIENT_CONMSG(client, "%s\n", buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!plnum)
|
||||
{
|
||||
CLIENT_CONMSG(client, "No active plugins loaded.\n");
|
||||
}
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
}
|
||||
@ -758,7 +725,79 @@ void ClientCommand_handler(edict_t *client)
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void SMConVarAccessor::UnloadMetamodCommands()
|
||||
{
|
||||
Unregister(&metamod_version);
|
||||
Unregister(&mm_pluginsfile);
|
||||
Unregister(&mm_basedir);
|
||||
Unregister(&meta_command);
|
||||
}
|
||||
|
||||
const char *GetPluginsFile()
|
||||
{
|
||||
return mm_pluginsfile.GetString();
|
||||
}
|
||||
|
||||
const char *GetMetamodBaseDir()
|
||||
{
|
||||
return mm_basedir.GetString();
|
||||
}
|
||||
|
||||
/* Signature for ICvar::GetCommands() in vstdlib for Win32 and Linux.
|
||||
*
|
||||
* 20226EE0 A1 50 5C 5A 20 mov eax,dword ptr ds:[205A5C50h] <-- What we want
|
||||
* 20226EE5 C3 ret
|
||||
*/
|
||||
#define CMDLIST_SIG "\xA1\x2A\x2A\x2A\x2A\xC3"
|
||||
#define CMDLIST_SIGLEN 6
|
||||
|
||||
/* Linux symbol name of ConCommandBase list in vstdlib */
|
||||
#define CMDLIST_SYMBOL "_ZN14ConCommandBase18s_pConCommandBasesE"
|
||||
|
||||
/* This function retrieves the address of the var that holds the top of the ConCommandBase list.
|
||||
* Having this allows us to change the beginning of this list with ease.
|
||||
*
|
||||
* This craziness eliminates the need for the eternal command/cvar used previously which
|
||||
* could have caused a crash as a result of registering commands/cvars more than once.
|
||||
*/
|
||||
bool SMConVarAccessor::InitConCommandBaseList()
|
||||
{
|
||||
char *vfunc = UTIL_GetOrigFunction(&ICvar::GetCommands, g_Engine.icvar, g_CvarPatch);
|
||||
|
||||
if (!vfunc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef OS_WIN32
|
||||
if (UTIL_VerifySignature(vfunc, CMDLIST_SIG, CMDLIST_SIGLEN))
|
||||
{
|
||||
/* Skip past 0xA1 and get addr of ConCommandBase list var */
|
||||
m_TopConCommandBase = *reinterpret_cast<ConCommandBase ***>(vfunc + 1);
|
||||
return true;
|
||||
}
|
||||
#elif defined OS_LINUX
|
||||
/* Try dlsym first */
|
||||
char path[PATH_SIZE];
|
||||
if (GetFileOfAddress((void *)g_Engine.icvar, path, sizeof(path)))
|
||||
{
|
||||
void *handle = dlopen(path, RTLD_NOW);
|
||||
if (handle)
|
||||
{
|
||||
m_TopConCommandBase = reinterpret_cast<ConCommandBase **>(dlsym(handle, CMDLIST_SYMBOL));
|
||||
dlclose(handle);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If dlsym failed, then verify signature of function */
|
||||
if (!m_TopConCommandBase && UTIL_VerifySignature(vfunc, CMDLIST_SIG, CMDLIST_SIGLEN))
|
||||
{
|
||||
/* Skip past 0xA1 and get addr of ConCommandBase list var */
|
||||
m_TopConCommandBase = *reinterpret_cast<ConCommandBase ***>(vfunc + 1);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -16,37 +16,28 @@
|
||||
* @file concommands.h
|
||||
*/
|
||||
|
||||
#include <interface.h>
|
||||
#include <eiface.h>
|
||||
#include "sourcemm.h"
|
||||
#include "convar_smm.h"
|
||||
#include "sourcemm.h"
|
||||
#include "sh_list.h"
|
||||
|
||||
class SMConVarAccessor : public IConCommandBaseAccessor
|
||||
{
|
||||
SourceHook::List<ConCommandBase*> m_RegisteredCommands;
|
||||
ConCommandBase **m_TopConCommandBase;
|
||||
public:
|
||||
SMConVarAccessor();
|
||||
virtual bool RegisterConCommandBase(ConCommandBase *pCommand);
|
||||
bool Register(ConCommandBase *pCommand);
|
||||
void MarkCommandsAsGameDLL();
|
||||
bool InitConCommandBaseList();
|
||||
void Unregister(ConCommandBase *pCommand);
|
||||
void UnregisterGameDLLCommands();
|
||||
};
|
||||
|
||||
class CAlwaysRegisterableCommand : public ConCommandBase
|
||||
{
|
||||
ICvar *m_pICvar;
|
||||
public:
|
||||
CAlwaysRegisterableCommand();
|
||||
bool IsRegistered( void ) const;
|
||||
// If already registered, removes us
|
||||
// Then it registers us again
|
||||
void BringToFront();
|
||||
void UnloadMetamodCommands();
|
||||
};
|
||||
|
||||
void ClientCommand_handler(edict_t *client);
|
||||
|
||||
const char *GetPluginsFile();
|
||||
const char *GetMetamodBaseDir();
|
||||
|
||||
extern SMConVarAccessor g_SMConVarAccessor;
|
||||
|
||||
|
@ -198,6 +198,11 @@ protected:
|
||||
|
||||
// ConVars in this executable use this 'global' to access values.
|
||||
static IConCommandBaseAccessor *s_pAccessor;
|
||||
public:
|
||||
inline void SetRegistered(bool registered)
|
||||
{
|
||||
m_bRegistered = registered;
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -242,7 +247,7 @@ private:
|
||||
FnCommandCompletionCallback m_fnCompletionCallback;
|
||||
bool m_bHasCompletionCallback;
|
||||
public:
|
||||
FnCommandCallback GetCallback() { return m_fnCommandCallback; }
|
||||
inline FnCommandCallback GetCallback() { return m_fnCommandCallback; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -41,6 +41,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=""$(HL2SDK)\public";"$(HL2SDK)\public\dlls";"$(HL2SDK)\public\engine";"$(HL2SDK)\public\tier0";"$(HL2SDK)\public\tier1";"$(HL2SDK)\public\vstdlib";..\..;..\..\sourcehook"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
@ -62,7 +63,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
|
||||
AdditionalDependencies=""$(HL2SDK)\lib\public\tier0.lib" "$(HL2SDK)\lib\public\tier1.lib" "$(HL2SDK)\lib\public\vstdlib.lib""
|
||||
OutputFile="$(OutDir)/server.dll"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
|
||||
@ -126,6 +127,7 @@
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
AdditionalIncludeDirectories=""$(HL2SDK)\public";"$(HL2SDK)\public\dlls";"$(HL2SDK)\public\engine";"$(HL2SDK)\public\tier0";"$(HL2SDK)\public\tier1";"$(HL2SDK)\public\vstdlib";..\..;..\..\sourcehook"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||
StringPooling="true"
|
||||
ExceptionHandling="1"
|
||||
@ -148,7 +150,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
|
||||
AdditionalDependencies=""$(HL2SDK)\lib\public\tier0.lib" "$(HL2SDK)\lib\public\tier1.lib" "$(HL2SDK)\lib\public\vstdlib.lib""
|
||||
OutputFile="$(OutDir)/server.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"
|
||||
@ -273,6 +275,10 @@
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\svn_version.tpl"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\version.rc"
|
||||
>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -16,17 +16,29 @@
|
||||
#include "oslink.h"
|
||||
#ifdef __linux
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
const char *dlerror()
|
||||
{
|
||||
static char buf[1024];
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(),
|
||||
DWORD num;
|
||||
|
||||
num = GetLastError();
|
||||
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
num,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &buf, 0, NULL);
|
||||
buf,
|
||||
sizeof(buf),
|
||||
NULL)
|
||||
== 0)
|
||||
{
|
||||
_snprintf(buf, sizeof(buf), "unknown error %x", num);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -56,7 +56,7 @@
|
||||
#endif
|
||||
|
||||
#if defined __linux__
|
||||
extern int errno;
|
||||
#include <errno.h>
|
||||
int GetLastError();
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
The software is Copyright (C) 2004-2007, Metamod:Source Development Team.
|
||||
The software is Copyright (C) 2004-2008, Metamod:Source Development Team.
|
||||
|
||||
Metamod:Source is distributed under the "zLib/libpng" license, which is reproduced
|
||||
below:
|
||||
|
@ -1,4 +1,4 @@
|
||||
#(C)2004-2007 SourceMM Development Team
|
||||
#(C)2004-2008 SourceMM Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
HL2SDK = ../../../hl2sdk
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== sample_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== sample_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== sample_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== sample_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -41,6 +41,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=""$(SOURCEMM14)";"$(SOURCEMM14)\sourcemm";"$(SOURCEMM14)\sourcehook";"$(HL2SDK)\public";"$(HL2SDK)\public\dlls";"$(HL2SDK)\public\engine";"$(HL2SDK)\public\tier0";"$(HL2SDK)\public\tier1";"$(HL2SDK)\public\vstdlib""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
@ -62,7 +63,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
|
||||
AdditionalDependencies=""$(HL2SDK)\lib\public\tier0.lib" "$(HL2SDK)\lib\public\tier1.lib" "$(HL2SDK)\lib\public\vstdlib.lib""
|
||||
OutputFile="$(OutDir)/sample_mm.dll"
|
||||
LinkIncremental="2"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
|
||||
@ -122,6 +123,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""$(SOURCEMM14)";"$(SOURCEMM14)\sourcemm";"$(SOURCEMM14)\sourcehook";"$(HL2SDK)\public";"$(HL2SDK)\public\dlls";"$(HL2SDK)\public\engine";"$(HL2SDK)\public\tier0";"$(HL2SDK)\public\tier1";"$(HL2SDK)\public\vstdlib""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
|
||||
RuntimeLibrary="0"
|
||||
RuntimeTypeInfo="false"
|
||||
@ -142,7 +144,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib"
|
||||
AdditionalDependencies=""$(HL2SDK)\lib\public\tier0.lib" "$(HL2SDK)\lib\public\tier1.lib" "$(HL2SDK)\lib\public\vstdlib.lib""
|
||||
OutputFile="$(OutDir)/sample_mm.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -19,6 +19,8 @@
|
||||
#include "CPlugin.h"
|
||||
#include "util.h"
|
||||
#include "vsp_listener.h"
|
||||
#include "iplayerinfo.h"
|
||||
#include <filesystem.h>
|
||||
|
||||
using namespace SourceMM;
|
||||
|
||||
@ -43,6 +45,8 @@ void DLLShutdown_handler();
|
||||
void LevelShutdown_handler();
|
||||
bool LevelInit_handler(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
|
||||
bool GameInit_handler();
|
||||
void LookForVDFs(const char *dir);
|
||||
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL);
|
||||
|
||||
GameDllInfo g_GameDll = {false, NULL, NULL, NULL, NULL};
|
||||
EngineInfo g_Engine;
|
||||
@ -57,24 +61,28 @@ bool gParsedGameInfo = false;
|
||||
bool bGameInit = false;
|
||||
SourceHook::List<GameDllInfo *> gamedll_list;
|
||||
SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
|
||||
SourceHook::CallClass<ICvar> *g_CvarPatch;
|
||||
int g_GameDllVersion = 0;
|
||||
const char VSPIFACE_001[] = "ISERVERPLUGINCALLBACKS001";
|
||||
const char VSPIFACE_002[] = "ISERVERPLUGINCALLBACKS002";
|
||||
const char GAMEINFO_PATH[] = "|gameinfo_path|";
|
||||
IFileSystem *baseFs = NULL;
|
||||
bool g_bLevelChanged = false;
|
||||
|
||||
|
||||
void ClearGamedllList();
|
||||
|
||||
/* Helper Macro */
|
||||
#define IFACE_MACRO(orig,nam) \
|
||||
CPluginManager::CPlugin *pl; \
|
||||
SourceHook::List<IMetamodListener *>::iterator event; \
|
||||
SourceHook::List<CPluginEventHandler>::iterator event; \
|
||||
IMetamodListener *api; \
|
||||
int mret = 0; \
|
||||
void *val = NULL; \
|
||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
||||
pl = (*iter); \
|
||||
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
|
||||
api = (*event); \
|
||||
api = (*event).event; \
|
||||
mret = IFACE_FAILED; \
|
||||
if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \
|
||||
if (ret) *ret = mret; \
|
||||
@ -86,12 +94,12 @@ void ClearGamedllList();
|
||||
|
||||
#define ITER_EVENT(evn, args) \
|
||||
CPluginManager::CPlugin *pl; \
|
||||
SourceHook::List<IMetamodListener *>::iterator event; \
|
||||
SourceHook::List<CPluginEventHandler>::iterator event; \
|
||||
IMetamodListener *api; \
|
||||
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
|
||||
pl = (*iter); \
|
||||
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
|
||||
api = (*event); \
|
||||
api = (*event).event; \
|
||||
api->evn args; \
|
||||
} \
|
||||
}
|
||||
@ -119,25 +127,34 @@ void InitMainStates()
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelShutdown, g_GameDll.pGameDLL, LevelShutdown_handler, true);
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelInit, g_GameDll.pGameDLL, LevelInit_handler, true);
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, GameInit, g_GameDll.pGameDLL, GameInit_handler, false);
|
||||
|
||||
if (g_GameDll.pGameClients)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, g_GameDll.pGameClients, ClientCommand_handler, false);
|
||||
} else {
|
||||
/* If IServerGameClients isn't found, this really isn't a fatal error so... */
|
||||
LogMessage("[META] Warning: Could not find IServerGameClients!");
|
||||
LogMessage("[META] Warning: The 'meta' command will not be available to clients.");
|
||||
}
|
||||
}
|
||||
|
||||
bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
|
||||
void DoInitialPluginLoads()
|
||||
{
|
||||
g_Engine.engineFactory = engineFactory;
|
||||
g_Engine.fileSystemFactory = filesystemFactory;
|
||||
g_Engine.physicsFactory = physicsFactory;
|
||||
g_Engine.pGlobals = pGlobals;
|
||||
const char *pluginFile = g_Engine.icvar->GetCommandLineValue("mm_pluginsfile");
|
||||
const char *mmBaseDir = g_Engine.icvar->GetCommandLineValue("mm_basedir");
|
||||
|
||||
if (!pluginFile)
|
||||
{
|
||||
pluginFile = GetPluginsFile();
|
||||
}
|
||||
if (!mmBaseDir)
|
||||
{
|
||||
mmBaseDir = GetMetamodBaseDir();
|
||||
}
|
||||
|
||||
char full_path[260];
|
||||
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), pluginFile);
|
||||
LoadPluginsFromFile(full_path);
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), mmBaseDir);
|
||||
LookForVDFs(full_path);
|
||||
}
|
||||
|
||||
bool StartupMetamod(CreateInterfaceFn engineFactory, bool bWaitForGameInit)
|
||||
{
|
||||
g_Engine.engine = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL));
|
||||
|
||||
if (!g_Engine.engine)
|
||||
{
|
||||
Error("Could not find IVEngineServer! Metamod cannot load.");
|
||||
@ -152,10 +169,24 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory,
|
||||
|
||||
g_Engine.loaded = true;
|
||||
|
||||
/* Initialize our console hooks */
|
||||
/* The Ship is the only game known at this time that uses the pre-Episode One engine */
|
||||
g_Engine.original = strcmp(CommandLine()->ParmValue("-game", "hl2"), "ship") == 0;
|
||||
|
||||
ConCommandBaseMgr::OneTimeInit(static_cast<IConCommandBaseAccessor *>(&g_SMConVarAccessor));
|
||||
|
||||
g_GameDllPatch = SH_GET_CALLCLASS(g_GameDll.pGameDLL);
|
||||
g_CvarPatch = SH_GET_CALLCLASS(g_Engine.icvar);
|
||||
|
||||
if (g_GameDll.pGameClients)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, g_GameDll.pGameClients, ClientCommand_handler, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If IServerGameClients isn't found, this really isn't a fatal error so... */
|
||||
LogMessage("[META] Warning: Could not find IServerGameClients!");
|
||||
LogMessage("[META] Warning: The 'meta' command will not be available to clients.");
|
||||
}
|
||||
|
||||
if (!g_SmmAPI.CacheCmds())
|
||||
{
|
||||
@ -172,34 +203,127 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory,
|
||||
LogMessage("[META] Warning: The 'meta game' command will not display user messages.");
|
||||
}
|
||||
|
||||
const char *pluginFile = g_Engine.icvar->GetCommandLineValue("mm_pluginsfile");
|
||||
if (!pluginFile)
|
||||
baseFs = (IFileSystem *)((engineFactory)(FILESYSTEM_INTERFACE_VERSION, NULL));
|
||||
if (baseFs == NULL)
|
||||
{
|
||||
pluginFile = GetPluginsFile();
|
||||
LogMessage("[META] Failed to find filesystem interface, .vdf files will not be parsed.");
|
||||
}
|
||||
|
||||
char full_path[260];
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), pluginFile);
|
||||
|
||||
LoadPluginsFromFile(full_path);
|
||||
if (!g_SMConVarAccessor.InitConCommandBaseList())
|
||||
{
|
||||
/* This is very unlikely considering it's old engine */
|
||||
LogMessage("[META] Warning: Failed to find ConCommandBase list!");
|
||||
LogMessage("[META] Warning: ConVars and ConCommands cannot be unregistered properly! Please file a bug report.");
|
||||
}
|
||||
|
||||
if (!bWaitForGameInit)
|
||||
{
|
||||
DoInitialPluginLoads();
|
||||
bInFirstLevel = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
|
||||
{
|
||||
g_Engine.engineFactory = engineFactory;
|
||||
g_Engine.fileSystemFactory = filesystemFactory;
|
||||
g_Engine.physicsFactory = physicsFactory;
|
||||
g_Engine.pGlobals = pGlobals;
|
||||
|
||||
StartupMetamod(engineFactory, false);
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn serverFactory)
|
||||
{
|
||||
g_Engine.engineFactory = ifaceFactory;
|
||||
g_Engine.fileSystemFactory = ifaceFactory;
|
||||
g_Engine.physicsFactory = ifaceFactory;
|
||||
|
||||
IPlayerInfoManager *playerInfoManager = (IPlayerInfoManager *)serverFactory("PlayerInfoManager002", NULL);
|
||||
if (playerInfoManager == NULL)
|
||||
{
|
||||
Error("Metamod:Source requires gameinfo.txt modification to load on this game.");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_Engine.pGlobals = playerInfoManager->GetGlobalVars();
|
||||
|
||||
/* Now find the server */
|
||||
g_GameDll.factory = serverFactory;
|
||||
g_GameDll.lib = NULL;
|
||||
|
||||
char gamedll_iface[] = "ServerGameDLL000";
|
||||
for (unsigned int i = 3; i <= 50; i++)
|
||||
{
|
||||
gamedll_iface[15] = '0' + i;
|
||||
g_GameDll.pGameDLL = (IServerGameDLL *)serverFactory(gamedll_iface, NULL);
|
||||
if (g_GameDll.pGameDLL != NULL)
|
||||
{
|
||||
g_GameDllVersion = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_GameDll.pGameDLL == NULL)
|
||||
{
|
||||
Error("Metamod:Source requires gameinfo.txt modification to load on this game.");
|
||||
return false;
|
||||
}
|
||||
|
||||
char gameclients_iface[] = "ServerGameClients000";
|
||||
for (unsigned int i = 3; i <= 4; i++)
|
||||
{
|
||||
gameclients_iface[19] = '0' + i;
|
||||
g_GameDll.pGameClients = (IServerGameClients *)serverFactory(gameclients_iface, NULL);
|
||||
if (g_GameDll.pGameClients != NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char smm_path[PATH_SIZE];
|
||||
const char *game_dir;
|
||||
GetFileOfAddress((void *)AlternatelyLoadMetamod, smm_path, sizeof(smm_path));
|
||||
g_SmmPath.assign(smm_path);
|
||||
|
||||
game_dir = CommandLine()->ParmValue("-game", "hl2");
|
||||
abspath(smm_path, game_dir);
|
||||
g_ModPath.assign(smm_path);
|
||||
|
||||
InitMainStates();
|
||||
|
||||
if (!StartupMetamod(ifaceFactory, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
g_PluginMngr.SetAllLoaded();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GameInit_handler()
|
||||
{
|
||||
if (bGameInit)
|
||||
{
|
||||
return true;
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
if (g_SmmAPI.VSPEnabled())
|
||||
if (g_SmmAPI.VSPEnabled() && !g_VspListener.IsRootLoadMethod())
|
||||
{
|
||||
g_SmmAPI.LoadAsVSP();
|
||||
}
|
||||
|
||||
if (g_VspListener.IsRootLoadMethod())
|
||||
{
|
||||
DoInitialPluginLoads();
|
||||
//gaben
|
||||
}
|
||||
|
||||
bGameInit = true;
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
@ -217,7 +341,7 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
/* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */
|
||||
if (strcmp(iface, PLAPI_NAME) == 0)
|
||||
{
|
||||
Warning("Do not try loading Metamod:Source as a SourceMM or Valve server plugin.\n");
|
||||
Warning("Do not try loading Metamod:Source as a Metamod:Source plugin");
|
||||
|
||||
if (ret)
|
||||
{
|
||||
@ -240,6 +364,12 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
return &g_VspListener;
|
||||
}
|
||||
|
||||
/* If we're a VSP, bypass this by default */
|
||||
if (g_VspListener.IsRootLoadMethod())
|
||||
{
|
||||
IFACE_MACRO(g_GameDll.factory, GameDLL);
|
||||
}
|
||||
|
||||
if (!gParsedGameInfo)
|
||||
{
|
||||
gParsedGameInfo = true;
|
||||
@ -373,7 +503,6 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
pInfo->lib = gamedll;
|
||||
pInfo->loaded = true;
|
||||
pInfo->pGameDLL = NULL;
|
||||
pInfo->pGameClients = (IServerGameClients *)((fn)(INTERFACEVERSION_SERVERGAMECLIENTS, NULL));
|
||||
gamedll_list.push_back(pInfo);
|
||||
break;
|
||||
}
|
||||
@ -446,6 +575,15 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
|
||||
}
|
||||
}
|
||||
|
||||
/* We use this interface for responding to the meta client command */
|
||||
if (strncmp(iface, "ServerGameClients", 17) == 0)
|
||||
{
|
||||
void *ptr = (g_GameDll.factory)(iface, ret);
|
||||
g_GameDll.pGameClients = static_cast<IServerGameClients *>(ptr);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* If we got here, there's definitely a GameDLL */
|
||||
IFACE_MACRO(g_GameDll.factory, GameDLL);
|
||||
}
|
||||
@ -465,29 +603,212 @@ void ClearGamedllList()
|
||||
gamedll_list.clear();
|
||||
}
|
||||
|
||||
void DLLShutdown_handler()
|
||||
void UnloadMetamod(bool shutting_down)
|
||||
{
|
||||
/* Unload plugins */
|
||||
g_PluginMngr.UnloadAll();
|
||||
|
||||
if (shutting_down)
|
||||
{
|
||||
/* Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly */
|
||||
g_SMConVarAccessor.MarkCommandsAsGameDLL();
|
||||
g_SMConVarAccessor.UnregisterGameDLLCommands();
|
||||
g_Engine.icvar->UnlinkVariables(FCVAR_GAMEDLL);
|
||||
|
||||
SH_CALL(g_GameDllPatch, &IServerGameDLL::DLLShutdown)();
|
||||
}
|
||||
|
||||
SH_RELEASE_CALLCLASS(g_GameDllPatch);
|
||||
SH_RELEASE_CALLCLASS(g_CvarPatch);
|
||||
g_GameDllPatch = NULL;
|
||||
g_CvarPatch = NULL;
|
||||
|
||||
g_SourceHook.CompleteShutdown();
|
||||
|
||||
if (g_GameDll.lib && g_GameDll.loaded)
|
||||
{
|
||||
dlclose(g_GameDll.lib);
|
||||
}
|
||||
memset(&g_GameDll, 0, sizeof(GameDllInfo));
|
||||
}
|
||||
|
||||
void DLLShutdown_handler()
|
||||
{
|
||||
UnloadMetamod(true);
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
|
||||
void LoadFromVDF(const char *file)
|
||||
{
|
||||
PluginId id;
|
||||
bool already, kvfileLoaded;
|
||||
KeyValues *pValues;
|
||||
const char *plugin_file, *alias;
|
||||
char full_path[256], error[256];
|
||||
|
||||
pValues = new KeyValues("Metamod Plugin");
|
||||
|
||||
if (g_Engine.original)
|
||||
{
|
||||
/* The Ship must use a special version of this function */
|
||||
kvfileLoaded = KVLoadFromFile(pValues, baseFs, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
kvfileLoaded = pValues->LoadFromFile(baseFs, file);
|
||||
}
|
||||
|
||||
if (!kvfileLoaded)
|
||||
{
|
||||
pValues->deleteThis();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((plugin_file = pValues->GetString("file", NULL)) == NULL)
|
||||
{
|
||||
pValues->deleteThis();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((alias = pValues->GetString("alias", NULL)) != NULL)
|
||||
{
|
||||
g_PluginMngr.SetAlias(alias, plugin_file);
|
||||
}
|
||||
|
||||
/* Attempt to find a file extension */
|
||||
if (UTIL_GetExtension(plugin_file) == NULL)
|
||||
{
|
||||
g_SmmAPI.PathFormat(full_path,
|
||||
sizeof(full_path),
|
||||
"%s/%s%s",
|
||||
g_ModPath.c_str(),
|
||||
plugin_file,
|
||||
#if defined WIN32 || defined _WIN32
|
||||
".dll"
|
||||
#else
|
||||
"_i486.so"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_SmmAPI.PathFormat(full_path,
|
||||
sizeof(full_path),
|
||||
"%s/%s",
|
||||
g_ModPath.c_str(),
|
||||
plugin_file);
|
||||
}
|
||||
|
||||
id = g_PluginMngr.Load(full_path, Pl_File, already, error, sizeof(error));
|
||||
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
|
||||
{
|
||||
LogMessage("[META] Failed to load plugin %s: %s", plugin_file, error);
|
||||
}
|
||||
|
||||
pValues->deleteThis();
|
||||
}
|
||||
|
||||
void LookForVDFs(const char *dir)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
int extidx;
|
||||
|
||||
#if defined _MSC_VER
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA fd;
|
||||
char error[255];
|
||||
|
||||
g_SmmAPI.PathFormat(path, sizeof(path), "%s\\*.*", dir);
|
||||
if ((hFind = FindFirstFile(path, &fd)) == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD dw = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
error,
|
||||
sizeof(error),
|
||||
NULL);
|
||||
LogMessage("[META] Could not open folder \"%s\" (%s)", dir, error);
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (strcmp(fd.cFileName, ".") == 0
|
||||
|| strcmp(fd.cFileName, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
extidx = strlen(fd.cFileName) - 4;
|
||||
if (extidx < 0 || stricmp(&fd.cFileName[extidx], ".vdf"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
g_SmmAPI.PathFormat(path, sizeof(path), "%s\\%s", dir, fd.cFileName);
|
||||
LoadFromVDF(path);
|
||||
} while (FindNextFile(hFind, &fd));
|
||||
|
||||
FindClose(hFind);
|
||||
#else
|
||||
DIR *pDir;
|
||||
struct dirent *pEnt;
|
||||
|
||||
if ((pDir = opendir(dir)) == NULL)
|
||||
{
|
||||
LogMessage("[META] Could not open folder \"%s\" (%s)", dir, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
while ((pEnt = readdir(pDir)) != NULL)
|
||||
{
|
||||
if (strcmp(pEnt->d_name, ".") == 0
|
||||
|| strcmp(pEnt->d_name, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
extidx = strlen(pEnt->d_name) - 4;
|
||||
if (extidx < 0 || stricmp(&pEnt->d_name[extidx], ".vdf"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
g_SmmAPI.PathFormat(path, sizeof(path), "%s/%s", dir, pEnt->d_name);
|
||||
LoadFromVDF(path);
|
||||
}
|
||||
|
||||
closedir(pDir);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID)
|
||||
{
|
||||
Assert(filesystem);
|
||||
#ifdef _MSC_VER
|
||||
Assert(_heapchk() == _HEAPOK);
|
||||
#endif
|
||||
|
||||
FileHandle_t f = filesystem->Open(resourceName, "rb", pathID);
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
// load file into a null-terminated buffer
|
||||
int fileSize = filesystem->Size(f);
|
||||
char *buffer = (char *)MemAllocScratch(fileSize + 1);
|
||||
|
||||
Assert(buffer);
|
||||
|
||||
filesystem->Read(buffer, fileSize, f); // read into local buffer
|
||||
|
||||
buffer[fileSize] = 0; // null terminate file as EOF
|
||||
|
||||
filesystem->Close( f ); // close file after reading
|
||||
|
||||
bool retOK = kv->LoadFromBuffer( resourceName, buffer, filesystem );
|
||||
|
||||
MemFreeScratch();
|
||||
|
||||
return retOK;
|
||||
}
|
||||
|
||||
int LoadPluginsFromFile(const char *_file)
|
||||
{
|
||||
FILE *fp;
|
||||
@ -505,21 +826,22 @@ int LoadPluginsFromFile(const char *_file)
|
||||
char buffer[255], error[255], full_path[255];
|
||||
const char *ptr, *ext, *file;
|
||||
size_t length;
|
||||
while (!feof(fp))
|
||||
while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL)
|
||||
{
|
||||
buffer[0] = '\0';
|
||||
fgets(buffer, sizeof(buffer), fp);
|
||||
length = strlen(buffer);
|
||||
if (!length)
|
||||
continue;
|
||||
if (buffer[length-1] == '\n')
|
||||
buffer[--length] = '\0';
|
||||
|
||||
UTIL_TrimLeft(buffer);
|
||||
UTIL_TrimRight(buffer);
|
||||
|
||||
if (buffer[0] == '\0' || buffer[0] == ';' || strncmp(buffer, "//", 2) == 0)
|
||||
length = strlen(buffer);
|
||||
if (!length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buffer[0] == '\0' || buffer[0] == ';' || strncmp(buffer, "//", 2) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
file = buffer;
|
||||
if (buffer[0] == '"')
|
||||
{
|
||||
@ -535,7 +857,9 @@ int LoadPluginsFromFile(const char *_file)
|
||||
}
|
||||
cptr++;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char *cptr = buffer;
|
||||
while (*cptr)
|
||||
{
|
||||
@ -543,7 +867,9 @@ int LoadPluginsFromFile(const char *_file)
|
||||
{
|
||||
char *optr = cptr;
|
||||
while (*cptr && isspace(*cptr))
|
||||
{
|
||||
cptr++;
|
||||
}
|
||||
*optr = '\0';
|
||||
UTIL_TrimRight(cptr);
|
||||
if (*cptr && isalpha(*cptr))
|
||||
@ -568,13 +894,21 @@ int LoadPluginsFromFile(const char *_file)
|
||||
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
|
||||
{
|
||||
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
|
||||
} else {
|
||||
if (already)
|
||||
skipped++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (already)
|
||||
{
|
||||
skipped++;
|
||||
}
|
||||
else
|
||||
{
|
||||
total++;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Attempt to find a file extension */
|
||||
ptr = UTIL_GetExtension(file);
|
||||
/* Add an extension if there's none there */
|
||||
@ -585,7 +919,9 @@ int LoadPluginsFromFile(const char *_file)
|
||||
#else
|
||||
ext = "_i486.so";
|
||||
#endif
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ext = "";
|
||||
}
|
||||
/* Format the new path */
|
||||
@ -594,26 +930,35 @@ int LoadPluginsFromFile(const char *_file)
|
||||
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
|
||||
{
|
||||
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
|
||||
} else {
|
||||
if (already)
|
||||
skipped++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (already)
|
||||
{
|
||||
skipped++;
|
||||
}
|
||||
else
|
||||
{
|
||||
total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (skipped)
|
||||
{
|
||||
LogMessage("[META] Loaded %d plugins from file (%d already loaded)", total, skipped);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
LogMessage("[META] Loaded %d plugins from file.", total);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
/* Wrapper function. This is called when the GameDLL thinks it's using
|
||||
* the engine's real engineFactory.
|
||||
*/
|
||||
@ -663,13 +1008,20 @@ void LevelShutdown_handler(void)
|
||||
if (!bInFirstLevel)
|
||||
{
|
||||
char full_path[255];
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile());
|
||||
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile());
|
||||
LoadPluginsFromFile(full_path);
|
||||
} else {
|
||||
|
||||
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetMetamodBaseDir());
|
||||
LookForVDFs(full_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
bInFirstLevel = false;
|
||||
}
|
||||
|
||||
g_bLevelChanged = true;
|
||||
|
||||
ITER_EVENT(OnLevelShutdown, ());
|
||||
|
||||
RETURN_META(MRES_IGNORED);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -74,11 +74,12 @@ struct GameDllInfo
|
||||
/** @brief Stores information about the HL2 Engine pointers */
|
||||
struct EngineInfo
|
||||
{
|
||||
EngineInfo() : loaded(false),
|
||||
EngineInfo() : loaded(false), original(false),
|
||||
engineFactory(NULL), physicsFactory(NULL), fileSystemFactory(NULL),
|
||||
pGlobals(NULL), icvar(NULL), engine(NULL)
|
||||
{ };
|
||||
bool loaded;
|
||||
bool original;
|
||||
CreateInterfaceFn engineFactory;
|
||||
CreateInterfaceFn physicsFactory;
|
||||
CreateInterfaceFn fileSystemFactory;
|
||||
@ -87,6 +88,8 @@ struct EngineInfo
|
||||
IVEngineServer *engine;
|
||||
};
|
||||
|
||||
bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn serverFactory);
|
||||
|
||||
/** @brief Global variable for GameDLL info */
|
||||
extern GameDllInfo g_GameDll;
|
||||
|
||||
@ -115,8 +118,14 @@ extern PluginId g_PLID;
|
||||
extern int g_GameDllVersion;
|
||||
|
||||
extern bool bGameInit;
|
||||
extern bool g_bLevelChanged;
|
||||
|
||||
void UnloadMetamod(bool shutting_down);
|
||||
|
||||
/** @brief Global CallClass for IServerGameDLL */
|
||||
extern SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
|
||||
|
||||
/** @brief Global CallClass for ICvar */
|
||||
extern SourceHook::CallClass<ICvar> *g_CvarPatch;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMM_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
The software is Copyright (C) 2004-2007, Metamod:Source Development Team.
|
||||
The software is Copyright (C) 2004-2008, Metamod:Source Development Team.
|
||||
|
||||
Metamod:Source is distributed under the "zLib/libpng" license, which is reproduced
|
||||
below:
|
||||
|
@ -1,4 +1,4 @@
|
||||
#(C)2004-2007 SourceMM Development Team
|
||||
#(C)2004-2008 SourceMM Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
HL2SDK = ../../../hl2sdk
|
||||
|
@ -41,6 +41,7 @@
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=""$(SOURCEMM14)";"$(SOURCEMM14)\sourcemm";"$(SOURCEMM14)\sourcehook";"$(HL2SDK)\public";"$(HL2SDK)\public\dlls";"$(HL2SDK)\public\engine";"$(HL2SDK)\public\tier0";"$(HL2SDK)\public\tier1";"$(HL2SDK)\public\vstdlib""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
@ -62,7 +63,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib"
|
||||
AdditionalDependencies=""$(HL2SDK)\lib\public\tier0.lib""
|
||||
ShowProgress="0"
|
||||
OutputFile="$(OutDir)/stub_mm.dll"
|
||||
LinkIncremental="2"
|
||||
@ -123,6 +124,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""$(SOURCEMM14)";"$(SOURCEMM14)\sourcemm";"$(SOURCEMM14)\sourcehook";"$(HL2SDK)\public";"$(HL2SDK)\public\dlls";"$(HL2SDK)\public\engine";"$(HL2SDK)\public\tier0";"$(HL2SDK)\public\tier1";"$(HL2SDK)\public\vstdlib""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS"
|
||||
RuntimeLibrary="0"
|
||||
RuntimeTypeInfo="false"
|
||||
@ -142,7 +144,7 @@
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="tier0.lib"
|
||||
AdditionalDependencies=""$(HL2SDK)\lib\public\tier0.lib""
|
||||
OutputFile="$(OutDir)/stub_mm.dll"
|
||||
LinkIncremental="1"
|
||||
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== stub_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== stub_mm ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
|
@ -3,11 +3,11 @@
|
||||
#ifndef _INCLUDE_SVN_VERSION_H_
|
||||
#define _INCLUDE_SVN_VERSION_H_
|
||||
|
||||
#define SVN_PRODUCT_VERSION "1.4.0"
|
||||
#define SVN_PRODUCT_VERSION "1.4.4"
|
||||
|
||||
#define SVN_REVISION 346
|
||||
#define SVN_REVISION_STRING "346"
|
||||
#define SVN_FILE_VERSION 1,4,0,346
|
||||
#define SVN_FILE_VERSION_STRING "1.4.0.346"
|
||||
#define SVN_REVISION 705
|
||||
#define SVN_REVISION_STRING "705"
|
||||
#define SVN_FILE_VERSION 1,4,4,705
|
||||
#define SVN_FILE_VERSION_STRING "1.4.4.705"
|
||||
|
||||
#endif //_INCLUDE_SVN_VERSION_H_
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -239,3 +239,186 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
inline bool pathchar_isalpha(char a)
|
||||
{
|
||||
return (((a & 1<<7) == 0) && isalpha(a));
|
||||
}
|
||||
|
||||
inline bool pathchar_sep(char a)
|
||||
{
|
||||
#if defined WIN32
|
||||
return (a == '/' || a == '\\');
|
||||
#elif defined __linux__
|
||||
return (a == '/');
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool pathstr_isabsolute(const char *str)
|
||||
{
|
||||
#if defined WIN32
|
||||
return (pathchar_isalpha(str[0])
|
||||
&& str[1] == ':'
|
||||
&& pathchar_sep(str[2]));
|
||||
#elif defined __linux__
|
||||
return (str[0] == '/');
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool pathchar_cmp(char a, char b)
|
||||
{
|
||||
#if defined WIN32
|
||||
if (pathchar_isalpha(a) && pathchar_isalpha(b))
|
||||
{
|
||||
return (tolower(a) == tolower(b));
|
||||
}
|
||||
/* Either path separator is acceptable */
|
||||
if (pathchar_sep(a))
|
||||
{
|
||||
return pathchar_sep(b);
|
||||
}
|
||||
#endif
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Forms a relative path given two absolute paths.
|
||||
*
|
||||
* @param buffer Buffer to store relative path in.
|
||||
* @param maxlength Maximum length of the output buffer.
|
||||
* @param relTo Destination folder to use as a working directory.
|
||||
* Final folder name should not be pathchar-terminated.
|
||||
* @param relFrom Source file or folder to use as a target.
|
||||
* @return True on success, false on failure.
|
||||
*/
|
||||
bool UTIL_Relatize(char buffer[],
|
||||
size_t maxlength,
|
||||
const char *relTo,
|
||||
const char *relFrom)
|
||||
{
|
||||
/* We don't allow relative paths in here, force
|
||||
* the user to resolve these himself!
|
||||
*/
|
||||
if (!pathstr_isabsolute(relTo)
|
||||
|| !pathstr_isabsolute(relFrom))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined WIN32
|
||||
/* Relative paths across drives are not possible */
|
||||
if (!pathchar_cmp(relTo[0], relFrom[0]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/* Get rid of the drive and semicolon part */
|
||||
relTo = &relTo[2];
|
||||
relFrom = &relFrom[2];
|
||||
#endif
|
||||
|
||||
/* Eliminate the common root between the paths */
|
||||
const char *rootTo = NULL;
|
||||
const char *rootFrom = NULL;
|
||||
while (*relTo != '\0' && *relFrom != '\0')
|
||||
{
|
||||
/* If we get to a new path sequence, start over */
|
||||
if (pathchar_sep(*relTo)
|
||||
&& pathchar_sep(*relFrom))
|
||||
{
|
||||
rootTo = relTo;
|
||||
rootFrom = relFrom;
|
||||
/* If the paths don't compare, stop looking for a common root */
|
||||
} else if (!pathchar_cmp(*relTo, *relFrom)) {
|
||||
break;
|
||||
}
|
||||
relTo++;
|
||||
relFrom++;
|
||||
}
|
||||
|
||||
/* NULLs shouldn't happen! */
|
||||
if (rootTo == NULL
|
||||
|| rootFrom == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t numLevels = 0;
|
||||
|
||||
/* The root case is special!
|
||||
* Don't count anything from it.
|
||||
*/
|
||||
if (*(rootTo + 1) != '\0')
|
||||
{
|
||||
/* Search for how many levels we need to go up.
|
||||
* Since the root pointer points to a '/', we increment
|
||||
* the initial pointer by one.
|
||||
*/
|
||||
while (*rootTo != '\0')
|
||||
{
|
||||
if (pathchar_sep(*rootTo))
|
||||
{
|
||||
/* Check for an improper trailing slash,
|
||||
* just to be nice even though the user
|
||||
* should NOT have done this!
|
||||
*/
|
||||
if (*(rootTo + 1) == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
numLevels++;
|
||||
}
|
||||
rootTo++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now build the new relative path. */
|
||||
size_t len, total = 0;
|
||||
while (numLevels--)
|
||||
{
|
||||
len = _snprintf(&buffer[total], maxlength - total, ".." PATH_SEP_STR);
|
||||
if (len >= maxlength - total)
|
||||
{
|
||||
/* Not enough space in the buffer */
|
||||
return false;
|
||||
}
|
||||
total += len;
|
||||
}
|
||||
|
||||
/* Add the absolute path. */
|
||||
len = _snprintf(&buffer[total], maxlength - total, "%s", &rootFrom[1]);
|
||||
if (len >= maxlength - total)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params)
|
||||
{
|
||||
size_t len = vsnprintf(buffer, maxlength, fmt, params);
|
||||
|
||||
if (len >= maxlength)
|
||||
{
|
||||
len = maxlength - 1;
|
||||
buffer[len] = '\0';
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool UTIL_VerifySignature(const void *addr, const char *sig, size_t len)
|
||||
{
|
||||
unsigned char *addr1 = (unsigned char *) addr;
|
||||
unsigned char *addr2 = (unsigned char *) sig;
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
if (addr2[i] == '*')
|
||||
continue;
|
||||
if (addr1[i] != addr2[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -12,12 +12,15 @@
|
||||
#define _INCLUDE_UTIL_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <sourcehook/sourcehook.h>
|
||||
|
||||
/**
|
||||
* @brief Utility functions
|
||||
* @file util.h
|
||||
*/
|
||||
|
||||
#define IA32_JMP_IMM32 '\xE9'
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the extension in a file name.
|
||||
*/
|
||||
@ -56,17 +59,72 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
|
||||
/**
|
||||
* @brief Same as vsnprintf except that it ensures the string buffer is null terminated.
|
||||
*/
|
||||
inline size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params)
|
||||
{
|
||||
size_t len = vsnprintf(buffer, maxlength, fmt, params);
|
||||
size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params);
|
||||
|
||||
if (len >= maxlength)
|
||||
/**
|
||||
* @brief Forms a relative path given two absolute paths.
|
||||
*
|
||||
* @param buffer Buffer to store relative path in.
|
||||
* @param maxlength Maximum length of the output buffer.
|
||||
* @param relTo Destination folder to use as a working directory.
|
||||
* Final folder name should not be pathchar-terminated.
|
||||
* @param relFrom Source file or folder to use as a target.
|
||||
* @return True on success, false on failure.
|
||||
*/
|
||||
bool UTIL_Relatize(char buffer[],
|
||||
size_t maxlength,
|
||||
const char *relTo,
|
||||
const char *relFrom);
|
||||
|
||||
/**
|
||||
* @brief Compares memory address against a signature.
|
||||
*
|
||||
* @param addr Memory address to check.
|
||||
* @param sig Signature used to check against memory address. Accept 0x2A as wildcard.
|
||||
* @param len Length of signature.
|
||||
* @return True if signature was verified, false otherwise.
|
||||
*/
|
||||
bool UTIL_VerifySignature(const void *addr, const char *sig, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Returns the original function address of a given virtual function.
|
||||
*
|
||||
* @param mfp Member function pointer to virtual function.
|
||||
* @param ptr Pointer to interface in which the virtual function belongs.
|
||||
* @param cls A CallClass for the interface in which the virtual function belongs.
|
||||
* @return Address of function originally pointed to by the virtual function.
|
||||
*/
|
||||
template <class MFP, class Iface>
|
||||
char *UTIL_GetOrigFunction(MFP vfunc, Iface *ptr, SourceHook::CallClass<Iface> *cls)
|
||||
{
|
||||
len = maxlength - 1;
|
||||
buffer[len] = '\0';
|
||||
SourceHook::MemFuncInfo info = {true, -1, 0, 0};
|
||||
SourceHook::GetFuncInfo(vfunc, info);
|
||||
|
||||
/* Get address of original GetUserMessageInfo() */
|
||||
char *func = reinterpret_cast<char *>(cls->GetOrigFunc(info.vtbloffs, info.vtblindex));
|
||||
|
||||
/* If we can't get original function, that means there's no hook */
|
||||
if (func == NULL)
|
||||
{
|
||||
/* Get virtual function address 'manually' then */
|
||||
char *adjustedptr = reinterpret_cast<char *>(ptr) + info.vtbloffs + info.vtbloffs;
|
||||
char **vtable = *reinterpret_cast<char ***>(adjustedptr);
|
||||
|
||||
func = vtable[info.vtblindex];
|
||||
}
|
||||
|
||||
return len;
|
||||
/* Check for relative jumps */
|
||||
if (func[0] == IA32_JMP_IMM32)
|
||||
{
|
||||
/* Get address from displacement...
|
||||
*
|
||||
* Add 5 because it's relative to next instruction:
|
||||
* Opcode <1 byte> + 32-bit displacement <4 bytes>
|
||||
*/
|
||||
func += *reinterpret_cast<unsigned long *>(func + 1) + 5;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
#endif //_INCLUDE_UTIL_H
|
||||
|
@ -47,7 +47,7 @@ BEGIN
|
||||
VALUE "FileDescription", "Metamod: Source"
|
||||
VALUE "FileVersion", SVN_FILE_VERSION_STRING
|
||||
VALUE "InternalName", "sourcemm"
|
||||
VALUE "LegalCopyright", "Copyright (c) 2004-2007, Metamod: Source Development Team"
|
||||
VALUE "LegalCopyright", "Copyright (c) 2004-2008, Metamod: Source Development Team"
|
||||
VALUE "OriginalFilename", "server.dll"
|
||||
VALUE "ProductName", "Metamod: Source"
|
||||
VALUE "ProductVersion", SVN_PRODUCT_VERSION
|
||||
@ -99,3 +99,4 @@ END
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -10,15 +10,31 @@
|
||||
|
||||
#include "vsp_listener.h"
|
||||
#include "CPlugin.h"
|
||||
#include "concommands.h"
|
||||
|
||||
SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
||||
|
||||
using namespace SourceMM;
|
||||
|
||||
VSPListener g_VspListener;
|
||||
ConCommand *g_plugin_unload = NULL;
|
||||
bool g_bIsTryingToUnload;
|
||||
|
||||
void InterceptPluginUnloads()
|
||||
{
|
||||
g_bIsTryingToUnload = true;
|
||||
}
|
||||
|
||||
void InterceptPluginUnloads_Post()
|
||||
{
|
||||
g_bIsTryingToUnload = false;
|
||||
}
|
||||
|
||||
VSPListener::VSPListener()
|
||||
{
|
||||
m_Loaded = false;
|
||||
m_Loadable = false;
|
||||
m_bIsRootLoadMethod = false;
|
||||
}
|
||||
|
||||
void VSPListener::ClientActive(edict_t *pEntity)
|
||||
@ -92,6 +108,25 @@ void VSPListener::ServerActivate(edict_t *pEdictList, int edictCount, int client
|
||||
|
||||
void VSPListener::Unload()
|
||||
{
|
||||
if (g_bIsTryingToUnload)
|
||||
{
|
||||
Error("Metamod:Source cannot be unloaded from VSP mode. Use \"meta unload\" to unload specific plugins.\n");
|
||||
return;
|
||||
}
|
||||
if (IsRootLoadMethod())
|
||||
{
|
||||
if (g_plugin_unload != NULL)
|
||||
{
|
||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_plugin_unload, InterceptPluginUnloads, false);
|
||||
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_plugin_unload, InterceptPluginUnloads_Post, true);
|
||||
g_plugin_unload = NULL;
|
||||
}
|
||||
g_SMConVarAccessor.UnloadMetamodCommands();
|
||||
UnloadMetamod(false);
|
||||
}
|
||||
m_Loadable = true;
|
||||
m_Loaded = false;
|
||||
m_bIsRootLoadMethod = false;
|
||||
}
|
||||
|
||||
void VSPListener::SetLoadable(bool set)
|
||||
@ -99,53 +134,60 @@ void VSPListener::SetLoadable(bool set)
|
||||
m_Loadable = set;
|
||||
}
|
||||
|
||||
bool VSPListener::IsRootLoadMethod()
|
||||
{
|
||||
return m_bIsRootLoadMethod;
|
||||
}
|
||||
|
||||
bool VSPListener::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory)
|
||||
{
|
||||
if (!g_GameDll.loaded)
|
||||
{
|
||||
Error("Metamod:Source is not a Valve Server Plugin\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_Loadable)
|
||||
{
|
||||
Warning("Do not manually load Metamod:Source as a Valve Server Plugin\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_Loaded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_Loadable && !g_GameDll.loaded)
|
||||
{
|
||||
/* New loading mechanism, do a bunch o' stuff! */
|
||||
m_bIsRootLoadMethod = true;
|
||||
m_Loaded = true;
|
||||
SetLoadable(false);
|
||||
if (!AlternatelyLoadMetamod(interfaceFactory, gameServerFactory))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ConCommandBase *pBase = g_Engine.icvar->GetCommands();
|
||||
while (pBase != NULL)
|
||||
{
|
||||
if (pBase->IsCommand() && strcmp(pBase->GetName(), "plugin_unload") == 0)
|
||||
{
|
||||
g_plugin_unload = (ConCommand *)pBase;
|
||||
break;
|
||||
}
|
||||
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
|
||||
}
|
||||
|
||||
if (g_plugin_unload != NULL)
|
||||
{
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_plugin_unload, InterceptPluginUnloads, false);
|
||||
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_plugin_unload, InterceptPluginUnloads_Post, true);
|
||||
}
|
||||
|
||||
/* Ho ho ho... if we get here, set a new cvar version. */
|
||||
extern ConVar metamod_version;
|
||||
char buffer[255];
|
||||
|
||||
UTIL_Format(buffer, sizeof(buffer), "%sV", metamod_version.GetString());
|
||||
metamod_version.SetValue(buffer);
|
||||
}
|
||||
|
||||
m_Loaded = true;
|
||||
SetLoadable(false);
|
||||
|
||||
PluginIter iter;
|
||||
CPluginManager::CPlugin *pPlugin;
|
||||
SourceHook::List<IMetamodListener *>::iterator event;
|
||||
IMetamodListener *pML;
|
||||
for (iter=g_PluginMngr._begin(); iter!=g_PluginMngr._end(); iter++)
|
||||
if (!m_bIsRootLoadMethod)
|
||||
{
|
||||
pPlugin = (*iter);
|
||||
if (pPlugin->m_Status < Pl_Paused)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* Only valid for plugins >= 10 (v1:5, SourceMM 1.4) */
|
||||
if (pPlugin->m_API->GetApiVersion() < 10)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (event=pPlugin->m_Events.begin();
|
||||
event!=pPlugin->m_Events.end();
|
||||
event++)
|
||||
{
|
||||
pML = (*event);
|
||||
pML->OnVSPListening(this);
|
||||
}
|
||||
g_PluginMngr.SetVSPAsLoaded();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* ======== SourceMM ========
|
||||
* Copyright (C) 2004-2007 Metamod:Source Development Team
|
||||
* Copyright (C) 2004-2008 Metamod:Source Development Team
|
||||
* No warranties of any kind
|
||||
*
|
||||
* License: zlib/libpng
|
||||
@ -39,9 +39,11 @@ public:
|
||||
public:
|
||||
bool IsLoaded();
|
||||
void SetLoadable(bool loadable);
|
||||
bool IsRootLoadMethod();
|
||||
private:
|
||||
bool m_Loaded;
|
||||
bool m_Loadable;
|
||||
bool m_bIsRootLoadMethod;
|
||||
};
|
||||
|
||||
extern VSPListener g_VspListener;
|
||||
|
@ -1,68 +0,0 @@
|
||||
#(C)2004-2007 SourceMM Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
HL2SDK = ../../hl2sdk
|
||||
SMM_ROOT = ..
|
||||
SRCDS = ~/srcds
|
||||
|
||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||
|
||||
OPT_FLAGS = -O2 -funroll-loops -s -pipe
|
||||
GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden
|
||||
DEBUG_FLAGS = -g -ggdb3
|
||||
CPP = gcc-4.1
|
||||
BINARY = sourcemm_update_tool_i486.so
|
||||
|
||||
HL2PUB = $(HL2SDK)/public
|
||||
HL2LIB = $(HL2SDK)/linux_sdk
|
||||
|
||||
OBJECTS = update_tool.cpp
|
||||
|
||||
LINK = vstdlib_i486.so tier0_i486.so -static-libgcc
|
||||
|
||||
INCLUDE = -I. -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
|
||||
-I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_ROOT) -I$(SMM_ROOT)/sourcehook
|
||||
|
||||
ifeq "$(DEBUG)" "true"
|
||||
BIN_DIR = Debug
|
||||
CFLAGS = $(DEBUG_FLAGS)
|
||||
else
|
||||
BIN_DIR = Release
|
||||
CFLAGS = $(OPT_FLAGS)
|
||||
endif
|
||||
|
||||
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
|
||||
|
||||
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
|
||||
|
||||
ifeq "$(GCC_VERSION)" "4"
|
||||
CFLAGS += $(GCC4_FLAGS)
|
||||
endif
|
||||
|
||||
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
|
||||
|
||||
$(BIN_DIR)/%.o: %.cpp
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
all:
|
||||
mkdir -p $(BIN_DIR)
|
||||
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
|
||||
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
|
||||
nasm api_link.asm -f elf -o $(BIN_DIR)/api_link.o -DLINUX
|
||||
$(MAKE) sourcemm
|
||||
rm -rf $(BINARY)
|
||||
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
|
||||
|
||||
sourcemm: $(OBJ_LINUX)
|
||||
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(BIN_DIR)/api_link.o $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
|
||||
|
||||
debug:
|
||||
$(MAKE) all DEBUG=true
|
||||
|
||||
default: all
|
||||
|
||||
clean:
|
||||
rm -rf Release/*.o
|
||||
rm -rf Release/$(BINARY)
|
||||
rm -rf Debug/*.o
|
||||
rm -rf Debug/$(BINARY)
|
@ -1,90 +0,0 @@
|
||||
This is the README file for sourcemm_update_tool.
|
||||
|
||||
This tool will automatically correct gameinfo.txt when your server gets updated, and Valve's updater overwrites Metamod:Source's changes. This tool is experimental, and is thus a separate download for now.
|
||||
|
||||
1. INSTALLATION
|
||||
|
||||
a. Extract the entire package to your mod folder. The structure should look like:
|
||||
|
||||
<mod>/addons/metamod/bin/sourcemm_update_tool.dll
|
||||
<mod>/addons/metamod/bin/sourcemm_update_tool_i486.so
|
||||
<mod>/addons/metamod/README.txt
|
||||
<mod>/addons/sourcemm_update_tool.vdf
|
||||
<mod>/sourcemm_updater.conf
|
||||
|
||||
b. Open <mod>/sourcemm_updater.conf with your favorite text editor. Change the
|
||||
"cstrike" folder to match your mod folder.
|
||||
|
||||
2. CONFIGURATION
|
||||
|
||||
The sourcemm_updater.conf file has two configuration options.
|
||||
|
||||
mmpath - Set this to the path Metamod:Source is located in.
|
||||
This defaults to addons/metamod/bin
|
||||
restart - Set this to how the server should be restarted when
|
||||
gameinfo.txt is patched. There are three options:
|
||||
|
||||
quit - Execute "quit" in the console. Currently does not work.
|
||||
never - Do not restart.
|
||||
error - Generate an error message. Because of a bug in SourceDS,
|
||||
this will generate a crash dump on Windows, but the server
|
||||
will successfully quit.
|
||||
|
||||
3. USAGE
|
||||
|
||||
You do not need to do anything to use the updater tool. When your server starts,
|
||||
it silently checks to see if Metamod:Source is loaded. If not, it will make sure
|
||||
gameinfo.txt is correctly set. Then, depending on how it's configured, it will
|
||||
kill the server. Most game server provides have auto-restart functionality on their
|
||||
servers; if not, you will need to manually restart the server.
|
||||
|
||||
The update tool unloads itself immediately after the server starts, so it will not
|
||||
use any resources, and will not display when you type 'plugin_print'.
|
||||
|
||||
4. TROUBLESHOOTING
|
||||
|
||||
This tool is currently experimental. There are two possible problems. For
|
||||
any issue you encounter, you should post a report here:
|
||||
|
||||
http://bugs.alliedmods.net/index.php?project=4
|
||||
|
||||
a. The updater tool does not patch gameinfo.txt
|
||||
|
||||
Verify that the tool is loading. You can do this by opening up the
|
||||
sourcemm_update_tool.vdf file and copying its file path. Then, enter
|
||||
the following command in your server console:
|
||||
|
||||
plugin_load <path>
|
||||
|
||||
Example:
|
||||
|
||||
plugin_load cstrike\addons\metamod\bin\sourcemm_update_tool
|
||||
|
||||
If you get the following reply:
|
||||
|
||||
Failed to load plugin "cstrike\addons\sourcemm_update_tool"
|
||||
Unable to load plugin "cstrike\addons\sourcemm_update_tool"
|
||||
|
||||
Then the tool is working, and you should post a bug report. If instead,
|
||||
you get:
|
||||
|
||||
Unable to load plugin "cstrike\addons\sourcemm_update_tool"
|
||||
Unable to load plugin "cstrike\addons\sourcemm_update_tool"
|
||||
|
||||
Then the tool is not loading properly, and the path you are trying to use
|
||||
is not correct.
|
||||
|
||||
b. The server always dies, and you can't start it at all
|
||||
|
||||
The updater tool is either crashing or not repairing Metamod:Source
|
||||
correctly. First, try changing the 'restart' line in sourcemm_updater.conf
|
||||
to the following line:
|
||||
|
||||
restart = never
|
||||
|
||||
If that does not fix the problem, remove the .vdf file so the updater tool
|
||||
will not be loaded.
|
||||
|
||||
In either case, you should post a bug report containing your mod name and
|
||||
your gameinfo.txt as an attachment.
|
||||
|
@ -1,138 +0,0 @@
|
||||
;;;;
|
||||
;; (C)2005-2007 AlliedModders LLC
|
||||
;; By the Metamod:Source Development Team
|
||||
;; This software is licensed under the zlib/libpng free software license.
|
||||
;;
|
||||
;; This assembly file is a short thunk wrapper to let us load as a VSP and exit quietly,
|
||||
;; without any overhead of the rest of the interface, and also to prevent linking against
|
||||
;; tierX or vstdlib
|
||||
;;;;
|
||||
|
||||
;;Exports:
|
||||
;; void GetBaseDir(char *buffer, maxlength);
|
||||
;; void *GetThisPointer();
|
||||
;;Imports:
|
||||
;; void LoadFunction();
|
||||
|
||||
section .text
|
||||
|
||||
global GetThisPointer, GetGameDir, ServerCommand
|
||||
global _GetThisPointer, _GetGameDir, _ServerCommand
|
||||
global _GetICvar, GetICvar
|
||||
extern _LoadFunction
|
||||
|
||||
GetICvar:
|
||||
_GetICvar:
|
||||
mov eax, [icvar]
|
||||
ret
|
||||
|
||||
GetThisPointer:
|
||||
_GetThisPointer:
|
||||
mov eax, GLOBAL_POINTER
|
||||
ret
|
||||
|
||||
GetGameDir:
|
||||
_GetGameDir:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
mov ecx, [engine] ;get this pointer
|
||||
mov edx, [ecx] ;get the vtable
|
||||
push dword [ebp+12] ;push maxlenth
|
||||
push dword [ebp+8] ;push buffer
|
||||
%ifdef LINUX
|
||||
push ecx ;push this pointer
|
||||
%endif
|
||||
call dword [edx+216] ;call IVEngineServer::GetGameDir
|
||||
%ifdef LINUX
|
||||
add esp, 12 ;correct stack
|
||||
%endif
|
||||
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
ServerCommand
|
||||
_ServerCommand:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
mov ecx, [engine] ;get this pointer
|
||||
mov edx, [ecx] ;get the vtable
|
||||
push dword [ebp+8] ;push string
|
||||
%ifdef LINUX
|
||||
push ecx ;push this pointer
|
||||
%endif
|
||||
call dword [edx+144] ;call IVEngineServer::ServerCommand
|
||||
%ifdef LINUX
|
||||
add esp, 8 ;correct stack
|
||||
%endif
|
||||
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
thisLoadFunction:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
push edi
|
||||
|
||||
;get factory
|
||||
%ifdef LINUX
|
||||
mov edi, [ebp+12]
|
||||
%else
|
||||
mov edi, [ebp+8]
|
||||
%endif
|
||||
|
||||
push dword 0 ;NULL
|
||||
push dword VENGINESERVER ;iface name
|
||||
call edi ;call factory
|
||||
add esp, 8 ;correct stack
|
||||
|
||||
test eax, eax ;do we have a valid pointer?
|
||||
jz .end ;no, bail out
|
||||
|
||||
mov [engine], eax ;store the engine pointer
|
||||
|
||||
push dword 0 ;NULL
|
||||
push dword VENGINECVAR ;iface name
|
||||
call edi ;call factory
|
||||
add esp, 8 ;correct stack
|
||||
|
||||
test eax, eax ;do we have a valid pointer?
|
||||
jz .end ;no, bail out
|
||||
|
||||
mov [icvar], eax ;store the icvar pointer
|
||||
|
||||
call _LoadFunction
|
||||
|
||||
.end:
|
||||
;We never load, never ever ever!
|
||||
xor eax, eax
|
||||
|
||||
pop edi
|
||||
|
||||
pop ebp
|
||||
%ifdef LINUX
|
||||
ret
|
||||
%else
|
||||
retn 8
|
||||
%endif
|
||||
|
||||
thisUnloadFunction:
|
||||
ret
|
||||
|
||||
section .data
|
||||
INTERFACE_NAME DB "ISERVERPLUGINCALLBACKS001", 0
|
||||
VENGINESERVER DB "VEngineServer021", 0
|
||||
VENGINECVAR DB "VEngineCvar003", 0
|
||||
|
||||
VIRTUAL_TABLE DD thisLoadFunction
|
||||
DD thisUnloadFunction
|
||||
;We don't need any more of the vtable here
|
||||
|
||||
GLOBAL_POINTER DD VIRTUAL_TABLE
|
||||
|
||||
temp_ret DD 0
|
||||
temp_ptr DD temp_ret
|
||||
engine DD 0
|
||||
icvar DD 0
|
@ -1,20 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "update_tool", "update_tool.vcproj", "{DDD1563F-7EE2-4E76-BE57-ED84A2664A51}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DDD1563F-7EE2-4E76-BE57-ED84A2664A51}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{DDD1563F-7EE2-4E76-BE57-ED84A2664A51}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{DDD1563F-7EE2-4E76-BE57-ED84A2664A51}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{DDD1563F-7EE2-4E76-BE57-ED84A2664A51}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,203 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="update_tool"
|
||||
ProjectGUID="{DDD1563F-7EE2-4E76-BE57-ED84A2664A51}"
|
||||
RootNamespace="update_tool"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
CommandLine="nasmw ..\api_link.asm -f win32 -oDebug\api_link.obj -DWIN32"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;UPDATE_TOOL_EXPORTS;_CRT_SECURE_NO_DEPRECATE;_CRT_STD_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="Debug\api_link.obj tier0.lib"
|
||||
OutputFile="$(OutDir)\sourcemm_update_tool.dll"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
CommandLine="nasmw ..\api_link.asm -f win32 -oRelease\api_link.obj -DWIN32"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;UPDATE_TOOL_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="Release\api_link.obj tier0.lib"
|
||||
OutputFile="$(OutDir)\sourcemm_update_tool.dll"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\update_tool.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -1,6 +0,0 @@
|
||||
//This is a sample VDF file. You need to edit "cstrike" to point to the mod you use.
|
||||
|
||||
"Plugin"
|
||||
{
|
||||
"file" "cstrike/addons/metamod/bin/sourcemm_update_tool"
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
;Use this to configure where Metamod resides, if you have
|
||||
;changed its location
|
||||
;mmpath = addons/metamod/bin
|
||||
|
||||
;Use this to specify how the updater tool restarts SourceDS
|
||||
; never - don't restart
|
||||
; error - restart by generating a fatal error message
|
||||
; quit - restart by issuing a "quit" server command
|
||||
restart = error
|
@ -1,366 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined _MSC_VER
|
||||
#define SEPCHAR "\\"
|
||||
#define MMPATH "addons\\metamod\\bin"
|
||||
#define WINDOWS_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#elif defined __linux__
|
||||
#define SEPCHAR "/"
|
||||
#define MMPATH "addons/metamod/bin"
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <icvar.h>
|
||||
|
||||
extern "C" void GetGameDir(char *buffer, int maxlength);
|
||||
extern "C" void *GetThisPointer();
|
||||
extern "C" void ServerCommand(const char *command);
|
||||
extern "C" ICvar *GetICvar();
|
||||
|
||||
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
|
||||
bool s_isspace(char c);
|
||||
bool RenameFile(const char *old, const char *newf);
|
||||
bool RemoveFile(const char *file);
|
||||
|
||||
/* This will be called by the thunk */
|
||||
#if defined _MSC_VER
|
||||
extern "C" void LoadFunction()
|
||||
#elif defined __linux__
|
||||
extern "C" void _LoadFunction()
|
||||
#endif
|
||||
{
|
||||
ICvar *pCvar = GetICvar();
|
||||
if (pCvar->FindVar("metamod_version") != NULL)
|
||||
{
|
||||
/* Already exists, bail out */
|
||||
return;
|
||||
}
|
||||
|
||||
char gamedir[260];
|
||||
char mmpath[260];
|
||||
|
||||
enum RestartMode
|
||||
{
|
||||
Restart_Never,
|
||||
Restart_Error,
|
||||
Restart_Quit,
|
||||
};
|
||||
|
||||
RestartMode mode = Restart_Error;
|
||||
|
||||
GetGameDir(gamedir, sizeof(gamedir));
|
||||
|
||||
/* Defaults */
|
||||
UTIL_Format(mmpath, sizeof(mmpath), "|gameinfo_path|%s", MMPATH);
|
||||
|
||||
/* Read config */
|
||||
char config[260];
|
||||
UTIL_Format(config, sizeof(config), "%s" SEPCHAR "sourcemm_updater.conf", gamedir);
|
||||
FILE *fpCfg = fopen(config, "rt");
|
||||
if (fpCfg)
|
||||
{
|
||||
char cfgLine[512];
|
||||
while (!feof(fpCfg) && fgets(cfgLine, sizeof(cfgLine), fpCfg) != NULL)
|
||||
{
|
||||
char key[255];
|
||||
|
||||
size_t keyLen = 0;
|
||||
|
||||
/* Strip whitespace */
|
||||
char *input = cfgLine;
|
||||
while (*input != '\0' && s_isspace(*input))
|
||||
{
|
||||
input++;
|
||||
}
|
||||
|
||||
/* Strip ending whitespace */
|
||||
size_t len = strlen(input);
|
||||
for (size_t i = len - 1;
|
||||
i >= 0 && i < len;
|
||||
i--)
|
||||
{
|
||||
if (s_isspace(input[i]))
|
||||
{
|
||||
input[i] = '\0';
|
||||
len--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Eat stuff until we find a key */
|
||||
while (*input != '\0' && !s_isspace(*input))
|
||||
{
|
||||
if (keyLen < sizeof(key))
|
||||
{
|
||||
key[keyLen++] = *input;
|
||||
}
|
||||
input++;
|
||||
}
|
||||
key[keyLen] = '\0';
|
||||
|
||||
/* Eat spaces until we hit an = sign */
|
||||
while (*input != '\0' && *input != '=')
|
||||
{
|
||||
input++;
|
||||
}
|
||||
|
||||
if (*input == '=')
|
||||
{
|
||||
input++;
|
||||
}
|
||||
|
||||
/* Eat spaces again */
|
||||
while (*input != '\0' && s_isspace(*input))
|
||||
{
|
||||
input++;
|
||||
}
|
||||
|
||||
/* Ignore comments */
|
||||
if (key[0] == ';')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The rest is our key */
|
||||
if (strcmp(key, "mmpath") == 0)
|
||||
{
|
||||
UTIL_Format(mmpath, sizeof(mmpath), "%s", input);
|
||||
} else if (strcmp(key, "restart") == 0) {
|
||||
if (strcmp(input, "never") == 0)
|
||||
{
|
||||
mode = Restart_Never;
|
||||
} else if (strcmp(input, "error") == 0) {
|
||||
mode = Restart_Error;
|
||||
} else if (strcmp(input, "quit") == 0) {
|
||||
mode = Restart_Quit;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fpCfg);
|
||||
}
|
||||
|
||||
char old_path[260];
|
||||
char new_path[260];
|
||||
|
||||
UTIL_Format(old_path, sizeof(old_path), "%s" SEPCHAR "gameinfo.txt", gamedir);
|
||||
UTIL_Format(new_path, sizeof(new_path), "%s" SEPCHAR "gameinfo.new.txt", gamedir);
|
||||
|
||||
FILE *fp = fopen(old_path, "rt");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *op = fopen(new_path, "wt");
|
||||
if (!op)
|
||||
{
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
enum ParseState
|
||||
{
|
||||
Parse_None,
|
||||
Parse_Root,
|
||||
Parse_GameInfo,
|
||||
Parse_FileSystem,
|
||||
Parse_SearchPaths,
|
||||
};
|
||||
|
||||
ParseState ps = Parse_Root;
|
||||
|
||||
char input[1024];
|
||||
char backup[1024];
|
||||
|
||||
bool bWroteOutput = false;
|
||||
|
||||
while (!feof(fp) && fgets(input, sizeof(input), fp) != NULL)
|
||||
{
|
||||
UTIL_Format(backup, sizeof(backup), "%s", input);
|
||||
|
||||
if (ps != Parse_None)
|
||||
{
|
||||
char *inbuf = input;
|
||||
|
||||
/* Strip beginning whitespace */
|
||||
while (*inbuf != '\0' && s_isspace(*inbuf))
|
||||
{
|
||||
inbuf++;
|
||||
}
|
||||
|
||||
/* Strip ending whitespace */
|
||||
size_t len = strlen(inbuf);
|
||||
for (size_t i = len - 1;
|
||||
i >= 0 && i < len;
|
||||
i--)
|
||||
{
|
||||
if (s_isspace(inbuf[i]))
|
||||
{
|
||||
inbuf[i] = '\0';
|
||||
len--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Strip quotation marks */
|
||||
if (inbuf[0] == '"'
|
||||
&& inbuf[len-1] == '"')
|
||||
{
|
||||
inbuf[len - 1] = '\0';
|
||||
inbuf = &inbuf[1];
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
/* Do tests */
|
||||
if (ps == Parse_Root && strcmp(inbuf, "GameInfo") == 0)
|
||||
{
|
||||
ps = Parse_GameInfo;
|
||||
} else if (ps == Parse_GameInfo && strcmp(inbuf, "FileSystem") == 0) {
|
||||
ps = Parse_FileSystem;
|
||||
} else if (ps == Parse_FileSystem && strcmp(inbuf, "SearchPaths") == 0) {
|
||||
ps = Parse_SearchPaths;
|
||||
} else if (ps == Parse_SearchPaths) {
|
||||
const char *game = strstr(inbuf, "Game");
|
||||
if (game)
|
||||
{
|
||||
if (strstr(game, "GameBin") != NULL
|
||||
&& strstr(game, mmpath) != NULL)
|
||||
{
|
||||
fclose(op);
|
||||
op = NULL;
|
||||
break; /* Nothing more to do! */
|
||||
} else {
|
||||
fputs("\t\t\tGameBin\t\t\t", op);
|
||||
fputs(mmpath, op);
|
||||
fputs("\n", op);
|
||||
ps = Parse_None;
|
||||
bWroteOutput = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fputs(backup, op);
|
||||
}
|
||||
|
||||
if (!op)
|
||||
{
|
||||
/* Well, we can't really do anything else. Give up. */
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Close all streams */
|
||||
fclose(op);
|
||||
fclose(fp);
|
||||
|
||||
/* If we didn't change anything, abort here */
|
||||
if (!bWroteOutput)
|
||||
{
|
||||
RemoveFile(new_path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move the old file to a backup name */
|
||||
char backup_name[260];
|
||||
UTIL_Format(backup_name, sizeof(backup_name), "%s" SEPCHAR "gameinfo.backup.txt", gamedir);
|
||||
|
||||
if (!RenameFile(old_path, backup_name))
|
||||
{
|
||||
/* If we can't rename, just bail out.
|
||||
* We don't want to overwrite the client's default
|
||||
* without backing it up first!
|
||||
*/
|
||||
return;
|
||||
}
|
||||
if (!RenameFile(new_path, old_path))
|
||||
{
|
||||
/* Since this failed, we really have no choice.
|
||||
* Try and rename the old back.
|
||||
*/
|
||||
RenameFile(backup_name, old_path);
|
||||
return;
|
||||
}
|
||||
RemoveFile(new_path);
|
||||
|
||||
if (mode == Restart_Error)
|
||||
{
|
||||
Error("Server is restarting to load Metamod:Source");
|
||||
} else if (mode == Restart_Quit) {
|
||||
ServerCommand("quit\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoveFile(const char *file)
|
||||
{
|
||||
#if defined _MSC_VER
|
||||
return (_unlink(file) == 0);
|
||||
#else
|
||||
return (unlink(file) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool s_isspace(char c)
|
||||
{
|
||||
if ((unsigned)c & 0x80)
|
||||
{
|
||||
return false;
|
||||
} else {
|
||||
return isspace(c) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
size_t len = vsnprintf(buffer, maxlength, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len >= maxlength)
|
||||
{
|
||||
len = maxlength - 1;
|
||||
buffer[len] = '\0';
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool RenameFile(const char *old, const char *newf)
|
||||
{
|
||||
#if defined __linux__
|
||||
return (rename(old, newf) == 0);
|
||||
#elif defined WIN32
|
||||
return (MoveFileA(old, newf) != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined _MSC_VER
|
||||
extern "C" __declspec(dllexport) void *CreateInterface(const char *iface, int *ret)
|
||||
#elif defined __linux__
|
||||
extern "C" __attribute__((visibility("default"))) void *CreateInterface(const char *iface, int *ret)
|
||||
#endif
|
||||
{
|
||||
if (strcmp(iface, "ISERVERPLUGINCALLBACKS001") == 0)
|
||||
{
|
||||
if (ret)
|
||||
{
|
||||
*ret = 0;
|
||||
}
|
||||
return GetThisPointer();
|
||||
}
|
||||
|
||||
if (ret)
|
||||
{
|
||||
*ret = 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user