1
0
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:
Scott Ehlert 2008-09-16 03:32:01 -05:00
commit 2ea6e744bb
85 changed files with 1863 additions and 1863 deletions

View File

@ -31,8 +31,8 @@
-M -M
-$M16384,1048576 -$M16384,1048576
-K$00400000 -K$00400000
-LE"c:\programme\borland\delphi7\Projects\Bpl" -LE"c:\program files\borland\delphi7\Projects\Bpl"
-LN"c:\programme\borland\delphi7\Projects\Bpl" -LN"c:\program files\borland\delphi7\Projects\Bpl"
-w-UNSAFE_TYPE -w-UNSAFE_TYPE
-w-UNSAFE_CODE -w-UNSAFE_CODE
-w-UNSAFE_CAST -w-UNSAFE_CAST

View File

@ -14,24 +14,31 @@ begin
WriteLn(''); WriteLn('');
WriteLn('// Looking up files...'); WriteLn('// Looking up files...');
{ Check files } { Check files }
if FileExists(ExtractFilePath(ParamStr(0)) + 'files\hl2launch.exe') then if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server.dll.source') then
WriteLn('// Found files\hl2launch.exe') WriteLn('// Found files\server.dll.source')
else begin else begin
WriteLn('// Error: Couldn''t find files\hl2launch.exe!'); WriteLn('// Error: Couldn''t find files\server.dll.source!');
ReadLn; ReadLn;
exit; exit;
end; end;
if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server.dll') then if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so.source') then
WriteLn('// Found files\server.dll') WriteLn('// Found files\server_i486.so.source')
else begin else begin
WriteLn('// Error: Couldn''t find files\server.dll!'); WriteLn('// Error: Couldn''t find files\server_i486.so.source!');
ReadLn; ReadLn;
exit; exit;
end; end;
if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so') then if FileExists(ExtractFilePath(ParamStr(0)) + 'files\server.dll.orangebox') then
WriteLn('// Found files\server_i486.so') WriteLn('// Found files\server.dll.orangebox')
else begin 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; ReadLn;
exit; exit;
end; end;
@ -53,9 +60,10 @@ begin
{ Compress files } { Compress files }
WriteLn('// Compressing files...'); WriteLn('// Compressing files...');
eFiles := TStringList.Create; eFiles := TStringList.Create;
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\hl2launch.exe'); eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server.dll.source');
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server.dll'); eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so.source');
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so'); eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server.dll.orangebox');
eFiles.Add(ExtractFilePath(ParamStr(0)) + 'files\server_i486.so.orangebox');
eStream := TMemoryStream.Create; eStream := TMemoryStream.Create;
CompressFiles(eFiles, ExtractFilePath(ParamStr(0)) + 'temp.zip'); CompressFiles(eFiles, ExtractFilePath(ParamStr(0)) + 'temp.zip');
eStream.LoadFromFile(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); AttachToFile(ExtractFilePath(ParamStr(0)) + 'MMS_Installer.exe', eStream, Version);
DeleteFile(ExtractFilePath(ParamStr(0)) + 'temp.zip'); DeleteFile(ExtractFilePath(ParamStr(0)) + 'temp.zip');
eStream.Free; eStream.Free;
eFiles.Free;
WriteLn('// Done.'); WriteLn('// Done.');
ReadLn; ReadLn;
end. end.

Binary file not shown.

View File

@ -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

View File

@ -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.

View File

@ -31,8 +31,8 @@
-M -M
-$M16384,1048576 -$M16384,1048576
-K$00400000 -K$00400000
-LE"c:\program files (x86)\borland\delphi7\Projects\Bpl" -LE"c:\program files\borland\delphi7\Projects\Bpl"
-LN"c:\program files (x86)\borland\delphi7\Projects\Bpl" -LN"c:\program files\borland\delphi7\Projects\Bpl"
-w-UNSAFE_TYPE -w-UNSAFE_TYPE
-w-UNSAFE_CODE -w-UNSAFE_CODE
-w-UNSAFE_CAST -w-UNSAFE_CAST

Binary file not shown.

View File

@ -10,6 +10,8 @@ function GetAllFiles(Mask: String; Attr: Integer; Recursive: Boolean; ShowDirs:
// ftp // ftp
function GetAllDirs: TStringList; function GetAllDirs: TStringList;
function GetModName(const Path: String): String;
implementation implementation
uses UnitfrmMain; uses UnitfrmMain;
@ -121,6 +123,20 @@ begin
Result := eList; Result := eList;
end; } 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. end.

View File

@ -13,11 +13,11 @@ procedure AddSkipped;
procedure AddNotFound; procedure AddNotFound;
procedure DownloadFile(eFile: String; eDestination: String); procedure DownloadFile(eFile: String; eDestination: String);
procedure BasicInstallation(ePath: String; SteamInstall, ListenInstall: Boolean; OS: TOS); procedure BasicInstallation(ePath: String; SteamInstall, ListenInstall: Boolean; OS: TOS; const Source: Boolean);
procedure InstallDedicated(eModPath: String; UseSteam: Boolean); procedure InstallDedicated(eModPath: String; const UseSteam, Source: Boolean);
procedure InstallListen(ePath: String); procedure InstallListen(ePath: String; const Source: Boolean);
procedure InstallCustom(ePath: String; eOS: TOS); procedure InstallCustom(ePath: String; eOS: TOS; const Source: Boolean);
procedure InstallFTP(OS: TOS); procedure InstallFTP(OS: TOS; const Source: Boolean; const ModDir: String);
var StartTime: TDateTime; var StartTime: TDateTime;
SteamPath: String; SteamPath: String;
@ -32,7 +32,7 @@ uses UnitfrmMain, UnitfrmProxy, UnitFunctions, UnitPackSystem;
function InstallTime: String; function InstallTime: String;
begin begin
Result := FormatDateTime('HH:MM:SS', Now - StartTime); Result := Copy(FormatDateTime('HH:MM:SS', Now - StartTime), 4, 5);
end; end;
procedure AddStatus(Text: String; Color: TColor; ShowTime: Boolean = True); procedure AddStatus(Text: String; Color: TColor; ShowTime: Boolean = True);
@ -218,18 +218,16 @@ end;
{ Basic Installation } { 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; var eStr: TStringList;
i: integer;
CopyConfig: Boolean; CopyConfig: Boolean;
eFound: Boolean;
begin begin
frmMain.ggeAll.MaxValue := 8; frmMain.ggeAll.MaxValue := 8;
frmMain.ggeAll.Progress := 0; frmMain.ggeAll.Progress := 0;
frmMain.ggeItem.MaxValue := 1; frmMain.ggeItem.MaxValue := 1;
frmMain.ggeItem.Progress := 0; 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 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); AddStatus('Shutting down Steam...', clBlack, False);
if GetProcessID('Steam.exe') = -1 then if GetProcessID('Steam.exe') = -1 then
@ -247,13 +245,13 @@ begin
Application.Terminate; Application.Terminate;
exit; exit;
end; end;
end; end;}
frmMain.ggeAll.Progress := 1; frmMain.ggeAll.Progress := 1;
frmMain.ggeItem.Progress := 1; frmMain.ggeItem.Progress := 1;
{ Unpack } { Unpack }
frmMain.ggeItem.Progress := 0; frmMain.ggeItem.Progress := 0;
AddStatus('Unpacking files...', clBlack); AddStatus('Unpacking files...', clBlack);
if not Unpack() then begin if not Unpack(Source) then begin
AddStatus('No files attached!', clRed); AddStatus('No files attached!', clRed);
Screen.Cursor := crDefault; Screen.Cursor := crDefault;
exit; exit;
@ -265,8 +263,8 @@ begin
CopyConfig := True; CopyConfig := True;
AddStatus('Creating directories...', clBlack); AddStatus('Creating directories...', clBlack);
if DirectoryExists(ePath + 'addons\metamod\bin') then begin 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 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
mrNo: CopyConfig := False; mrYes: CopyConfig := False;
mrCancel: begin mrCancel: begin
Application.Terminate; Application.Terminate;
exit; exit;
@ -282,7 +280,7 @@ begin
frmMain.ggeItem.Progress := 1; frmMain.ggeItem.Progress := 1;
frmMain.ggeAll.Progress := 3; frmMain.ggeAll.Progress := 3;
{ gameinfo.txt } { gameinfo.txt for check / create VDF file }
if not FileExists(ePath + 'gameinfo.txt') then begin 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 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); AddStatus('Installation canceled by user!', clRed, False);
@ -304,33 +302,32 @@ begin
AddSkipped; AddSkipped;
frmMain.ggeItem.Progress := 1; frmMain.ggeItem.Progress := 1;
frmMain.ggeAll.Progress := 4; frmMain.ggeAll.Progress := 4;
{ Gameinfo.txt } { CDF Plugin }
frmMain.ggeItem.Progress := 0; frmMain.ggeItem.Progress := 0;
eFound := False; AddStatus('Creating VDF Plugin...', clBlack);
AddStatus('Editing gameinfo.txt...', clBlack); if (FileExists(ePath + 'addons\metamod.vdf')) then begin
eStr.LoadFromFile(ePath + 'gameinfo.txt'); eStr.LoadFromFile(ePath + 'addons\metamod.vdf');
for i := 0 to eStr.Count -1 do begin if (Pos('server.dll', eStr.Text) <> 0) then
if Trim(LowerCase(eStr[i])) = 'gamebin |gameinfo_path|addons/metamod/bin' then begin AddSkipped
eFound := True; else begin
break; 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; 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;
SetFileAttributes(PChar(ePath + 'gameinfo.txt'), 0);
eStr.SaveToFile(ePath + 'gameinfo.txt');
SetFileAttributes(PChar(ePath + 'gameinfo.txt'), faReadOnly); // important for listen servers
AddDone;
end end
else else begin
AddSkipped; 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; eStr.Free;
frmMain.ggeItem.Progress := 1; frmMain.ggeItem.Progress := 1;
frmMain.ggeAll.Progress := 5; frmMain.ggeAll.Progress := 5;
@ -342,16 +339,9 @@ begin
AddDone; AddDone;
frmMain.ggeItem.Progress := 1; frmMain.ggeItem.Progress := 1;
frmMain.ggeAll.Progress := 6; 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 } { Remove files }
frmMain.ggeItem.Progress := 0; frmMain.ggeItem.Progress := 0;
AddStatus('Removing temporary files...', clBlack); 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.dll'));
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server_i486.so')); DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server_i486.so'));
AddDone; AddDone;
@ -363,44 +353,41 @@ begin
frmMain.cmdNext.Enabled := True; frmMain.cmdNext.Enabled := True;
frmMain.cmdCancel.Hide; frmMain.cmdCancel.Hide;
Screen.Cursor := crDefault; 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; end;
{ Dedicated Server } { Dedicated Server }
procedure InstallDedicated(eModPath: String; UseSteam: Boolean); procedure InstallDedicated(eModPath: String; const UseSteam, Source: Boolean);
begin begin
StartTime := Now; StartTime := Now;
Screen.Cursor := crHourGlass; Screen.Cursor := crHourGlass;
AddStatus('Starting Metamod:Source installation on dedicated server...', clBlack, False); AddStatus('Starting Metamod:Source installation on dedicated server...', clBlack, False);
BasicInstallation(eModPath, UseSteam, False, osWindows); BasicInstallation(eModPath, UseSteam, False, osWindows, Source);
end; end;
{ Listen Server } { Listen Server }
procedure InstallListen(ePath: String); procedure InstallListen(ePath: String; const Source: Boolean);
begin begin
StartTime := Now; StartTime := Now;
Screen.Cursor := crHourGlass; Screen.Cursor := crHourGlass;
AddStatus('Starting Metamod:Source installation on the listen server...', clBlack); AddStatus('Starting Metamod:Source installation on the listen server...', clBlack);
BasicInstallation(ePath, True, True, osWindows); BasicInstallation(ePath, True, True, osWindows, Source);
end; end;
{ Custom mod } { Custom mod }
procedure InstallCustom(ePath: String; eOS: TOS); procedure InstallCustom(ePath: String; eOS: TOS; const Source: Boolean);
begin begin
StartTime := Now; StartTime := Now;
Screen.Cursor := crHourGlass; Screen.Cursor := crHourGlass;
AddStatus('Starting Metamod:Source installation...', clBlack); AddStatus('Starting Metamod:Source installation...', clBlack);
BasicInstallation(ePath, False, False, eOS); BasicInstallation(ePath, False, False, eOS, Source);
end; end;
{ FTP } { FTP }
procedure InstallFTP(OS: TOS); procedure InstallFTP(OS: TOS; const Source: Boolean; const ModDir: String);
function DoReconnect: Boolean; function DoReconnect: Boolean;
begin begin
Result := False; Result := False;
@ -414,11 +401,13 @@ begin
end; end;
end; end;
label CreateAgain; label CreateAgain;
label UploadAgain; label UploadAgain;
var eStr: TStringList; var eStr: TStringList;
i: integer; CopyConfig, CommentFound: Boolean;
CopyConfig, eFound: Boolean; i: Integer;
begin begin
frmMain.cmdCancel.Show; frmMain.cmdCancel.Show;
frmMain.cmdNext.Hide; frmMain.cmdNext.Hide;
@ -426,72 +415,27 @@ begin
frmMain.ggeAll.MaxValue := 6; frmMain.ggeAll.MaxValue := 6;
frmMain.ggeAll.Progress := 0; frmMain.ggeAll.Progress := 0;
frmMain.ggeItem.MaxValue := 1; frmMain.ggeItem.MaxValue := 3;
frmMain.ggeItem.Progress := 0; frmMain.ggeItem.Progress := 0;
StartTime := Now;
{ Unpack } { Unpack }
frmMain.ggeItem.Progress := 0;
AddStatus('Unpacking files...', clBlack); AddStatus('Unpacking files...', clBlack);
if not Unpack() then begin if not Unpack(Source) then begin
AddStatus('No files attached!', clRed); AddStatus('No files attached!', clRed);
Screen.Cursor := crDefault; Screen.Cursor := crDefault;
exit; exit;
end; end;
AddDone; AddDone;
frmMain.ggeAll.Progress := 2; frmMain.ggeAll.Progress := 1;
frmMain.ggeItem.Progress := 1; frmMain.ggeItem.Progress := 1;
{ Check for installation } Sleep(250);
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;
{ Create directories } { Create directories }
frmMain.ggeAll.Progress := 2;
frmMain.ggeItem.Progress := 0; frmMain.ggeItem.Progress := 0;
frmMain.ggeItem.MaxValue := 3;
AddStatus('Creating directories...', clBlack); AddStatus('Creating directories...', clBlack);
if not eFound then begin try
FTPMakeDir('addons'); FTPMakeDir('addons');
frmMain.IdFTP.ChangeDir('addons'); frmMain.IdFTP.ChangeDir('addons');
frmMain.ggeItem.Progress := 1; frmMain.ggeItem.Progress := 1;
@ -501,24 +445,108 @@ begin
FTPMakeDir('bin'); FTPMakeDir('bin');
frmMain.ggeItem.Progress := 3; frmMain.ggeItem.Progress := 3;
AddDone; AddDone;
end except
else
AddSkipped; 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; frmMain.ggeItem.Progress := 3;
{ Upload metaplugins.ini } { Upload metaplugins.ini }
frmMain.ggeAll.Progress := 4; frmMain.ggeAll.Progress := 4;
frmMain.ggeItem.MaxValue := 1; frmMain.ggeItem.MaxValue := 1;
frmMain.ggeItem.Progress := 0; frmMain.ggeItem.Progress := 0;
AddStatus('Uploading metaplugins.ini...', clBlack); AddStatus('Uploading metaplugins.ini...', clBlack);
if CopyConfig then begin frmMain.IdFTP.ChangeDir('metamod');
if (CopyConfig) then begin
eStr.Clear; 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'); eStr.SaveToFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini');
UploadFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini', 'metaplugins.ini'); UploadFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini', 'metaplugins.ini');
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini'));
end end
else else if (frmMain.IdFTP.Size('metaplugins.ini') <> -1) then begin
AddSkipped; 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.ggeAll.Progress := 5;
frmMain.ggeItem.Progress := 1; frmMain.ggeItem.Progress := 1;
{ Upload server.dll / server_i486.so } { Upload server.dll / server_i486.so }
@ -537,9 +565,10 @@ begin
end; end;
{ Remove created files } { Remove created files }
AddStatus('Removing temporary files...', clBlack); 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.dll'));
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server_i486.so')); DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server_i486.so'));
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'metamod.vdf'));
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini'));
AddDone; AddDone;
{ End } { End }
frmMain.IdFTP.Disconnect; frmMain.IdFTP.Disconnect;

View File

@ -4,11 +4,11 @@ interface
uses SysUtils, Classes, Zlib; uses SysUtils, Classes, Zlib;
procedure CompressFiles(Files : TStrings; const Filename : String); 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 AttachToFile(const AFileName: string; MemoryStream: TMemoryStream; Version: String): Boolean;
function LoadFromFile(const AFileName: string; MemoryStream: TMemoryStream): Boolean; function LoadFromFile(const AFileName: string; MemoryStream: TMemoryStream): Boolean;
function Unpack: Boolean; function Unpack(const Source: Boolean): Boolean;
function GetVersion: String; function GetVersion: String;
implementation implementation
@ -54,6 +54,8 @@ begin
{ append the compressed file to the destination file } { append the compressed file to the destination file }
tmpFile := TFileStream.Create('tmp',fmOpenRead); tmpFile := TFileStream.Create('tmp',fmOpenRead);
try try
l := tmpFile.Size;
outfile.WriteBuffer(l, SizeOf(l));
outfile.CopyFrom(tmpFile,0); outfile.CopyFrom(tmpFile,0);
finally finally
tmpFile.Free; tmpFile.Free;
@ -68,12 +70,13 @@ begin
DeleteFile('tmp'); DeleteFile('tmp');
end; end;
end; end;
function DecompressStream(Stream : TMemoryStream; DestDirectory : String): Boolean;
function DecompressStream(Stream : TMemoryStream; DestDirectory : String; const Source: Boolean): Boolean;
var var
dest,s : String; dest,s : String;
decompr : TDecompressionStream; decompr : TDecompressionStream;
outfile : TFilestream; outfile : TFilestream;
i,l,c : Integer; i,l,lr,c : Integer;
begin begin
// IncludeTrailingPathDelimiter (D6/D7 only) // IncludeTrailingPathDelimiter (D6/D7 only)
dest := IncludeTrailingPathDelimiter(DestDirectory); dest := IncludeTrailingPathDelimiter(DestDirectory);
@ -82,24 +85,30 @@ begin
try try
{ number of files } { number of files }
Stream.Read(c,SizeOf(c)); Stream.Read(c,SizeOf(c));
for i := 1 to c do for i := 1 to c do begin
begin
{ read filename } { read filename }
Stream.Read(l,SizeOf(l)); Stream.Read(l,SizeOf(l));
SetLength(s,l); SetLength(s,l);
Stream.Read(s[1],l); Stream.Read(s[1],l);
{ read filesize }
Stream.Read(l,SizeOf(l)); Stream.Read(l,SizeOf(l));
{ decompress the files and store it } Stream.Read(lr,SizeOf(lr));
s := dest+s; //include the path { check if this is the right file }
outfile := TFileStream.Create(s,fmCreate); if ((Pos('.source', s) <> 0) and (Source)) or ((Pos('.orangebox', s) <> 0) and (not Source)) then begin
decompr := TDecompressionStream.Create(Stream); { remove extension and read filesize }
try s := ChangeFileExt(s, '');
outfile.CopyFrom(decompr,l); { decompress the files and store it }
finally s := dest+s; //include the path
outfile.Free; outfile := TFileStream.Create(s,fmCreate);
decompr.Free; decompr := TDecompressionStream.Create(Stream);
end; try
outfile.CopyFrom(decompr,l);
finally
outfile.Free;
decompr.Free;
end;
end
else
Stream.Position := Stream.Position + lr;
end; end;
finally finally
Result := True; Result := True;
@ -114,6 +123,7 @@ begin
Result := False; Result := False;
if not FileExists(AFileName) then if not FileExists(AFileName) then
Exit; Exit;
try try
aStream := TFileStream.Create(AFileName, fmOpenWrite or fmShareDenyWrite); aStream := TFileStream.Create(AFileName, fmOpenWrite or fmShareDenyWrite);
MemoryStream.Seek(0, soFromBeginning); MemoryStream.Seek(0, soFromBeginning);
@ -177,14 +187,14 @@ end;
{ Unpack function } { Unpack function }
function Unpack: Boolean; function Unpack(const Source: Boolean): Boolean;
var eStream: TMemoryStream; var eStream: TMemoryStream;
begin begin
eStream := TMemoryStream.Create; eStream := TMemoryStream.Create;
try try
// Get ZIP // Get ZIP
LoadFromFile(ParamStr(0), eStream); LoadFromFile(ParamStr(0), eStream);
DecompressStream(eStream, ExtractFilePath(ParamStr(0))); // Unpack files DecompressStream(eStream, ExtractFilePath(ParamStr(0)), Source); // Unpack files
Result := True; Result := True;
except except

Binary file not shown.

View File

@ -5,7 +5,7 @@ interface
uses uses
SysUtils, Windows, Messages, Classes, Graphics, Controls, SysUtils, Windows, Messages, Classes, Graphics, Controls,
StdCtrls, ExtCtrls, Forms, FileCtrl, ComCtrls, ShellCtrls, StdCtrls, ExtCtrls, Forms, FileCtrl, ComCtrls, ShellCtrls,
TFlatComboBoxUnit, TFlatButtonUnit; TFlatComboBoxUnit, TFlatButtonUnit, TFlatCheckBoxUnit;
type type
TfrmSelectModPath = class(TForm) TfrmSelectModPath = class(TForm)
@ -14,6 +14,8 @@ type
trvDirectory: TShellTreeView; trvDirectory: TShellTreeView;
cmdOK: TFlatButton; cmdOK: TFlatButton;
cmdCancel: TFlatButton; cmdCancel: TFlatButton;
chkUsesOrangebox: TFlatCheckBox;
procedure trvDirectoryClick(Sender: TObject);
end; end;
var var
@ -23,4 +25,11 @@ implementation
{$R *.DFM} {$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. end.

View File

@ -10407,7 +10407,7 @@ object frmMain: TfrmMain
Lines.Strings = ( Lines.Strings = (
'The zlib/libpng License' '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' + 'This software is provided '#39'as-is'#39', without any express or implie' +
@ -10838,12 +10838,12 @@ object frmMain: TfrmMain
Height = 13 Height = 13
Caption = '2. Connect to server and select the mod directory:' Caption = '2. Connect to server and select the mod directory:'
end end
object lblStep4: TLabel object lblStep5: TLabel
Left = 44 Left = 44
Top = 296 Top = 338
Width = 64 Width = 64
Height = 13 Height = 13
Caption = '4. Click Next.' Caption = '5. Click Next.'
end end
object lblStep3: TLabel object lblStep3: TLabel
Left = 44 Left = 44
@ -10852,6 +10852,13 @@ object frmMain: TfrmMain
Height = 13 Height = 13
Caption = '3. Select the operating system of your server:' Caption = '3. Select the operating system of your server:'
end end
object lblStep4: TLabel
Left = 44
Top = 296
Width = 125
Height = 13
Caption = '4. Select the engine type:'
end
object pnlHeader3: TPanel object pnlHeader3: TPanel
Left = 0 Left = 0
Top = 0 Top = 0
@ -11130,7 +11137,7 @@ object frmMain: TfrmMain
TabStop = True TabStop = True
end end
object optLinux: TFlatRadioButton object optLinux: TFlatRadioButton
Left = 173 Left = 183
Top = 3 Top = 3
Width = 82 Width = 82
Height = 14 Height = 14
@ -11138,7 +11145,7 @@ object frmMain: TfrmMain
TabOrder = 1 TabOrder = 1
end end
object FlatRadioButton1: TFlatRadioButton object FlatRadioButton1: TFlatRadioButton
Left = 353 Left = 319
Top = 3 Top = 3
Width = 82 Width = 82
Height = 14 Height = 14
@ -11147,6 +11154,40 @@ object frmMain: TfrmMain
TabOrder = 2 TabOrder = 2
end end
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 end
object jspInstallProgress: TJvStandardPage object jspInstallProgress: TJvStandardPage
Left = 0 Left = 0
@ -11404,8 +11445,8 @@ object frmMain: TfrmMain
end end
end end
object ilImages: TImageList object ilImages: TImageList
Left = 154 Left = 334
Top = 324 Top = 8
Bitmap = { Bitmap = {
494C010102000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 494C010102000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
0000000000003600000028000000400000001000000001002000000000000010 0000000000003600000028000000400000001000000001002000000000000010
@ -11555,23 +11596,23 @@ object frmMain: TfrmMain
OnWork = IdFTPWork OnWork = IdFTPWork
ProxySettings.ProxyType = fpcmNone ProxySettings.ProxyType = fpcmNone
ProxySettings.Port = 0 ProxySettings.Port = 0
Left = 274 Left = 454
Top = 324 Top = 8
end end
object IdAntiFreeze: TIdAntiFreeze object IdAntiFreeze: TIdAntiFreeze
IdleTimeOut = 150 IdleTimeOut = 150
Left = 244 Left = 424
Top = 324 Top = 8
end end
object tmrSpeed: TTimer object tmrSpeed: TTimer
Enabled = False Enabled = False
OnTimer = tmrSpeedTimer OnTimer = tmrSpeedTimer
Left = 214 Left = 394
Top = 324 Top = 8
end end
object IdLogFile: TIdLogFile object IdLogFile: TIdLogFile
LogTime = False LogTime = False
Left = 184 Left = 364
Top = 324 Top = 8
end end
end end

View File

@ -63,7 +63,7 @@ type
cmdConnect: TFlatButton; cmdConnect: TFlatButton;
pnlDirectory: TPanel; pnlDirectory: TPanel;
trvDirectories: TTreeView; trvDirectories: TTreeView;
lblStep4: TLabel; lblStep5: TLabel;
jspInstallProgress: TJvStandardPage; jspInstallProgress: TJvStandardPage;
pnlHeader5: TPanel; pnlHeader5: TPanel;
imgIcon4: TImage; imgIcon4: TImage;
@ -101,6 +101,11 @@ type
shpMods: TShape; shpMods: TShape;
trvMods: TTreeView; trvMods: TTreeView;
FlatRadioButton1: TFlatRadioButton; FlatRadioButton1: TFlatRadioButton;
pnlEngineType: TPanel;
optAutoDetect: TFlatRadioButton;
optSource: TFlatRadioButton;
optOrangeBox: TFlatRadioButton;
lblStep4: TLabel;
procedure jvwStepsCancelButtonClick(Sender: TObject); procedure jvwStepsCancelButtonClick(Sender: TObject);
procedure cmdCancelClick(Sender: TObject); procedure cmdCancelClick(Sender: TObject);
procedure cmdNextClick(Sender: TObject); procedure cmdNextClick(Sender: TObject);
@ -136,6 +141,9 @@ var
var VERSION: String = '<none>'; var VERSION: String = '<none>';
const NormalHeight = 382;
FTPHeight = 422;
implementation implementation
uses UnitFunctions, UnitfrmProxy, UnitInstall, UnitSelectModPath; uses UnitFunctions, UnitfrmProxy, UnitInstall, UnitSelectModPath;
@ -159,10 +167,11 @@ var ePath: String;
CurNode: TTreeNode; CurNode: TTreeNode;
eOS: TOS; eOS: TOS;
i: integer; i: integer;
Source: Boolean;
begin begin
{ FTP } { FTP }
if jplWizard.ActivePage = jspFTP then begin if (jplWizard.ActivePage = jspFTP) then begin
if not IdFTP.Connected then if (not IdFTP.Connected) then
IdFTP.Connect; IdFTP.Connect;
eStr := TStringList.Create; eStr := TStringList.Create;
ePath := '/'; ePath := '/';
@ -175,14 +184,22 @@ begin
end; end;
IdFTP.ChangeDir(ePath); IdFTP.ChangeDir(ePath);
IdFTP.List(eStr, '', False); 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); MessageBox(Handle, 'Invalid directory. Please select your mod directory and try again.', PChar(Application.Title), MB_ICONWARNING);
eStr.Free; eStr.Free;
exit; exit;
end end
else else
eStr.Free; 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 // design stuff
trvDirectories.Enabled := False; trvDirectories.Enabled := False;
cmdConnect.Enabled := False; cmdConnect.Enabled := False;
@ -190,81 +207,131 @@ begin
optLinux.Enabled := False; optLinux.Enabled := False;
Screen.Cursor := crHourGlass; Screen.Cursor := crHourGlass;
if optWindows.Checked then if (optWindows.Checked) then begin
eOS := osWindows eOS := osWindows;
else 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; 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; jspInstallProgress.Show;
// installation // installation
Screen.Cursor := crAppStart; Screen.Cursor := crAppStart;
InstallFTP(eOS); InstallFTP(eOS, Source, trvDirectories.Selected.Text);
end end
else if jplWizard.ActivePage = jspInstallProgress then else if (jplWizard.ActivePage = jspInstallProgress) then
Close Close
else if jplWizard.ActivePage = jspSelectMod then begin else if (jplWizard.ActivePage = jspSelectMod) then begin
{ Dedicated Server } { Dedicated Server }
if (frbDedicatedServer.Checked) or (frbStandaloneServer.Checked) then begin if frbDedicatedServer.Checked 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, 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;
{ Standalone Server }
if (frbStandaloneServer.Checked) then begin
Source := True;
ePath := trvMods.Selected.Text; ePath := trvMods.Selected.Text;
if ePath = 'Counter-Strike:Source' then if ePath = 'Counter-Strike:Source' then
ePath := 'cstrike' ePath := 'cstrike'
else if ePath = 'Day of Defeat:Source' then else if ePath = 'Day of Defeat:Source' then
ePath := 'dod' ePath := 'dod'
else else if ePath = 'Half-Life 2 Deathmatch' then
ePath := 'hl2mp'; ePath := 'hl2mp'
ePath := 'SteamApps\' + trvMods.Selected.Parent.Text + '\source dedicated server\' + ePath; else begin
// install it { get games }
if frbDedicatedServer.Checked then begin if (ePath = 'Team Fortress 2') then
if DirectoryExists(SteamPath + ePath) then begin ePath := 'orangebox\tf';
jspInstallProgress.Show; { ask user, just in case }
InstallDedicated(IncludeTrailingPathDelimiter(SteamPath + ePath), True); 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
end mrYes: Source := False;
else begin mrNo: Source := True;
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); mrCancel: exit;
jspSelectMod.Show;
exit;
end; end;
end;
// install it
if (DirectoryExists(StandaloneServer + ePath)) then begin
jspInstallProgress.Show;
InstallDedicated(IncludeTrailingPathDelimiter(StandaloneServer + ePath), False, Source)
end end
else begin else begin
if DirectoryExists(StandaloneServer + ePath) then 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);
jspInstallProgress.Show; jspSelectMod.Show;
InstallDedicated(IncludeTrailingPathDelimiter(StandaloneServer + ePath), False) exit;
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);
jspSelectMod.Show;
exit;
end;
end; end;
end; end;
{ Listen Server } { Listen Server }
if frbListenServer.Checked then begin if (frbListenServer.Checked) then begin
Source := True;
ePath := trvMods.Selected.Text; 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' 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' ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\half-life 2 deathmatch\hl2mp'
else else if ePath = 'Day of Defeat:Source' then
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\day of defeat source\dod'; 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) 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 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); MessageBox(Handle, 'You have to play this game once before installing Metamod:Source. Do that and try again.', PChar(Application.Title), MB_ICONWARNING);
exit; exit;
end; end;
jspInstallProgress.Show; jspInstallProgress.Show;
InstallListen(IncludeTrailingPathDelimiter(ePath)); InstallListen(IncludeTrailingPathDelimiter(ePath), Source);
end; end;
end; end;
{ Custom mod below } { Custom mod below }
end end
else if jplWizard.ActivePage <> jspInstallMethod then else if (jplWizard.ActivePage = jspInstallMethod) then begin
jplWizard.NextPage if (frbDedicatedServer.Checked) then begin // Dedicated Server
else begin
if frbDedicatedServer.Checked then begin // Dedicated Server
eRegistry := TRegistry.Create(KEY_READ); eRegistry := TRegistry.Create(KEY_READ);
try try
eRegistry.RootKey := HKEY_CURRENT_USER; eRegistry.RootKey := HKEY_CURRENT_USER;
@ -274,19 +341,21 @@ begin
SteamPath := ePath; SteamPath := ePath;
ePath := ePath + 'SteamApps\'; ePath := ePath + 'SteamApps\';
if DirectoryExists(ePath) then begin if (DirectoryExists(ePath)) then begin
trvMods.Items.Clear; trvMods.Items.Clear;
// Check Mods // Check Mods
eStr := GetAllFiles(ePath + '*.*', faDirectory, False, True, False); eStr := GetAllFiles(ePath + '*.*', faDirectory, False, True, False);
for i := 0 to eStr.Count -1 do begin for i := 0 to eStr.Count -1 do begin
CurNode := trvMods.Items.Add(nil, eStr[i]); 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'); 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'); 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'); 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 if CurNode.Count = 0 then
CurNode.Free CurNode.Free
@ -307,11 +376,11 @@ begin
eRegistry.Free; eRegistry.Free;
end; end;
end end
else if frbListenServer.Checked then begin // Listen Server else if (frbListenServer.Checked) then begin // Listen Server
eRegistry := TRegistry.Create(KEY_READ); eRegistry := TRegistry.Create(KEY_READ);
try try
eRegistry.RootKey := HKEY_CURRENT_USER; 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 := eRegistry.ReadString('SteamPath');
ePath := IncludeTrailingPathDelimiter(StringReplace(ePath, '/', '\', [rfReplaceAll])); ePath := IncludeTrailingPathDelimiter(StringReplace(ePath, '/', '\', [rfReplaceAll]));
SteamPath := ePath; SteamPath := ePath;
@ -330,6 +399,8 @@ begin
trvMods.Items.AddChild(CurNode, 'Day of Defeat:Source'); trvMods.Items.AddChild(CurNode, 'Day of Defeat:Source');
if DirectoryExists(ePath + eStr[i] + '\half-life 2 deathmatch') then if DirectoryExists(ePath + eStr[i] + '\half-life 2 deathmatch') then
trvMods.Items.AddChild(CurNode, 'Half-Life 2 Deatmatch'); 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 if CurNode.Count = 0 then
CurNode.Free CurNode.Free
@ -350,7 +421,7 @@ begin
eRegistry.Free; eRegistry.Free;
end; end;
end end
else if frbStandaloneServer.Checked then begin // Standalone Server else if (frbStandaloneServer.Checked) then begin // Standalone Server
eRegistry := TRegistry.Create; eRegistry := TRegistry.Create;
try try
eRegistry.RootKey := HKEY_CURRENT_USER; eRegistry.RootKey := HKEY_CURRENT_USER;
@ -362,6 +433,8 @@ begin
trvMods.Items.Add(nil, 'Day of Defeat:Source'); trvMods.Items.Add(nil, 'Day of Defeat:Source');
if DirectoryExists(StandaloneServer + 'hl2mp') then if DirectoryExists(StandaloneServer + 'hl2mp') then
trvMods.Items.Add(nil, 'Half-Life 2 Deatmatch'); trvMods.Items.Add(nil, 'Half-Life 2 Deatmatch');
if DirectoryExists(StandaloneServer + 'orangebox\tf') then
trvMods.Items.Add(nil, 'Team Fortress 2');
jspSelectMod.Show; jspSelectMod.Show;
cmdNext.Enabled := False; cmdNext.Enabled := False;
end end
@ -371,16 +444,22 @@ begin
eRegistry.Free; eRegistry.Free;
end; end;
end end
else if frbSelectMod.Checked then begin else if (frbSelectMod.Checked) then begin
{ Custom mod } { Custom mod }
if frmSelectModPath.ShowModal = mrOk then begin if frmSelectModPath.ShowModal = mrOk then begin
ePath := frmSelectModPath.trvDirectory.SelectedFolder.PathName;
{ install now }
jspInstallProgress.Show; jspInstallProgress.Show;
InstallCustom(IncludeTrailingPathDelimiter(frmSelectModPath.trvDirectory.SelectedFolder.PathName), osWindows); InstallCustom(IncludeTrailingPathDelimiter(ePath), osWindows, not frmSelectModPath.chkUsesOrangebox.Checked);
end; end;
end end
else if frbFTP.Checked then // FTP else if (frbFTP.Checked) then begin // FTP
Height := FTPHeight;
jspFTP.Show; jspFTP.Show;
end; end;
end
else
jplWizard.NextPage
end; end;
procedure TfrmMain.CheckNext(Sender: TObject); procedure TfrmMain.CheckNext(Sender: TObject);
@ -390,8 +469,10 @@ end;
procedure TfrmMain.cmdBackClick(Sender: TObject); procedure TfrmMain.cmdBackClick(Sender: TObject);
begin begin
if jplWizard.ActivePage = jspFTP then if jplWizard.ActivePage = jspFTP then begin
jspInstallMethod.Show Height := NormalHeight;
jspInstallMethod.Show;
end
else begin else begin
jplWizard.PrevPage; jplWizard.PrevPage;
cmdBack.Visible := jplWizard.ActivePageIndex <> 0; cmdBack.Visible := jplWizard.ActivePageIndex <> 0;
@ -399,9 +480,9 @@ begin
end; end;
procedure TfrmMain.cmdConnectClick(Sender: TObject); procedure TfrmMain.cmdConnectClick(Sender: TObject);
var i: integer; var i, k: integer;
eStr: TStringList; eStr: TStringList;
CurNode: TTreeNode; CurNode, CurNode2: TTreeNode;
Path: String; Path: String;
begin begin
if (Trim(txtHost.Text) = '') or (Trim(txtUsername.Text) = '') then if (Trim(txtHost.Text) = '') or (Trim(txtUsername.Text) = '') then
@ -432,7 +513,7 @@ begin
eStr := TStringList.Create; eStr := TStringList.Create;
eStr.Text := StringReplace(Path, '/', #13, [rfReplaceAll]); eStr.Text := StringReplace(Path, '/', #13, [rfReplaceAll]);
for i := eStr.Count -1 downto 0 do begin for i := eStr.Count -1 downto 0 do begin
if eStr[i] = '' then if (eStr[i] = '') then
eStr.Delete(i); eStr.Delete(i);
end; end;
if (Copy(Path, Length(Path) -1, 1) <> '/') then if (Copy(Path, Length(Path) -1, 1) <> '/') then
@ -441,47 +522,39 @@ begin
trvDirectories.Enabled := True; trvDirectories.Enabled := True;
cmdConnect.Enabled := True; cmdConnect.Enabled := True;
cmdConnect.Caption := 'Disconnect'; 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 ... // ... find directories in start path ...
if eStr.Count <> 0 then begin CurNode := nil;
for i := 0 to eStr.Count -1 do begin CurNode2 := nil;
if (not ((i = 0) and (Assigned(CurNode)))) then if (eStr.Count <> 0) then begin
CurNode := trvDirectories.Items.AddChild(CurNode, eStr[i]); IdFTP.ChangeDir('/');
for i := 0 to eStr.Count do begin
try
with GetAllDirs do begin
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;
end; end;
trvDirectories.Selected := CurNode;
eStr.Free; eStr.Free;
// ... scan for directories ...
with GetAllDirs do begin
for i := 0 to Count -1 do
trvDirectories.Items.AddChild(trvDirectories.Items.AddChild(CurNode, Strings[i]), 'Scanning...');
Free;
end;
if Assigned(CurNode) then if Assigned(CurNode) then
CurNode.Expand(False); CurNode.Expand(False);

View File

@ -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: How to prepare a release:
1) Copy the latest MM:S dlls and hl2launch.exe into this folder 1) Copy the latest MM:S dlls into this folder
2) Run Attach.exe 2) Append .source to the Source binaries and .orangebox to the OrangeBox binaries
3) Test MMS_Installer.exe once (should work but nobody wants bug releases, especially not in the installer) 3) Run Attach.exe
4) If everything worked fine, release it, otherwise pm me (Basic-Master) 4) Test MMS_Installer.exe once (recommended)
5) Release it or e-Mail me if you find a bug

View File

@ -1,7 +1,7 @@
[PRODUCT] [PRODUCT]
major = 1 major = 1
minor = 4 minor = 4
revision = 0 revision = 4
[sourcemm] [sourcemm]
folder = sourcemm folder = sourcemm

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ======== /* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ======== /* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ======== /* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ======== /* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ======== /* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ======== /* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -153,6 +153,30 @@ public:
return npos; 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 bool is_space(int c) const
{ {
if (c == '\f' || c == '\n' || if (c == '\f' || c == '\n' ||

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -19,39 +19,58 @@ namespace SourceHook
// Vector // Vector
template <class T> class CVector template <class T> class CVector
{ {
bool Grow() bool Grow(size_t amount)
{ {
// automatic grow // automatic grow
size_t newSize = m_Size * 2; size_t newSize = m_Size * 2;
if (newSize == 0) if (newSize == 0)
newSize = 8; // a good init value {
newSize = 8;
}
while (m_CurrentUsedSize + amount > newSize)
{
newSize *= 2;
}
T *newData = new T[newSize]; T *newData = new T[newSize];
if (!newData)
return false;
if (m_Data) if (m_Data)
{ {
for (size_t i=0; i<m_CurrentUsedSize; i++) for (size_t i=0; i<m_CurrentUsedSize; i++)
{
newData[i] = m_Data[i]; newData[i] = m_Data[i];
}
delete [] m_Data; delete [] m_Data;
} }
m_Data = newData; m_Data = newData;
m_Size = newSize; m_Size = newSize;
return true; return true;
} }
bool GrowIfNeeded() bool GrowIfNeeded(size_t amount)
{ {
if (m_CurrentUsedSize >= m_Size) if (m_CurrentUsedSize + amount >= m_Size)
return Grow(); {
return Grow(amount);
}
else else
{
return true; return true;
}
} }
bool ChangeSize(size_t size) bool ChangeSize(size_t size)
{ {
// change size // change size
if (size == m_Size) if (size == m_Size)
{
return true; return true;
}
if (!size) if (!size)
{ {
@ -65,19 +84,24 @@ template <class T> class CVector
} }
T *newData = new T[size]; T *newData = new T[size];
if (!newData)
return false;
if (m_Data) if (m_Data)
{ {
size_t end = (m_CurrentUsedSize < size) ? (m_CurrentUsedSize) : size; size_t end = (m_CurrentUsedSize < size) ? (m_CurrentUsedSize) : size;
for (size_t i=0; i<end; i++) for (size_t i=0; i<end; i++)
{
newData[i] = m_Data[i]; newData[i] = m_Data[i];
}
delete [] m_Data; delete [] m_Data;
} }
m_Data = newData; m_Data = newData;
m_Size = size; m_Size = size;
if (m_CurrentUsedSize > m_Size) if (m_CurrentUsedSize > m_Size)
{
m_CurrentUsedSize = m_Size; m_CurrentUsedSize = m_Size;
}
return true; return true;
} }
@ -85,7 +109,9 @@ template <class T> class CVector
void FreeMemIfPossible() void FreeMemIfPossible()
{ {
if (!m_Data) if (!m_Data)
{
return; return;
}
if (!m_CurrentUsedSize) if (!m_CurrentUsedSize)
{ {
@ -95,10 +121,14 @@ template <class T> class CVector
size_t newSize = m_Size; size_t newSize = m_Size;
while (m_CurrentUsedSize <= newSize / 2) while (m_CurrentUsedSize <= newSize / 2)
{
newSize /= 2; newSize /= 2;
}
if (newSize != m_Size) if (newSize != m_Size)
{
ChangeSize(newSize); ChangeSize(newSize);
}
} }
protected: protected:
T *m_Data; T *m_Data;
@ -321,14 +351,13 @@ public:
bool push_back(const T & elem) bool push_back(const T & elem)
{ {
++m_CurrentUsedSize; if (!GrowIfNeeded(1))
if (!GrowIfNeeded())
{ {
--m_CurrentUsedSize;
return false; return false;
} }
m_Data[m_CurrentUsedSize - 1] = elem; m_Data[m_CurrentUsedSize++] = elem;
return true; return true;
} }
@ -433,13 +462,13 @@ public:
size_t ofs = where - begin(); size_t ofs = where - begin();
++m_CurrentUsedSize; if (!GrowIfNeeded(1))
if (!GrowIfNeeded())
{ {
--m_CurrentUsedSize;
return false; return false;
} }
++m_CurrentUsedSize;
where = begin() + ofs; where = begin() + ofs;
// Move subsequent entries // Move subsequent entries

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ======== /* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -752,11 +752,6 @@ namespace SourceHook
bool CSourceHookImpl::ShouldContinue() 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: // Post-recalls:
// The second element on the stack has recall set to Recall_Post1. // 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 // 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;
} }
} }
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() void CSourceHookImpl::DoRecall()
@ -994,6 +1003,9 @@ namespace SourceHook
ret->Set(m_UsedIters); // m_UsedIters is the last returned and not released iterator 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: ret->Next(); // Use next instead of directly incrementing its m_Iter:
// skips paused plugins // skips paused plugins
// Set the last iterator to END!
m_UsedIters->GoToEnd();
} }
ret->m_pNext = m_UsedIters; ret->m_pNext = m_UsedIters;
@ -1008,6 +1020,8 @@ namespace SourceHook
} }
void CSourceHookImpl::CHookList::ReleaseIter(IIter *pIter) void CSourceHookImpl::CHookList::ReleaseIter(IIter *pIter)
{ {
m_RelFlag = true;
CIter *pIter2 = static_cast<CIter*>(pIter); CIter *pIter2 = static_cast<CIter*>(pIter);
// Unlink from m_UsedIters // Unlink from m_UsedIters
@ -1017,7 +1031,7 @@ namespace SourceHook
if (pIter2->m_pPrev) if (pIter2->m_pPrev)
pIter2->m_pPrev->m_pNext = pIter2->m_pNext; pIter2->m_pPrev->m_pNext = pIter2->m_pNext;
if (pIter2 == m_UsedIters) if (pIter2 == m_UsedIters)
m_UsedIters = NULL; m_UsedIters = m_UsedIters->m_pNext;
// Link to m_FreeIters // Link to m_FreeIters
@ -1048,6 +1062,11 @@ namespace SourceHook
SkipPaused(); SkipPaused();
} }
void CSourceHookImpl::CHookList::CIter::GoToEnd()
{
m_Iter = m_pList->m_List.end();
}
bool CSourceHookImpl::CHookList::CIter::End() bool CSourceHookImpl::CHookList::CIter::End()
{ {
if (!m_pList) if (!m_pList)
@ -1056,7 +1075,7 @@ namespace SourceHook
} }
void CSourceHookImpl::CHookList::CIter::Next() void CSourceHookImpl::CHookList::CIter::Next()
{ {
if (!m_pList) if (!m_pList || m_Iter == m_pList->m_List.end())
return; return;
++m_Iter; ++m_Iter;
SkipPaused(); SkipPaused();

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ======== /* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ======== /* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -257,6 +257,7 @@ namespace SourceHook
virtual ~CIter(); virtual ~CIter();
void GoToBegin(); void GoToBegin();
void GoToEnd();
void Set(CIter *pOther); void Set(CIter *pOther);
bool End(); bool End();
@ -276,6 +277,7 @@ namespace SourceHook
// For recalls // For recalls
bool m_Recall; bool m_Recall;
bool m_RQFlag; bool m_RQFlag;
bool m_RelFlag;
void SetRecallState(); // Sets the list into a state where the next returned void SetRecallState(); // Sets the list into a state where the next returned
// iterator (from GetIter) will be a copy of the last // iterator (from GetIter) will be a copy of the last
@ -283,8 +285,9 @@ namespace SourceHook
// The hook resets this state automatically on: // The hook resets this state automatically on:
// GetIter, ReleaseIter // GetIter, ReleaseIter
void RQFlagReset() { m_RQFlag = false; } void RQFlagReset() { m_RQFlag = false; m_RelFlag = false; }
bool RQFlagGet() { return m_RQFlag; } bool RQFlagGet() { return m_RQFlag; }
bool RelFlagGet() { return m_RelFlag; }
CHookList(); CHookList();
CHookList(const CHookList &other); CHookList(const CHookList &other);
virtual ~CHookList(); virtual ~CHookList();

View File

@ -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 # Makefile written by David "BAILOPAN" Anderson and Pavol Marko
OPT_FLAGS = -O3 -funroll-loops -s -pipe OPT_FLAGS = -O3 -funroll-loops -s -pipe

View File

@ -289,6 +289,9 @@
<File <File
RelativePath="..\testref.cpp"> RelativePath="..\testref.cpp">
</File> </File>
<File
RelativePath="..\testrefret.cpp">
</File>
</Filter> </Filter>
<Filter <Filter
Name="Header Files" Name="Header Files"

View File

@ -109,6 +109,10 @@ bool TestBail(std::string &error)
new State_EatYams_Return(6), new State_EatYams_Return(6),
NULL), "Part 6"); NULL), "Part 6");
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler1, false);
UntestBail2();
delete g_Gabgab; delete g_Gabgab;
return true; return true;

View File

@ -28,6 +28,7 @@ namespace N_TestBail
extern IGaben *g_Gabgab; extern IGaben *g_Gabgab;
bool TestBail2(std::string &error); bool TestBail2(std::string &error);
void UntestBail2();
} }
using namespace N_TestBail; using namespace N_TestBail;

View File

@ -5,6 +5,7 @@
#include "sourcehook_test.h" #include "sourcehook_test.h"
#include "testbail.h" #include "testbail.h"
static unsigned int n_calls = 0;
int EatYams_Handler2(int a) int EatYams_Handler2(int a)
{ {
@ -31,6 +32,18 @@ namespace N_TestBail
CHECK_COND(ret == 6, "Part 2.1"); CHECK_COND(ret == 6, "Part 2.1");
n_calls++;
return true; 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--;
}
}
} }

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ======== /* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -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]; delete pv[i];
} }
@ -104,3 +104,4 @@ bool TestMulti(std::string &error)
return true; return true;
} }

View File

@ -222,5 +222,11 @@ bool TestRecall(std::string &error)
CHECK_COND(a == 0xDEADFC, "Part 5.1"); 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; return true;
} }

View File

@ -159,5 +159,7 @@ bool TestRef(std::string &error)
new State_Result(12), new State_Result(12),
NULL), "Part 4"); NULL), "Part 4");
SH_REMOVE_HOOK_MEMFUNC(CHello, Func, &hello, &hook, &CHook::Func, false);
return true; return true;
} }

View File

@ -196,5 +196,13 @@ bool TestRefRet(std::string &error)
new State_Func2_Ret(&hook.m_Var), // really returned hook.m_Var new State_Func2_Ret(&hook.m_Var), // really returned hook.m_Var
NULL), "Part 7"); 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; return true;
} }

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -12,6 +12,7 @@
#include "CSmmAPI.h" #include "CSmmAPI.h"
#include "sourcemm.h" #include "sourcemm.h"
#include "concommands.h" #include "concommands.h"
#include "vsp_listener.h"
/** /**
* @brief Implements functions from CPlugin.h * @brief Implements functions from CPlugin.h
@ -22,14 +23,14 @@ using namespace SourceMM;
#define ITER_PLEVENT(evn, plid) \ #define ITER_PLEVENT(evn, plid) \
CPluginManager::CPlugin *_Xpl; \ CPluginManager::CPlugin *_Xpl; \
SourceHook::List<IMetamodListener *>::iterator event; \ SourceHook::List<CPluginEventHandler>::iterator event; \
IMetamodListener *api; \ IMetamodListener *api; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \ for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
_Xpl = (*iter); \ _Xpl = (*iter); \
if (_Xpl->m_Id == plid) \ if (_Xpl->m_Id == plid) \
continue; \ continue; \
for (event=_Xpl->m_Events.begin(); event!=_Xpl->m_Events.end(); event++) { \ for (event=_Xpl->m_Events.begin(); event!=_Xpl->m_Events.end(); event++) { \
api = (*event); \ api = (*event).event; \
api->evn(plid); \ 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) bool CPluginManager::Pause(PluginId id, char *error, size_t maxlen)
{ {
CPlugin *pl = FindById(id); CPlugin *pl = FindById(id);
@ -335,7 +368,7 @@ CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source
if (!pl->m_Lib) if (!pl->m_Lib)
{ {
if (error) if (error)
UTIL_Format(error, maxlen, "%s", dlerror()); UTIL_Format(error, maxlen, "[%d]", GetLastError());
pl->m_Status = Pl_Error; pl->m_Status = Pl_Error;
} else { } else {
CreateInterfaceFn pfn = (CreateInterfaceFn)(dlsym(pl->m_Lib, PL_EXPOSURE_C)); 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) //if (pl->m_API->GetApiVersion() >= 4)
pl->m_API->AllPluginsLoaded(); 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 { } else {
pl->m_Status = Pl_Refused; pl->m_Status = Pl_Refused;
} }
@ -496,23 +545,17 @@ bool CPluginManager::UnloadAll()
{ {
PluginIter i; 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]; char error[128];
bool status = true; 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)) ) if ( !_Unload( (*i), true, error, sizeof(error)) )
{
status = false; status = false;
}
} }
m_Plugins.clear();
remqueue.clear();
return status; return status;
} }
@ -622,3 +665,34 @@ void CPluginManager::UnregAllConCmds(CPlugin *pl)
pl->m_Cmds.clear(); 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();
}

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -50,6 +50,13 @@ namespace SourceMM
SourceHook::String alias; SourceHook::String alias;
SourceHook::String value; SourceHook::String value;
}; };
struct CPluginEventHandler
{
bool got_vsp;
IMetamodListener *event;
};
/** /**
* @brief Implements Plugin Manager API * @brief Implements Plugin Manager API
*/ */
@ -72,7 +79,7 @@ namespace SourceMM
HINSTANCE m_Lib; HINSTANCE m_Lib;
SourceHook::List<ConCommandBase *> m_Cvars; SourceHook::List<ConCommandBase *> m_Cvars;
SourceHook::List<ConCommandBase *> m_Cmds; SourceHook::List<ConCommandBase *> m_Cmds;
SourceHook::List<IMetamodListener *> m_Events; SourceHook::List<CPluginEventHandler> m_Events;
}; };
public: public:
CPluginManager(); CPluginManager();
@ -123,6 +130,10 @@ namespace SourceMM
//Internal iterators //Internal iterators
SourceHook::List<SourceMM::CPluginManager::CPlugin *>::iterator _begin(); SourceHook::List<SourceMM::CPluginManager::CPlugin *>::iterator _begin();
SourceHook::List<SourceMM::CPluginManager::CPlugin *>::iterator _end(); SourceHook::List<SourceMM::CPluginManager::CPlugin *>::iterator _end();
void SetVSPAsLoaded();
unsigned int GetPluginCount();
const char *GetStatusText(CPlugin *pl);
private: private:
//These are identical internal functions for the wrappers above. //These are identical internal functions for the wrappers above.
CPlugin *_Load(const char *file, PluginId source, char *error, size_t maxlen); CPlugin *_Load(const char *file, PluginId source, char *error, size_t maxlen);

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -141,8 +141,12 @@ void CSmmAPI::ConPrintf(const char *fmt, ...)
void CSmmAPI::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener) void CSmmAPI::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener)
{ {
CPluginManager::CPlugin *pl = g_PluginMngr.FindByAPI(plugin); 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) 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; CPluginManager::CPlugin *pl;
SourceHook::List<IMetamodListener *>::iterator event; SourceHook::List<CPluginEventHandler>::iterator event;
IMetamodListener *api; IMetamodListener *api;
int ret = 0; int ret = 0;
void *val = NULL; void *val = NULL;
@ -184,7 +188,7 @@ void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
pl = (*iter); pl = (*iter);
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++)
{ {
api = (*event); api = (*event).event;
ret = IFACE_FAILED; ret = IFACE_FAILED;
if ( (val=api->OnMetamodQuery(iface, &ret)) != NULL ) 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 ENGINEW32_OFFS 38
#define IA32_CALL 0xE8 #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 //Thanks to fysh for the idea of extracting info from "echo" and for
// having the original offsets at hand! // having the original offsets at hand!
bool CSmmAPI::CacheCmds() bool CSmmAPI::CacheCmds()
@ -256,20 +244,20 @@ bool CSmmAPI::CacheCmds()
callback = ((ConCommand *)pBase)->GetCallback(); callback = ((ConCommand *)pBase)->GetCallback();
ptr = (unsigned char *)callback; ptr = (unsigned char *)callback;
#ifdef OS_LINUX #ifdef OS_LINUX
if (vcmp(ptr, ENGINE486_SIG, SIGLEN)) if (UTIL_VerifySignature(ptr, ENGINE486_SIG, SIGLEN))
{ {
offs = ENGINE486_OFFS; offs = ENGINE486_OFFS;
} }
else if (vcmp(ptr, ENGINE686_SIG, SIGLEN)) else if (UTIL_VerifySignature(ptr, ENGINE686_SIG, SIGLEN))
{ {
offs = ENGINE686_OFFS; offs = ENGINE686_OFFS;
} }
else if (vcmp(ptr, ENGINEAMD_SIG, SIGLEN)) else if (UTIL_VerifySignature(ptr, ENGINEAMD_SIG, SIGLEN))
{ {
offs = ENGINEAMD_OFFS; offs = ENGINEAMD_OFFS;
} }
#elif defined OS_WIN32 // Only one Windows engine binary so far... #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; offs = ENGINEW32_OFFS;
} }
@ -454,16 +442,40 @@ void CSmmAPI::ClientConPrintf(edict_t *client, const char *fmt, ...)
void CSmmAPI::LoadAsVSP() 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); 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); g_Engine.engine->ServerCommand(command);
} }
void CSmmAPI::EnableVSPListener() void CSmmAPI::EnableVSPListener()
{ {
/* If GameInit already passed and we're not already enabled or loaded, go ahead and LoadAsVSP load */ /* 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(); LoadAsVSP();
} }
@ -492,6 +504,11 @@ int CSmmAPI::GetGameDLLVersion()
#define MSGCLASS2_SIGLEN 16 #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_SIG "\x56\x8B\x74\x24\x2A\x85\xF6\x7C\x2A\x3B\x35\x2A\x2A\x2A\x2A\x7D"
#define MSGCLASS2_OFFS 11 #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 #elif defined OS_LINUX
/* No frame pointer sig */ /* No frame pointer sig */
#define MSGCLASS_SIGLEN 14 #define MSGCLASS_SIGLEN 14
@ -508,45 +525,22 @@ int CSmmAPI::GetGameDLLVersion()
/* :TODO: Make this prettier */ /* :TODO: Make this prettier */
bool CSmmAPI::CacheUserMessages() 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; 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 */ /* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS_OFFS); char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS_OFFS);
/* Get address of CUserMessages::m_UserMessages */ /* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass); 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 #ifdef OS_WIN32
/* If we get here, the code is possibly inlined like in Dystopia */ /* 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 */ /* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass); dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif #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) if (dict)

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -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 Metamod:Source is distributed under the "zLib/libpng" license, which is reproduced
below: below:

View File

@ -1,4 +1,4 @@
#(C)2004-2007 SourceMM Development Team #(C)2004-2008 SourceMM Development Team
# Makefile written by David "BAILOPAN" Anderson # Makefile written by David "BAILOPAN" Anderson
HL2SDK = ../../hl2sdk HL2SDK = ../../hl2sdk
@ -34,7 +34,10 @@ endif
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) 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" ifeq "$(GCC_VERSION)" "4"
CFLAGS += $(GCC4_FLAGS) CFLAGS += $(GCC4_FLAGS)
@ -55,7 +58,7 @@ all:
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY) ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
sourcemm: $(OBJ_LINUX) 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: debug:
$(MAKE) all DEBUG=true $(MAKE) all DEBUG=true

View File

@ -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: 2007/04/05 1.4.0:
- Added API functions for retrieving User Message info without potentially crashing. - Added API functions for retrieving User Message info without potentially crashing.
- Added API functions for letting SourceMM plugins use Valve Server Plugin callbacks. - Added API functions for letting SourceMM plugins use Valve Server Plugin callbacks.

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -9,31 +9,38 @@
*/ */
#include <ctype.h> #include <ctype.h>
#include "convar_smm.h"
#include "CSmmAPI.h" #include "CSmmAPI.h"
#include "concommands.h" #include "concommands.h"
#include "CPlugin.h" #include "CPlugin.h"
#include "sh_string.h" #include "sh_string.h"
#include "sh_list.h" #include "sh_list.h"
#include "vsp_listener.h"
/** /**
* @brief Console Command Implementations * @brief Console Command Implementations
* @file concommands.cpp * @file concommands.cpp
*/ */
CAlwaysRegisterableCommand g_EternalCommand;
SMConVarAccessor g_SMConVarAccessor; SMConVarAccessor g_SMConVarAccessor;
SMConVarAccessor::SMConVarAccessor()
{
m_TopConCommandBase = NULL;
}
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand) bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
{ {
// Add the FCVAR_GAMEDLL flag /* Add the FCVAR_GAMEDLL flag
// => No crash on exit! * => No crash on exit!
// UPDATE: Do _not_ add the FCVAR_GAMEDLL flag here, as it * UPDATE: Do _not_ add the FCVAR_GAMEDLL flag here, as it
// causes the command to be unusable on listenservers until you load a map * 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 * We will set the FCVAR_GAMEDLL flag on all commands we have registered once we are being unloaded
//pCommand->AddFlags(FCVAR_GAMEDLL); */
// pCommand->AddFlags(FCVAR_GAMEDLL);
m_RegisteredCommands.push_back(pCommand); m_RegisteredCommands.push_back(pCommand);
pCommand->SetNext( NULL ); pCommand->SetNext(NULL);
g_Engine.icvar->RegisterConCommandBase(pCommand); g_Engine.icvar->RegisterConCommandBase(pCommand);
return true; return true;
@ -41,8 +48,8 @@ bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
bool SMConVarAccessor::Register(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 ); pCommand->SetNext(NULL);
g_Engine.icvar->RegisterConCommandBase(pCommand); g_Engine.icvar->RegisterConCommandBase(pCommand);
return true; return true;
@ -59,67 +66,52 @@ void SMConVarAccessor::MarkCommandsAsGameDLL()
void SMConVarAccessor::Unregister(ConCommandBase *pCommand) void SMConVarAccessor::Unregister(ConCommandBase *pCommand)
{ {
ICvar *cv = g_Engine.icvar; ConCommandBase *pCur = NULL;
ConCommandBase *ptr = cv->GetCommands(); ConCommandBase *pPrev = NULL;
if (ptr == pCommand) if (!pCommand || !pCommand->IsRegistered())
{ {
//first in list return;
g_EternalCommand.BringToFront(); }
g_EternalCommand.SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
} else { pCur = g_Engine.icvar->GetCommands();
//find us and unregister us pCommand->SetRegistered(false);
ConCommandBase *pPrev = NULL;
while (ptr) if (!m_TopConCommandBase || !pCur)
{ {
if (ptr == pCommand) return;
break; }
pPrev = ptr;
ptr = const_cast<ConCommandBase *>(ptr->GetNext()); if (pCur == pCommand)
} {
if (pPrev && ptr == 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())); pPrev->SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
pCommand->SetNext(NULL);
} }
pPrev = pCur;
pCur = const_cast<ConCommandBase *>(pCur->GetNext());
} }
} }
void SMConVarAccessor::UnregisterGameDLLCommands() ConVar metamod_version("metamod_version", SOURCEMM_VERSION, FCVAR_SPONLY | FCVAR_NOTIFY, "Metamod:Source Version");
{ #ifdef OS_WIN32
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 mm_pluginsfile("mm_pluginsfile", "addons\\metamod\\metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File"); 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 #else
ConVar mm_pluginsfile("mm_pluginsfile", "addons/metamod/metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File"); 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 #endif
CON_COMMAND(meta, "Metamod:Source Menu") CON_COMMAND(meta, "Metamod:Source Menu")
@ -128,6 +120,12 @@ CON_COMMAND(meta, "Metamod:Source Menu")
int args = e->Cmd_Argc(); 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) if (args >= 2)
{ {
const char *command = e->Cmd_Argv(1); 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/Plugins: David \"BAILOPAN\" Anderson\n");
CONMSG(" GameDLL: Scott \"Damaged Soul\" Ehlert\n"); CONMSG(" GameDLL: Scott \"Damaged Soul\" Ehlert\n");
CONMSG("For more information, see the official website\n"); CONMSG("For more information, see the official website\n");
CONMSG("http://www.sourcemm.net/\n"); CONMSG("http://www.metamodsource.net/\n");
return; return;
} else if (strcmp(command, "version") == 0) { } else if (strcmp(command, "version") == 0) {
CONMSG("Metamod:Source version %s\n", SOURCEMM_VERSION); 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("Compiled on: %s\n", SOURCEMM_DATE);
CONMSG("Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION); 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("SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
CONMSG("http://www.sourcemm.net/\n"); CONMSG("http://www.metamodsource.net/\n");
return; return;
} else if (strcmp(command, "game") == 0) { } else if (strcmp(command, "game") == 0) {
@ -191,59 +197,63 @@ CON_COMMAND(meta, "Metamod:Source Menu")
return; return;
} else if (strcmp(command, "list") == 0) { } else if (strcmp(command, "list") == 0) {
SourceMM::CPluginManager::CPlugin *pl; size_t len;
PluginIter i; PluginIter i;
const char *status=""; char buffer[255];
const char *version=NULL; ISmmPlugin *plapi;
const char *name=NULL; const char *plname;
const char *author=NULL; 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++) for (i=g_PluginMngr._begin(); i!=g_PluginMngr._end(); i++)
{ {
pl = (*i); pl = (*i);
if (!pl) if (!pl)
{
break; break;
if (pl->m_Status == Pl_Paused)
{
status = "PAUSE";
} else if (pl->m_Status == Pl_Running) {
if (pl->m_API && pl->m_API->QueryRunning(NULL, 0))
status = "RUN";
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) len = 0;
if (pl->m_Status != Pl_Running)
{ {
version = pl->m_API->GetVersion(); len += UTIL_Format(buffer, sizeof(buffer), " [%02d] <%s>", pl->m_Id, g_PluginMngr.GetStatusText(pl));
author = pl->m_API->GetAuthor(); }
name = pl->m_API->GetName(); else
} else { {
version = "-"; len += UTIL_Format(buffer, sizeof(buffer), " [%02d]", pl->m_Id);
author = "-";
name = "-";
} }
if (!version) if ((plapi = pl->m_API))
version = "-"; {
if (!author) plname = IS_STR_FILLED(plapi->GetName()) ? plapi->GetName() : pl->m_File.c_str();
author = "-"; len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " %s", plname);
if (!name)
name = pl->m_File.c_str();
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("[%02d] %-20.19s %-10.9s %-20.19s %-8.7s\n", pl->m_Id, name, version, author, status); CONMSG("%s\n", buffer);
} }
//CONMSG("\n");
return; return;
} else if (strcmp(command, "cmds") == 0) { } else if (strcmp(command, "cmds") == 0) {
if (args >= 3) if (args >= 3)
@ -625,53 +635,6 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG(" version - Version information\n"); 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) void ClientCommand_handler(edict_t *client)
{ {
IVEngineServer *e = g_Engine.engine; 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, "Metamod:Source was developed by:\n");
CLIENT_CONMSG(client, " SourceHook: Pavol \"PM OnoTo\" Marko\n"); CLIENT_CONMSG(client, " SourceHook: Pavol \"PM OnoTo\" Marko\n");
CLIENT_CONMSG(client, " GameDLL/Plugins: David \"BAILOPAN\" Anderson\n"); CLIENT_CONMSG(client, " Core: David \"BAILOPAN\" Anderson\n");
CLIENT_CONMSG(client, " GameDLL: Scott \"Damaged Soul\" Ehlert\n"); CLIENT_CONMSG(client, " Core: Scott \"Damaged Soul\" Ehlert\n");
CLIENT_CONMSG(client, "For more information, see the official website\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); RETURN_META(MRES_SUPERCEDE);
} else if(strcmp(subcmd, "version") == 0) { } 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, "Compiled on: %s\n", SOURCEMM_DATE);
CLIENT_CONMSG(client, "Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION); 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, "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); RETURN_META(MRES_SUPERCEDE);
} else if(strcmp(subcmd, "list") == 0) { } else if(strcmp(subcmd, "list") == 0) {
SourceMM::CPluginManager::CPlugin *pl; SourceMM::CPluginManager::CPlugin *pl;
Pl_Status st; ISmmPlugin *plapi;
const char *plname;
PluginIter i; PluginIter i;
const char *version = NULL; char buffer[256];
const char *name = NULL; int len = 0;
const char *author = NULL; int plnum = 0;
const char *status = NULL;
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++, len=0)
for (i=g_PluginMngr._begin(); i!=g_PluginMngr._end(); i++)
{ {
pl = (*i); pl = (*i);
if (!pl) if (pl && pl->m_Status == Pl_Running)
break;
st = pl->m_Status;
/* Only show plugins that are running or paused */
if (pl->m_API && (st == Pl_Running || st == Pl_Paused))
{ {
version = pl->m_API->GetVersion(); plapi = pl->m_API;
author = pl->m_API->GetAuthor(); if (!plapi || !plapi->QueryRunning(NULL, 0))
name = pl->m_API->GetName();
if (st == Pl_Running && pl->m_API->QueryRunning(NULL, 0))
{ {
status = "RUN"; continue;
} else { }
status = "PAUSE"; 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) CLIENT_CONMSG(client, "%s\n", buffer);
break;
CLIENT_CONMSG(client, "[%02d] %-20.19s %-10.9s %-20.19s %6s\n", pl->m_Id, name, version, author, status);
} }
} }
if (!plnum)
{
CLIENT_CONMSG(client, "No active plugins loaded.\n");
}
RETURN_META(MRES_SUPERCEDE); RETURN_META(MRES_SUPERCEDE);
} }
} }
@ -758,7 +725,79 @@ void ClientCommand_handler(edict_t *client)
RETURN_META(MRES_IGNORED); RETURN_META(MRES_IGNORED);
} }
void SMConVarAccessor::UnloadMetamodCommands()
{
Unregister(&metamod_version);
Unregister(&mm_pluginsfile);
Unregister(&mm_basedir);
Unregister(&meta_command);
}
const char *GetPluginsFile() const char *GetPluginsFile()
{ {
return mm_pluginsfile.GetString(); 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;
}

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -16,37 +16,28 @@
* @file concommands.h * @file concommands.h
*/ */
#include <interface.h>
#include <eiface.h>
#include "sourcemm.h"
#include "convar_smm.h" #include "convar_smm.h"
#include "sourcemm.h"
#include "sh_list.h" #include "sh_list.h"
class SMConVarAccessor : public IConCommandBaseAccessor class SMConVarAccessor : public IConCommandBaseAccessor
{ {
SourceHook::List<ConCommandBase*> m_RegisteredCommands; SourceHook::List<ConCommandBase*> m_RegisteredCommands;
ConCommandBase **m_TopConCommandBase;
public: public:
SMConVarAccessor();
virtual bool RegisterConCommandBase(ConCommandBase *pCommand); virtual bool RegisterConCommandBase(ConCommandBase *pCommand);
bool Register(ConCommandBase *pCommand); bool Register(ConCommandBase *pCommand);
void MarkCommandsAsGameDLL(); void MarkCommandsAsGameDLL();
bool InitConCommandBaseList();
void Unregister(ConCommandBase *pCommand); void Unregister(ConCommandBase *pCommand);
void UnregisterGameDLLCommands(); void UnloadMetamodCommands();
};
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 ClientCommand_handler(edict_t *client); void ClientCommand_handler(edict_t *client);
const char *GetPluginsFile(); const char *GetPluginsFile();
const char *GetMetamodBaseDir();
extern SMConVarAccessor g_SMConVarAccessor; extern SMConVarAccessor g_SMConVarAccessor;

View File

@ -198,6 +198,11 @@ protected:
// ConVars in this executable use this 'global' to access values. // ConVars in this executable use this 'global' to access values.
static IConCommandBaseAccessor *s_pAccessor; static IConCommandBaseAccessor *s_pAccessor;
public:
inline void SetRegistered(bool registered)
{
m_bRegistered = registered;
}
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -242,7 +247,7 @@ private:
FnCommandCompletionCallback m_fnCompletionCallback; FnCommandCompletionCallback m_fnCompletionCallback;
bool m_bHasCompletionCallback; bool m_bHasCompletionCallback;
public: public:
FnCommandCallback GetCallback() { return m_fnCommandCallback; } inline FnCommandCallback GetCallback() { return m_fnCommandCallback; }
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -41,6 +41,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="&quot;$(HL2SDK)\public&quot;;&quot;$(HL2SDK)\public\dlls&quot;;&quot;$(HL2SDK)\public\engine&quot;;&quot;$(HL2SDK)\public\tier0&quot;;&quot;$(HL2SDK)\public\tier1&quot;;&quot;$(HL2SDK)\public\vstdlib&quot;;..\..;..\..\sourcehook"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
@ -62,7 +63,7 @@
/> />
<Tool <Tool
Name="VCLinkerTool" Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib" AdditionalDependencies="&quot;$(HL2SDK)\lib\public\tier0.lib&quot; &quot;$(HL2SDK)\lib\public\tier1.lib&quot; &quot;$(HL2SDK)\lib\public\vstdlib.lib&quot;"
OutputFile="$(OutDir)/server.dll" OutputFile="$(OutDir)/server.dll"
LinkIncremental="2" LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib" IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
@ -126,6 +127,7 @@
Optimization="3" Optimization="3"
FavorSizeOrSpeed="1" FavorSizeOrSpeed="1"
OmitFramePointers="true" OmitFramePointers="true"
AdditionalIncludeDirectories="&quot;$(HL2SDK)\public&quot;;&quot;$(HL2SDK)\public\dlls&quot;;&quot;$(HL2SDK)\public\engine&quot;;&quot;$(HL2SDK)\public\tier0&quot;;&quot;$(HL2SDK)\public\tier1&quot;;&quot;$(HL2SDK)\public\vstdlib&quot;;..\..;..\..\sourcehook"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SOURCEMM_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true" StringPooling="true"
ExceptionHandling="1" ExceptionHandling="1"
@ -148,7 +150,7 @@
/> />
<Tool <Tool
Name="VCLinkerTool" Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib" AdditionalDependencies="&quot;$(HL2SDK)\lib\public\tier0.lib&quot; &quot;$(HL2SDK)\lib\public\tier1.lib&quot; &quot;$(HL2SDK)\lib\public\vstdlib.lib&quot;"
OutputFile="$(OutDir)/server.dll" OutputFile="$(OutDir)/server.dll"
LinkIncremental="1" LinkIncremental="1"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib" 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" Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
> >
<File
RelativePath="..\svn_version.tpl"
>
</File>
<File <File
RelativePath="..\version.rc" RelativePath="..\version.rc"
> >

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -16,17 +16,29 @@
#include "oslink.h" #include "oslink.h"
#ifdef __linux #ifdef __linux
#include <errno.h> #include <errno.h>
#include <stdio.h>
#endif #endif
#include <stdio.h>
#if defined __WIN32__ || defined _WIN32 || defined WIN32 #if defined __WIN32__ || defined _WIN32 || defined WIN32
const char *dlerror() const char *dlerror()
{ {
static char buf[1024]; static char buf[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, DWORD num;
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), num = GetLastError();
(LPTSTR) &buf, 0, NULL);
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
num,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf,
sizeof(buf),
NULL)
== 0)
{
_snprintf(buf, sizeof(buf), "unknown error %x", num);
}
return buf; return buf;
} }
#endif #endif

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -56,7 +56,7 @@
#endif #endif
#if defined __linux__ #if defined __linux__
extern int errno; #include <errno.h>
int GetLastError(); int GetLastError();
#endif #endif

View File

@ -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 Metamod:Source is distributed under the "zLib/libpng" license, which is reproduced
below: below:

View File

@ -1,4 +1,4 @@
#(C)2004-2007 SourceMM Development Team #(C)2004-2008 SourceMM Development Team
# Makefile written by David "BAILOPAN" Anderson # Makefile written by David "BAILOPAN" Anderson
HL2SDK = ../../../hl2sdk HL2SDK = ../../../hl2sdk

View File

@ -1,5 +1,5 @@
/* ======== sample_mm ======== /* ======== sample_mm ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== sample_mm ======== /* ======== sample_mm ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== sample_mm ======== /* ======== sample_mm ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== sample_mm ======== /* ======== sample_mm ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -41,6 +41,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="&quot;$(SOURCEMM14)&quot;;&quot;$(SOURCEMM14)\sourcemm&quot;;&quot;$(SOURCEMM14)\sourcehook&quot;;&quot;$(HL2SDK)\public&quot;;&quot;$(HL2SDK)\public\dlls&quot;;&quot;$(HL2SDK)\public\engine&quot;;&quot;$(HL2SDK)\public\tier0&quot;;&quot;$(HL2SDK)\public\tier1&quot;;&quot;$(HL2SDK)\public\vstdlib&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
@ -62,7 +63,7 @@
/> />
<Tool <Tool
Name="VCLinkerTool" Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib" AdditionalDependencies="&quot;$(HL2SDK)\lib\public\tier0.lib&quot; &quot;$(HL2SDK)\lib\public\tier1.lib&quot; &quot;$(HL2SDK)\lib\public\vstdlib.lib&quot;"
OutputFile="$(OutDir)/sample_mm.dll" OutputFile="$(OutDir)/sample_mm.dll"
LinkIncremental="2" LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib" IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
@ -122,6 +123,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(SOURCEMM14)&quot;;&quot;$(SOURCEMM14)\sourcemm&quot;;&quot;$(SOURCEMM14)\sourcehook&quot;;&quot;$(HL2SDK)\public&quot;;&quot;$(HL2SDK)\public\dlls&quot;;&quot;$(HL2SDK)\public\engine&quot;;&quot;$(HL2SDK)\public\tier0&quot;;&quot;$(HL2SDK)\public\tier1&quot;;&quot;$(HL2SDK)\public\vstdlib&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SAMPLE_MM_EXPORTS"
RuntimeLibrary="0" RuntimeLibrary="0"
RuntimeTypeInfo="false" RuntimeTypeInfo="false"
@ -142,7 +144,7 @@
/> />
<Tool <Tool
Name="VCLinkerTool" Name="VCLinkerTool"
AdditionalDependencies="tier0.lib tier1.lib vstdlib.lib" AdditionalDependencies="&quot;$(HL2SDK)\lib\public\tier0.lib&quot; &quot;$(HL2SDK)\lib\public\tier1.lib&quot; &quot;$(HL2SDK)\lib\public\vstdlib.lib&quot;"
OutputFile="$(OutDir)/sample_mm.dll" OutputFile="$(OutDir)/sample_mm.dll"
LinkIncremental="1" LinkIncremental="1"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib" IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -19,6 +19,8 @@
#include "CPlugin.h" #include "CPlugin.h"
#include "util.h" #include "util.h"
#include "vsp_listener.h" #include "vsp_listener.h"
#include "iplayerinfo.h"
#include <filesystem.h>
using namespace SourceMM; using namespace SourceMM;
@ -43,6 +45,8 @@ void DLLShutdown_handler();
void LevelShutdown_handler(); void LevelShutdown_handler();
bool LevelInit_handler(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background); bool LevelInit_handler(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
bool GameInit_handler(); 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}; GameDllInfo g_GameDll = {false, NULL, NULL, NULL, NULL};
EngineInfo g_Engine; EngineInfo g_Engine;
@ -57,24 +61,28 @@ bool gParsedGameInfo = false;
bool bGameInit = false; bool bGameInit = false;
SourceHook::List<GameDllInfo *> gamedll_list; SourceHook::List<GameDllInfo *> gamedll_list;
SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch; SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
SourceHook::CallClass<ICvar> *g_CvarPatch;
int g_GameDllVersion = 0; int g_GameDllVersion = 0;
const char VSPIFACE_001[] = "ISERVERPLUGINCALLBACKS001"; const char VSPIFACE_001[] = "ISERVERPLUGINCALLBACKS001";
const char VSPIFACE_002[] = "ISERVERPLUGINCALLBACKS002"; const char VSPIFACE_002[] = "ISERVERPLUGINCALLBACKS002";
const char GAMEINFO_PATH[] = "|gameinfo_path|"; const char GAMEINFO_PATH[] = "|gameinfo_path|";
IFileSystem *baseFs = NULL;
bool g_bLevelChanged = false;
void ClearGamedllList(); void ClearGamedllList();
/* Helper Macro */ /* Helper Macro */
#define IFACE_MACRO(orig,nam) \ #define IFACE_MACRO(orig,nam) \
CPluginManager::CPlugin *pl; \ CPluginManager::CPlugin *pl; \
SourceHook::List<IMetamodListener *>::iterator event; \ SourceHook::List<CPluginEventHandler>::iterator event; \
IMetamodListener *api; \ IMetamodListener *api; \
int mret = 0; \ int mret = 0; \
void *val = NULL; \ void *val = NULL; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \ for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
pl = (*iter); \ pl = (*iter); \
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \ for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
api = (*event); \ api = (*event).event; \
mret = IFACE_FAILED; \ mret = IFACE_FAILED; \
if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \ if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \
if (ret) *ret = mret; \ if (ret) *ret = mret; \
@ -86,12 +94,12 @@ void ClearGamedllList();
#define ITER_EVENT(evn, args) \ #define ITER_EVENT(evn, args) \
CPluginManager::CPlugin *pl; \ CPluginManager::CPlugin *pl; \
SourceHook::List<IMetamodListener *>::iterator event; \ SourceHook::List<CPluginEventHandler>::iterator event; \
IMetamodListener *api; \ IMetamodListener *api; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \ for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
pl = (*iter); \ pl = (*iter); \
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \ for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
api = (*event); \ api = (*event).event; \
api->evn args; \ 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, LevelShutdown, g_GameDll.pGameDLL, LevelShutdown_handler, true);
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelInit, g_GameDll.pGameDLL, LevelInit_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); 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; const char *pluginFile = g_Engine.icvar->GetCommandLineValue("mm_pluginsfile");
g_Engine.fileSystemFactory = filesystemFactory; const char *mmBaseDir = g_Engine.icvar->GetCommandLineValue("mm_basedir");
g_Engine.physicsFactory = physicsFactory;
g_Engine.pGlobals = pGlobals;
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)); g_Engine.engine = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL));
if (!g_Engine.engine) if (!g_Engine.engine)
{ {
Error("Could not find IVEngineServer! Metamod cannot load."); Error("Could not find IVEngineServer! Metamod cannot load.");
@ -152,10 +169,24 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory,
g_Engine.loaded = true; 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)); ConCommandBaseMgr::OneTimeInit(static_cast<IConCommandBaseAccessor *>(&g_SMConVarAccessor));
g_GameDllPatch = SH_GET_CALLCLASS(g_GameDll.pGameDLL); 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()) 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."); LogMessage("[META] Warning: The 'meta game' command will not display user messages.");
} }
const char *pluginFile = g_Engine.icvar->GetCommandLineValue("mm_pluginsfile"); baseFs = (IFileSystem *)((engineFactory)(FILESYSTEM_INTERFACE_VERSION, NULL));
if (!pluginFile) if (baseFs == NULL)
{ {
pluginFile = GetPluginsFile(); LogMessage("[META] Failed to find filesystem interface, .vdf files will not be parsed.");
} }
char full_path[260]; if (!g_SMConVarAccessor.InitConCommandBaseList())
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), pluginFile); {
/* 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.");
}
LoadPluginsFromFile(full_path); if (!bWaitForGameInit)
{
DoInitialPluginLoads();
bInFirstLevel = true;
}
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); 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() bool GameInit_handler()
{ {
if (bGameInit) if (bGameInit)
{ {
return true; RETURN_META_VALUE(MRES_IGNORED, true);
} }
if (g_SmmAPI.VSPEnabled()) if (g_SmmAPI.VSPEnabled() && !g_VspListener.IsRootLoadMethod())
{ {
g_SmmAPI.LoadAsVSP(); g_SmmAPI.LoadAsVSP();
} }
if (g_VspListener.IsRootLoadMethod())
{
DoInitialPluginLoads();
//gaben
}
bGameInit = true; bGameInit = true;
RETURN_META_VALUE(MRES_IGNORED, 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 */ /* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */
if (strcmp(iface, PLAPI_NAME) == 0) 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) if (ret)
{ {
@ -240,6 +364,12 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
return &g_VspListener; return &g_VspListener;
} }
/* If we're a VSP, bypass this by default */
if (g_VspListener.IsRootLoadMethod())
{
IFACE_MACRO(g_GameDll.factory, GameDLL);
}
if (!gParsedGameInfo) if (!gParsedGameInfo)
{ {
gParsedGameInfo = true; gParsedGameInfo = true;
@ -373,7 +503,6 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
pInfo->lib = gamedll; pInfo->lib = gamedll;
pInfo->loaded = true; pInfo->loaded = true;
pInfo->pGameDLL = NULL; pInfo->pGameDLL = NULL;
pInfo->pGameClients = (IServerGameClients *)((fn)(INTERFACEVERSION_SERVERGAMECLIENTS, NULL));
gamedll_list.push_back(pInfo); gamedll_list.push_back(pInfo);
break; 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 */ /* If we got here, there's definitely a GameDLL */
IFACE_MACRO(g_GameDll.factory, GameDLL); IFACE_MACRO(g_GameDll.factory, GameDLL);
} }
@ -465,29 +603,212 @@ void ClearGamedllList()
gamedll_list.clear(); gamedll_list.clear();
} }
void DLLShutdown_handler() void UnloadMetamod(bool shutting_down)
{ {
/* Unload plugins */ /* Unload plugins */
g_PluginMngr.UnloadAll(); g_PluginMngr.UnloadAll();
/* Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly */ if (shutting_down)
g_SMConVarAccessor.MarkCommandsAsGameDLL(); {
g_SMConVarAccessor.UnregisterGameDLLCommands(); /* Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly */
g_SMConVarAccessor.MarkCommandsAsGameDLL();
g_Engine.icvar->UnlinkVariables(FCVAR_GAMEDLL);
SH_CALL(g_GameDllPatch, &IServerGameDLL::DLLShutdown)(); SH_CALL(g_GameDllPatch, &IServerGameDLL::DLLShutdown)();
}
SH_RELEASE_CALLCLASS(g_GameDllPatch); SH_RELEASE_CALLCLASS(g_GameDllPatch);
SH_RELEASE_CALLCLASS(g_CvarPatch);
g_GameDllPatch = NULL; g_GameDllPatch = NULL;
g_CvarPatch = NULL;
g_SourceHook.CompleteShutdown(); g_SourceHook.CompleteShutdown();
if (g_GameDll.lib && g_GameDll.loaded) if (g_GameDll.lib && g_GameDll.loaded)
{
dlclose(g_GameDll.lib); dlclose(g_GameDll.lib);
}
memset(&g_GameDll, 0, sizeof(GameDllInfo)); memset(&g_GameDll, 0, sizeof(GameDllInfo));
}
void DLLShutdown_handler()
{
UnloadMetamod(true);
RETURN_META(MRES_SUPERCEDE); 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) int LoadPluginsFromFile(const char *_file)
{ {
FILE *fp; FILE *fp;
@ -505,21 +826,22 @@ int LoadPluginsFromFile(const char *_file)
char buffer[255], error[255], full_path[255]; char buffer[255], error[255], full_path[255];
const char *ptr, *ext, *file; const char *ptr, *ext, *file;
size_t length; 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_TrimLeft(buffer);
UTIL_TrimRight(buffer); UTIL_TrimRight(buffer);
if (buffer[0] == '\0' || buffer[0] == ';' || strncmp(buffer, "//", 2) == 0) length = strlen(buffer);
if (!length)
{
continue; continue;
}
if (buffer[0] == '\0' || buffer[0] == ';' || strncmp(buffer, "//", 2) == 0)
{
continue;
}
file = buffer; file = buffer;
if (buffer[0] == '"') if (buffer[0] == '"')
{ {
@ -535,7 +857,9 @@ int LoadPluginsFromFile(const char *_file)
} }
cptr++; cptr++;
} }
} else { }
else
{
char *cptr = buffer; char *cptr = buffer;
while (*cptr) while (*cptr)
{ {
@ -543,7 +867,9 @@ int LoadPluginsFromFile(const char *_file)
{ {
char *optr = cptr; char *optr = cptr;
while (*cptr && isspace(*cptr)) while (*cptr && isspace(*cptr))
{
cptr++; cptr++;
}
*optr = '\0'; *optr = '\0';
UTIL_TrimRight(cptr); UTIL_TrimRight(cptr);
if (*cptr && isalpha(*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) if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
{ {
LogMessage("[META] Failed to load plugin %s. %s", buffer, error); LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
} else {
if (already)
skipped++;
else
total++;
} }
} else { else
{
if (already)
{
skipped++;
}
else
{
total++;
}
}
}
else
{
/* Attempt to find a file extension */ /* Attempt to find a file extension */
ptr = UTIL_GetExtension(file); ptr = UTIL_GetExtension(file);
/* Add an extension if there's none there */ /* Add an extension if there's none there */
@ -585,7 +919,9 @@ int LoadPluginsFromFile(const char *_file)
#else #else
ext = "_i486.so"; ext = "_i486.so";
#endif #endif
} else { }
else
{
ext = ""; ext = "";
} }
/* Format the new path */ /* Format the new path */
@ -594,11 +930,17 @@ int LoadPluginsFromFile(const char *_file)
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused) if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
{ {
LogMessage("[META] Failed to load plugin %s. %s", buffer, error); LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
} else { }
else
{
if (already) if (already)
{
skipped++; skipped++;
}
else else
{
total++; total++;
}
} }
} }
} }
@ -607,13 +949,16 @@ int LoadPluginsFromFile(const char *_file)
if (skipped) if (skipped)
{ {
LogMessage("[META] Loaded %d plugins from file (%d already loaded)", total, skipped); LogMessage("[META] Loaded %d plugins from file (%d already loaded)", total, skipped);
} else { }
else
{
LogMessage("[META] Loaded %d plugins from file.", total); LogMessage("[META] Loaded %d plugins from file.", total);
} }
return total; return total;
} }
/* Wrapper function. This is called when the GameDLL thinks it's using /* Wrapper function. This is called when the GameDLL thinks it's using
* the engine's real engineFactory. * the engine's real engineFactory.
*/ */
@ -663,13 +1008,20 @@ void LevelShutdown_handler(void)
if (!bInFirstLevel) if (!bInFirstLevel)
{ {
char full_path[255]; 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); 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; bInFirstLevel = false;
} }
g_bLevelChanged = true;
ITER_EVENT(OnLevelShutdown, ()); ITER_EVENT(OnLevelShutdown, ());
RETURN_META(MRES_IGNORED); RETURN_META(MRES_IGNORED);

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -74,11 +74,12 @@ struct GameDllInfo
/** @brief Stores information about the HL2 Engine pointers */ /** @brief Stores information about the HL2 Engine pointers */
struct EngineInfo struct EngineInfo
{ {
EngineInfo() : loaded(false), EngineInfo() : loaded(false), original(false),
engineFactory(NULL), physicsFactory(NULL), fileSystemFactory(NULL), engineFactory(NULL), physicsFactory(NULL), fileSystemFactory(NULL),
pGlobals(NULL), icvar(NULL), engine(NULL) pGlobals(NULL), icvar(NULL), engine(NULL)
{ }; { };
bool loaded; bool loaded;
bool original;
CreateInterfaceFn engineFactory; CreateInterfaceFn engineFactory;
CreateInterfaceFn physicsFactory; CreateInterfaceFn physicsFactory;
CreateInterfaceFn fileSystemFactory; CreateInterfaceFn fileSystemFactory;
@ -87,6 +88,8 @@ struct EngineInfo
IVEngineServer *engine; IVEngineServer *engine;
}; };
bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn serverFactory);
/** @brief Global variable for GameDLL info */ /** @brief Global variable for GameDLL info */
extern GameDllInfo g_GameDll; extern GameDllInfo g_GameDll;
@ -115,8 +118,14 @@ extern PluginId g_PLID;
extern int g_GameDllVersion; extern int g_GameDllVersion;
extern bool bGameInit; extern bool bGameInit;
extern bool g_bLevelChanged;
void UnloadMetamod(bool shutting_down);
/** @brief Global CallClass for IServerGameDLL */ /** @brief Global CallClass for IServerGameDLL */
extern SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch; extern SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
/** @brief Global CallClass for ICvar */
extern SourceHook::CallClass<ICvar> *g_CvarPatch;
#endif //_INCLUDE_SOURCEMM_H #endif //_INCLUDE_SOURCEMM_H

View File

@ -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 Metamod:Source is distributed under the "zLib/libpng" license, which is reproduced
below: below:

View File

@ -1,4 +1,4 @@
#(C)2004-2007 SourceMM Development Team #(C)2004-2008 SourceMM Development Team
# Makefile written by David "BAILOPAN" Anderson # Makefile written by David "BAILOPAN" Anderson
HL2SDK = ../../../hl2sdk HL2SDK = ../../../hl2sdk

View File

@ -41,6 +41,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="&quot;$(SOURCEMM14)&quot;;&quot;$(SOURCEMM14)\sourcemm&quot;;&quot;$(SOURCEMM14)\sourcehook&quot;;&quot;$(HL2SDK)\public&quot;;&quot;$(HL2SDK)\public\dlls&quot;;&quot;$(HL2SDK)\public\engine&quot;;&quot;$(HL2SDK)\public\tier0&quot;;&quot;$(HL2SDK)\public\tier1&quot;;&quot;$(HL2SDK)\public\vstdlib&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
@ -62,7 +63,7 @@
/> />
<Tool <Tool
Name="VCLinkerTool" Name="VCLinkerTool"
AdditionalDependencies="tier0.lib" AdditionalDependencies="&quot;$(HL2SDK)\lib\public\tier0.lib&quot;"
ShowProgress="0" ShowProgress="0"
OutputFile="$(OutDir)/stub_mm.dll" OutputFile="$(OutDir)/stub_mm.dll"
LinkIncremental="2" LinkIncremental="2"
@ -123,6 +124,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(SOURCEMM14)&quot;;&quot;$(SOURCEMM14)\sourcemm&quot;;&quot;$(SOURCEMM14)\sourcehook&quot;;&quot;$(HL2SDK)\public&quot;;&quot;$(HL2SDK)\public\dlls&quot;;&quot;$(HL2SDK)\public\engine&quot;;&quot;$(HL2SDK)\public\tier0&quot;;&quot;$(HL2SDK)\public\tier1&quot;;&quot;$(HL2SDK)\public\vstdlib&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS" PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;STUB_MM_EXPORTS"
RuntimeLibrary="0" RuntimeLibrary="0"
RuntimeTypeInfo="false" RuntimeTypeInfo="false"
@ -142,7 +144,7 @@
/> />
<Tool <Tool
Name="VCLinkerTool" Name="VCLinkerTool"
AdditionalDependencies="tier0.lib" AdditionalDependencies="&quot;$(HL2SDK)\lib\public\tier0.lib&quot;"
OutputFile="$(OutDir)/stub_mm.dll" OutputFile="$(OutDir)/stub_mm.dll"
LinkIncremental="1" LinkIncremental="1"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib" IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"

View File

@ -1,5 +1,5 @@
/* ======== stub_mm ======== /* ======== stub_mm ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -1,5 +1,5 @@
/* ======== stub_mm ======== /* ======== stub_mm ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng

View File

@ -3,11 +3,11 @@
#ifndef _INCLUDE_SVN_VERSION_H_ #ifndef _INCLUDE_SVN_VERSION_H_
#define _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 705
#define SVN_REVISION_STRING "346" #define SVN_REVISION_STRING "705"
#define SVN_FILE_VERSION 1,4,0,346 #define SVN_FILE_VERSION 1,4,4,705
#define SVN_FILE_VERSION_STRING "1.4.0.346" #define SVN_FILE_VERSION_STRING "1.4.4.705"
#endif //_INCLUDE_SVN_VERSION_H_ #endif //_INCLUDE_SVN_VERSION_H_

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -239,3 +239,186 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
return len; 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;
}

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -12,12 +12,15 @@
#define _INCLUDE_UTIL_H #define _INCLUDE_UTIL_H
#include <stdarg.h> #include <stdarg.h>
#include <sourcehook/sourcehook.h>
/** /**
* @brief Utility functions * @brief Utility functions
* @file util.h * @file util.h
*/ */
#define IA32_JMP_IMM32 '\xE9'
/** /**
* @brief Returns a pointer to the extension in a file name. * @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. * @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 UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params);
{
size_t len = vsnprintf(buffer, maxlength, fmt, 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)
{
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)
{ {
len = maxlength - 1; /* Get virtual function address 'manually' then */
buffer[len] = '\0'; 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 #endif //_INCLUDE_UTIL_H

View File

@ -47,7 +47,7 @@ BEGIN
VALUE "FileDescription", "Metamod: Source" VALUE "FileDescription", "Metamod: Source"
VALUE "FileVersion", SVN_FILE_VERSION_STRING VALUE "FileVersion", SVN_FILE_VERSION_STRING
VALUE "InternalName", "sourcemm" 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 "OriginalFilename", "server.dll"
VALUE "ProductName", "Metamod: Source" VALUE "ProductName", "Metamod: Source"
VALUE "ProductVersion", SVN_PRODUCT_VERSION VALUE "ProductVersion", SVN_PRODUCT_VERSION
@ -99,3 +99,4 @@ END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED #endif // not APSTUDIO_INVOKED

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -10,15 +10,31 @@
#include "vsp_listener.h" #include "vsp_listener.h"
#include "CPlugin.h" #include "CPlugin.h"
#include "concommands.h"
SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
using namespace SourceMM; using namespace SourceMM;
VSPListener g_VspListener; VSPListener g_VspListener;
ConCommand *g_plugin_unload = NULL;
bool g_bIsTryingToUnload;
void InterceptPluginUnloads()
{
g_bIsTryingToUnload = true;
}
void InterceptPluginUnloads_Post()
{
g_bIsTryingToUnload = false;
}
VSPListener::VSPListener() VSPListener::VSPListener()
{ {
m_Loaded = false; m_Loaded = false;
m_Loadable = false; m_Loadable = false;
m_bIsRootLoadMethod = false;
} }
void VSPListener::ClientActive(edict_t *pEntity) void VSPListener::ClientActive(edict_t *pEntity)
@ -92,6 +108,25 @@ void VSPListener::ServerActivate(edict_t *pEdictList, int edictCount, int client
void VSPListener::Unload() 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) void VSPListener::SetLoadable(bool set)
@ -99,53 +134,60 @@ void VSPListener::SetLoadable(bool set)
m_Loadable = set; m_Loadable = set;
} }
bool VSPListener::IsRootLoadMethod()
{
return m_bIsRootLoadMethod;
}
bool VSPListener::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) 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) if (m_Loaded)
{ {
return false; 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; m_Loaded = true;
SetLoadable(false); SetLoadable(false);
PluginIter iter; if (!m_bIsRootLoadMethod)
CPluginManager::CPlugin *pPlugin;
SourceHook::List<IMetamodListener *>::iterator event;
IMetamodListener *pML;
for (iter=g_PluginMngr._begin(); iter!=g_PluginMngr._end(); iter++)
{ {
pPlugin = (*iter); g_PluginMngr.SetVSPAsLoaded();
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);
}
} }
return true; return true;

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ======== /* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team * Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind * No warranties of any kind
* *
* License: zlib/libpng * License: zlib/libpng
@ -39,9 +39,11 @@ public:
public: public:
bool IsLoaded(); bool IsLoaded();
void SetLoadable(bool loadable); void SetLoadable(bool loadable);
bool IsRootLoadMethod();
private: private:
bool m_Loaded; bool m_Loaded;
bool m_Loadable; bool m_Loadable;
bool m_bIsRootLoadMethod;
}; };
extern VSPListener g_VspListener; extern VSPListener g_VspListener;

View File

@ -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)

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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"
}

View File

@ -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

View File

@ -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;
}