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
-$M16384,1048576
-K$00400000
-LE"c:\programme\borland\delphi7\Projects\Bpl"
-LN"c:\programme\borland\delphi7\Projects\Bpl"
-LE"c:\program files\borland\delphi7\Projects\Bpl"
-LN"c:\program files\borland\delphi7\Projects\Bpl"
-w-UNSAFE_TYPE
-w-UNSAFE_CODE
-w-UNSAFE_CAST

View File

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

Binary file not shown.

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
-$M16384,1048576
-K$00400000
-LE"c:\program files (x86)\borland\delphi7\Projects\Bpl"
-LN"c:\program files (x86)\borland\delphi7\Projects\Bpl"
-LE"c:\program files\borland\delphi7\Projects\Bpl"
-LN"c:\program files\borland\delphi7\Projects\Bpl"
-w-UNSAFE_TYPE
-w-UNSAFE_CODE
-w-UNSAFE_CAST

Binary file not shown.

View File

@ -10,6 +10,8 @@ function GetAllFiles(Mask: String; Attr: Integer; Recursive: Boolean; ShowDirs:
// ftp
function GetAllDirs: TStringList;
function GetModName(const Path: String): String;
implementation
uses UnitfrmMain;
@ -121,6 +123,20 @@ begin
Result := eList;
end; }
function GetModName(const Path: String): String;
var i: integer;
begin
Result := '';
for i := Length(Path) -1 downto 1 do begin
if (Path[i] = '\') or (Path[i] = '/') then begin
Result := Copy(Path, i +1, Length(Path) -i);
break;
end;
end;
if (Copy(Result, Length(Result), 1) = '\') or (Copy(Result, Length(Result), 1) = '/') then
Result := Copy(Result, 1, Length(Result) -1);
end;
end.

View File

@ -13,11 +13,11 @@ procedure AddSkipped;
procedure AddNotFound;
procedure DownloadFile(eFile: String; eDestination: String);
procedure BasicInstallation(ePath: String; SteamInstall, ListenInstall: Boolean; OS: TOS);
procedure InstallDedicated(eModPath: String; UseSteam: Boolean);
procedure InstallListen(ePath: String);
procedure InstallCustom(ePath: String; eOS: TOS);
procedure InstallFTP(OS: TOS);
procedure BasicInstallation(ePath: String; SteamInstall, ListenInstall: Boolean; OS: TOS; const Source: Boolean);
procedure InstallDedicated(eModPath: String; const UseSteam, Source: Boolean);
procedure InstallListen(ePath: String; const Source: Boolean);
procedure InstallCustom(ePath: String; eOS: TOS; const Source: Boolean);
procedure InstallFTP(OS: TOS; const Source: Boolean; const ModDir: String);
var StartTime: TDateTime;
SteamPath: String;
@ -32,7 +32,7 @@ uses UnitfrmMain, UnitfrmProxy, UnitFunctions, UnitPackSystem;
function InstallTime: String;
begin
Result := FormatDateTime('HH:MM:SS', Now - StartTime);
Result := Copy(FormatDateTime('HH:MM:SS', Now - StartTime), 4, 5);
end;
procedure AddStatus(Text: String; Color: TColor; ShowTime: Boolean = True);
@ -218,18 +218,16 @@ end;
{ Basic Installation }
procedure BasicInstallation(ePath: String; SteamInstall, ListenInstall: Boolean; OS: TOS);
procedure BasicInstallation(ePath: String; SteamInstall, ListenInstall: Boolean; OS: TOS; const Source: Boolean);
var eStr: TStringList;
i: integer;
CopyConfig: Boolean;
eFound: Boolean;
begin
frmMain.ggeAll.MaxValue := 8;
frmMain.ggeAll.Progress := 0;
frmMain.ggeItem.MaxValue := 1;
frmMain.ggeItem.Progress := 0;
if (GetProcessID('Steam.exe') <> -1) and (SteamInstall) then begin
{if (GetProcessID('Steam.exe') <> -1) and (SteamInstall) then begin
if MessageBox(frmMain.Handle, 'Steam is still running. It is necersarry to shut it down before you install Metamod:Source. Shut it down now?', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNO) = mrYes then begin
AddStatus('Shutting down Steam...', clBlack, False);
if GetProcessID('Steam.exe') = -1 then
@ -247,13 +245,13 @@ begin
Application.Terminate;
exit;
end;
end;
end;}
frmMain.ggeAll.Progress := 1;
frmMain.ggeItem.Progress := 1;
{ Unpack }
frmMain.ggeItem.Progress := 0;
AddStatus('Unpacking files...', clBlack);
if not Unpack() then begin
if not Unpack(Source) then begin
AddStatus('No files attached!', clRed);
Screen.Cursor := crDefault;
exit;
@ -265,8 +263,8 @@ begin
CopyConfig := True;
AddStatus('Creating directories...', clBlack);
if DirectoryExists(ePath + 'addons\metamod\bin') then begin
case MessageBox(frmMain.Handle, 'A Metamod:Source installation was already detected. If you choose to reinstall, your configuration files will be erased. Click Yes to continue, No to Upgrade, or Cancel to abort the install.', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNOCANCEL) of
mrNo: CopyConfig := False;
case MessageBox(frmMain.Handle, 'A Metamod:Source installation was already detected. If you choose to reinstall, your configuration files will be erased. Click Yes to upgrade, No to reinstall, or Cancel to abort the installation.', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNOCANCEL) of
mrYes: CopyConfig := False;
mrCancel: begin
Application.Terminate;
exit;
@ -282,7 +280,7 @@ begin
frmMain.ggeItem.Progress := 1;
frmMain.ggeAll.Progress := 3;
{ gameinfo.txt }
{ gameinfo.txt for check / create VDF file }
if not FileExists(ePath + 'gameinfo.txt') then begin
if MessageBox(frmMain.Handle, 'The file "gameinfo.txt" couldn''t be found. Continue installation?', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNO) = mrNo then begin
AddStatus('Installation canceled by user!', clRed, False);
@ -304,33 +302,32 @@ begin
AddSkipped;
frmMain.ggeItem.Progress := 1;
frmMain.ggeAll.Progress := 4;
{ Gameinfo.txt }
{ CDF Plugin }
frmMain.ggeItem.Progress := 0;
eFound := False;
AddStatus('Editing gameinfo.txt...', clBlack);
eStr.LoadFromFile(ePath + 'gameinfo.txt');
for i := 0 to eStr.Count -1 do begin
if Trim(LowerCase(eStr[i])) = 'gamebin |gameinfo_path|addons/metamod/bin' then begin
eFound := True;
break;
AddStatus('Creating VDF Plugin...', clBlack);
if (FileExists(ePath + 'addons\metamod.vdf')) then begin
eStr.LoadFromFile(ePath + 'addons\metamod.vdf');
if (Pos('server.dll', eStr.Text) <> 0) then
AddSkipped
else begin
eStr.Add('');
eStr.Add('"Plugin"');
eStr.Add('{');
eStr.Add(' "file" "..\' + GetModName(ePath) + '\addons\metamod\bin\server.dll"');
eStr.Add('}');
eStr.SaveToFile(ePath + 'addons\metamod.vdf');
AddDone;
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
else
AddSkipped;
else begin
eStr.Add('');
eStr.Add('"Plugin"');
eStr.Add('{');
eStr.Add(' "file" "..\' + GetModName(ePath) + '\addons\metamod\bin\server.dll"');
eStr.Add('}');
eStr.SaveToFile(ePath + 'addons\metamod.vdf');
AddDone;
end;
eStr.Free;
frmMain.ggeItem.Progress := 1;
frmMain.ggeAll.Progress := 5;
@ -342,16 +339,9 @@ begin
AddDone;
frmMain.ggeItem.Progress := 1;
frmMain.ggeAll.Progress := 6;
if ListenInstall then begin
ePath := ExtractFilePath(Copy(ePath, 1, Length(ePath)-1));
AddStatus('Copying hl2launch.exe...', clBlack);
CopyFile(PChar(ExtractFilePath(ParamStr(0)) + 'hl2launch.exe'), PChar(ePath + 'hl2launch.exe'), False);
AddDone;
end;
{ Remove files }
frmMain.ggeItem.Progress := 0;
AddStatus('Removing temporary files...', clBlack);
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'hl2launch.exe'));
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server.dll'));
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server_i486.so'));
AddDone;
@ -363,44 +353,41 @@ begin
frmMain.cmdNext.Enabled := True;
frmMain.cmdCancel.Hide;
Screen.Cursor := crDefault;
if ListenInstall then
MessageBox(frmMain.Handle, PChar('hl2launch.exe has been copied to ' + ePath + '. You can use it if you want to start your Source game with Metamod:Source enabled.'), PChar(Application.Title), MB_ICONINFORMATION);
end;
{ Dedicated Server }
procedure InstallDedicated(eModPath: String; UseSteam: Boolean);
procedure InstallDedicated(eModPath: String; const UseSteam, Source: Boolean);
begin
StartTime := Now;
Screen.Cursor := crHourGlass;
AddStatus('Starting Metamod:Source installation on dedicated server...', clBlack, False);
BasicInstallation(eModPath, UseSteam, False, osWindows);
BasicInstallation(eModPath, UseSteam, False, osWindows, Source);
end;
{ Listen Server }
procedure InstallListen(ePath: String);
procedure InstallListen(ePath: String; const Source: Boolean);
begin
StartTime := Now;
Screen.Cursor := crHourGlass;
AddStatus('Starting Metamod:Source installation on the listen server...', clBlack);
BasicInstallation(ePath, True, True, osWindows);
BasicInstallation(ePath, True, True, osWindows, Source);
end;
{ Custom mod }
procedure InstallCustom(ePath: String; eOS: TOS);
procedure InstallCustom(ePath: String; eOS: TOS; const Source: Boolean);
begin
StartTime := Now;
Screen.Cursor := crHourGlass;
AddStatus('Starting Metamod:Source installation...', clBlack);
BasicInstallation(ePath, False, False, eOS);
BasicInstallation(ePath, False, False, eOS, Source);
end;
{ FTP }
procedure InstallFTP(OS: TOS);
procedure InstallFTP(OS: TOS; const Source: Boolean; const ModDir: String);
function DoReconnect: Boolean;
begin
Result := False;
@ -414,11 +401,13 @@ begin
end;
end;
label CreateAgain;
label UploadAgain;
var eStr: TStringList;
i: integer;
CopyConfig, eFound: Boolean;
CopyConfig, CommentFound: Boolean;
i: Integer;
begin
frmMain.cmdCancel.Show;
frmMain.cmdNext.Hide;
@ -426,72 +415,27 @@ begin
frmMain.ggeAll.MaxValue := 6;
frmMain.ggeAll.Progress := 0;
frmMain.ggeItem.MaxValue := 1;
frmMain.ggeItem.MaxValue := 3;
frmMain.ggeItem.Progress := 0;
StartTime := Now;
{ Unpack }
frmMain.ggeItem.Progress := 0;
AddStatus('Unpacking files...', clBlack);
if not Unpack() then begin
if not Unpack(Source) then begin
AddStatus('No files attached!', clRed);
Screen.Cursor := crDefault;
exit;
end;
AddDone;
frmMain.ggeAll.Progress := 2;
frmMain.ggeAll.Progress := 1;
frmMain.ggeItem.Progress := 1;
{ Check for installation }
AddStatus('Editing gameinfo.txt...', clBlack);
eStr := TStringList.Create;
DownloadFile('gameinfo.txt', ExtractFilePath(ParamStr(0)) + 'gameinfo.txt');
eStr.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'gameinfo.txt');
CopyConfig := True;
eFound := False;
for i := 0 to eStr.Count -1 do begin
if Trim(LowerCase(eStr[i])) = 'gamebin |gameinfo_path|addons/metamod/bin' then begin
eFound := True;
case MessageBox(frmMain.Handle, 'A Metamod:Source installation was already detected. If you choose to reinstall, your configuration files will be erased. Click Yes to continue, No to Upgrade, or Cancel to abort the install.', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNOCANCEL) of
mrNo: CopyConfig := False;
mrCancel: begin
Application.Terminate;
eStr.Free;
exit;
end;
end;
break;
end;
end;
if not eFound then begin
for i := 0 to eStr.Count -1 do begin
if Trim(eStr[i]) = 'SearchPaths' then begin
eStr.Insert(i +2, ' GameBin |gameinfo_path|addons/metamod/bin');
AddDone;
break;
end;
end;
eStr.SaveToFile(ExtractFilePath(ParamStr(0)) + 'gameinfo.txt');
UploadFile(ExtractFilePath(ParamStr(0)) + 'gameinfo.txt', 'gameinfo.txt');
try
AddStatus('Trying to set gameinfo.txt to read-only...', clBlack);
frmMain.IdFTP.Site('CHMOD 744 gameinfo.txt');
AddDone;
except
AddStatus('Warning: CHMOD not supported.', clMaroon);
end;
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'gameinfo.txt'));
end
else
AddSkipped;
frmMain.ggeAll.Progress := 3;
frmMain.ggeItem.Progress := 1;
Sleep(250);
{ Create directories }
frmMain.ggeAll.Progress := 2;
frmMain.ggeItem.Progress := 0;
frmMain.ggeItem.MaxValue := 3;
AddStatus('Creating directories...', clBlack);
if not eFound then begin
try
FTPMakeDir('addons');
frmMain.IdFTP.ChangeDir('addons');
frmMain.ggeItem.Progress := 1;
@ -501,24 +445,108 @@ begin
FTPMakeDir('bin');
frmMain.ggeItem.Progress := 3;
AddDone;
end
else
except
AddSkipped;
frmMain.ggeAll.Progress := 4;
end;
{ Check VDF Plugin }
CopyConfig := True;
frmMain.ggeAll.Progress := 3;
frmMain.ggeItem.Progress := 0;
AddStatus('Creating VDF Plugin...', clBlack);
eStr := TStringList.Create;
try
frmMain.IdFTP.ChangeDirUp;
frmMain.ggeItem.Progress := 1;
DownloadFile('metamod.vdf', ExtractFilePath(ParamStr(0)) + 'metamod.vdf');
eStr.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'metamod.vdf');
frmMain.ggeItem.Progress := 2;
if (((Pos('server.dll', eStr.Text) <> 0) and (OS = osWindows)) or ((Pos('server_i486.so', eStr.Text) <> 0) and (OS = osLinux))) then begin
case MessageBox(frmMain.Handle, 'A Metamod:Source installation was already detected. If you choose to reinstall, your configuration files will be erased. Click Yes to upgrade, No to reinstall, or Cancel to abort the installation.', PChar(frmMain.Caption), MB_ICONQUESTION + MB_YESNOCANCEL) of
mrYes: CopyConfig := False;
mrCancel: begin
Application.Terminate;
eStr.Free;
exit;
end;
end;
end;
except
// bacon
end;
{ Create and Upload plugin here }
frmMain.ggeItem.Progress := 2;
eStr.Clear;
eStr.Add('"Plugin"');
eStr.Add('{');
if (OS = osWindows) then
eStr.Add(' "file" "..\' + ModDir + '\addons\metamod\bin\server.dll"')
else
eStr.Add(' "file" "../' + ModDir + '/addons/metamod/bin/server_i486.so"');
eStr.Add('}');
eStr.SaveToFile(ExtractFilePath(ParamStr(0)) + 'metamod.vdf');
UploadFile(ExtractFilePath(ParamStr(0)) + 'metamod.vdf', 'metamod.vdf');
frmMain.ggeItem.Progress := 3;
{ Upload metaplugins.ini }
frmMain.ggeAll.Progress := 4;
frmMain.ggeItem.MaxValue := 1;
frmMain.ggeItem.Progress := 0;
AddStatus('Uploading metaplugins.ini...', clBlack);
if CopyConfig then begin
frmMain.IdFTP.ChangeDir('metamod');
if (CopyConfig) then begin
eStr.Clear;
// see http://svn.alliedmods.net/viewvc.cgi/metamodsource/orangebox/addons/metamod/metaplugins.ini?revision=1099&root=Packages
eStr.Add(';List one plugin per line. Each line should contain the path to the plugin''s binary.');
eStr.Add(';Any line starting with a '';'' character is a comment line, and is ignored.');
eStr.Add(';');
eStr.Add(';You do not need to include the _i486.so or .dll part of the file name. Example:');
eStr.Add('; addons/sourcemod/bin/sourcemod_mm');
eStr.Add(';You may also put an alias in front of the file, for example:');
eStr.Add('; sm addons/sourcemod/bin/sourcemod_mm');
eStr.Add(';Will allow you to use "meta load sm" from the console.');
eStr.Add(';');
eStr.Add(';********* LIST PLUGINS BELOW ***********');
// end
eStr.SaveToFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini');
UploadFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini', 'metaplugins.ini');
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini'));
end
else
AddSkipped;
else if (frmMain.IdFTP.Size('metaplugins.ini') <> -1) then begin
DownloadFile('metaplugins.ini', ExtractFilePath(ParamStr(0)) + 'metaplugins.ini');
eStr.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini');
CommentFound := False;
for i := 0 to eStr.Count -1 do begin
if (Pos(';', eStr[i]) = 1) then begin
CommentFound := True;
break;
end;
end;
if (CommentFound) then
AddSkipped
else begin
// delete empty lines first
for i := eStr.Count -1 downto 0 do begin
if (Trim(eStr[i]) = '') then
eStr.Delete(i);
end;
// see http://svn.alliedmods.net/viewvc.cgi/metamodsource/orangebox/addons/metamod/metaplugins.ini?revision=1099&root=Packages
eStr.Insert(0, ';List one plugin per line. Each line should contain the path to the plugin''s binary.');
eStr.Insert(1, ';Any line starting with a '';'' character is a comment line, and is ignored.');
eStr.Insert(2, ';');
eStr.Insert(3, ';You do not need to include the _i486.so or .dll part of the file name. Example:');
eStr.Insert(4, '; addons/sourcemod/bin/sourcemod_mm');
eStr.Insert(5, ';You may also put an alias in front of the file, for example:');
eStr.Insert(6, '; sm addons/sourcemod/bin/sourcemod_mm');
eStr.Insert(7, ';Will allow you to use "meta load sm" from the console.');
eStr.Insert(8, ';');
eStr.Insert(9, ';********* LIST PLUGINS BELOW ***********');
// end
eStr.SaveToFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini');
UploadFile(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini', 'metaplugins.ini');
end;
end;
frmMain.ggeAll.Progress := 5;
frmMain.ggeItem.Progress := 1;
{ Upload server.dll / server_i486.so }
@ -537,9 +565,10 @@ begin
end;
{ Remove created files }
AddStatus('Removing temporary files...', clBlack);
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'hl2launch.exe'));
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server.dll'));
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'server_i486.so'));
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'metamod.vdf'));
DeleteFile(PChar(ExtractFilePath(ParamStr(0)) + 'metaplugins.ini'));
AddDone;
{ End }
frmMain.IdFTP.Disconnect;

View File

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

Binary file not shown.

View File

@ -5,7 +5,7 @@ interface
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
StdCtrls, ExtCtrls, Forms, FileCtrl, ComCtrls, ShellCtrls,
TFlatComboBoxUnit, TFlatButtonUnit;
TFlatComboBoxUnit, TFlatButtonUnit, TFlatCheckBoxUnit;
type
TfrmSelectModPath = class(TForm)
@ -14,6 +14,8 @@ type
trvDirectory: TShellTreeView;
cmdOK: TFlatButton;
cmdCancel: TFlatButton;
chkUsesOrangebox: TFlatCheckBox;
procedure trvDirectoryClick(Sender: TObject);
end;
var
@ -23,4 +25,11 @@ implementation
{$R *.DFM}
procedure TfrmSelectModPath.trvDirectoryClick(Sender: TObject);
begin
// !! OrangeBox Check !!
if (trvDirectory.Selected <> nil) then
chkUsesOrangebox.Checked := (chkUsesOrangebox.Checked) or (trvDirectory.Selected.Text = 'tf');
end;
end.

View File

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

View File

@ -63,7 +63,7 @@ type
cmdConnect: TFlatButton;
pnlDirectory: TPanel;
trvDirectories: TTreeView;
lblStep4: TLabel;
lblStep5: TLabel;
jspInstallProgress: TJvStandardPage;
pnlHeader5: TPanel;
imgIcon4: TImage;
@ -101,6 +101,11 @@ type
shpMods: TShape;
trvMods: TTreeView;
FlatRadioButton1: TFlatRadioButton;
pnlEngineType: TPanel;
optAutoDetect: TFlatRadioButton;
optSource: TFlatRadioButton;
optOrangeBox: TFlatRadioButton;
lblStep4: TLabel;
procedure jvwStepsCancelButtonClick(Sender: TObject);
procedure cmdCancelClick(Sender: TObject);
procedure cmdNextClick(Sender: TObject);
@ -136,6 +141,9 @@ var
var VERSION: String = '<none>';
const NormalHeight = 382;
FTPHeight = 422;
implementation
uses UnitFunctions, UnitfrmProxy, UnitInstall, UnitSelectModPath;
@ -159,10 +167,11 @@ var ePath: String;
CurNode: TTreeNode;
eOS: TOS;
i: integer;
Source: Boolean;
begin
{ FTP }
if jplWizard.ActivePage = jspFTP then begin
if not IdFTP.Connected then
if (jplWizard.ActivePage = jspFTP) then begin
if (not IdFTP.Connected) then
IdFTP.Connect;
eStr := TStringList.Create;
ePath := '/';
@ -175,14 +184,22 @@ begin
end;
IdFTP.ChangeDir(ePath);
IdFTP.List(eStr, '', False);
if eStr.IndexOf('gameinfo.txt') = -1 then begin
eStr.CaseSensitive := False;
// check if gameinfo.txt is in the directory -> valid installation
if (eStr.IndexOf('gameinfo.txt') = -1) then begin
MessageBox(Handle, 'Invalid directory. Please select your mod directory and try again.', PChar(Application.Title), MB_ICONWARNING);
eStr.Free;
exit;
end
else
eStr.Free;
// check for orangebox directory (!! OrangeBox Check !!)
if (optAutoDetect.Checked) then
Source := not ((AnsiSameText(trvDirectories.Selected.Text, 'tf')) or (Pos('orangebox', LowerCase(ePath)) <> 0))
else if (optSource.Checked) then
Source := True
else
Source := False;
// design stuff
trvDirectories.Enabled := False;
cmdConnect.Enabled := False;
@ -190,81 +207,131 @@ begin
optLinux.Enabled := False;
Screen.Cursor := crHourGlass;
if optWindows.Checked then
eOS := osWindows
else
if (optWindows.Checked) then begin
eOS := osWindows;
if (Source) then
rtfDetails.Lines.Text := '* Installing Source binaries for Windows' + #13#10 + #13#10
else
rtfDetails.Lines.Text := '* Installing OrangeBox binaries for Windows' + #13#10 + #13#10
end
else begin
eOS := osLinux;
if (Source) then
rtfDetails.Lines.Text := '* Installing Source binaries for Linux' + #13#10 + #13#10
else
rtfDetails.Lines.Text := '* Installing OrangeBox binaries for Linux' + #13#10 + #13#10
end;
jspInstallProgress.Show;
// installation
Screen.Cursor := crAppStart;
InstallFTP(eOS);
InstallFTP(eOS, Source, trvDirectories.Selected.Text);
end
else if jplWizard.ActivePage = jspInstallProgress then
else if (jplWizard.ActivePage = jspInstallProgress) then
Close
else if jplWizard.ActivePage = jspSelectMod then begin
else if (jplWizard.ActivePage = jspSelectMod) then begin
{ Dedicated Server }
if (frbDedicatedServer.Checked) or (frbStandaloneServer.Checked) then begin
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;
if ePath = 'Counter-Strike:Source' then
ePath := 'cstrike'
else if ePath = 'Day of Defeat:Source' then
ePath := 'dod'
else
ePath := 'hl2mp';
ePath := 'SteamApps\' + trvMods.Selected.Parent.Text + '\source dedicated server\' + ePath;
// install it
if frbDedicatedServer.Checked then begin
if DirectoryExists(SteamPath + ePath) then begin
jspInstallProgress.Show;
InstallDedicated(IncludeTrailingPathDelimiter(SteamPath + ePath), True);
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;
else if ePath = 'Half-Life 2 Deathmatch' then
ePath := 'hl2mp'
else begin
{ get games }
if (ePath = 'Team Fortress 2') then
ePath := 'orangebox\tf';
{ ask user, just in case }
case MessageBox(Handle, 'It looks like your server is using the OrangeBox engine. Would you like to install the appropriate binaries for it?', PChar(Application.Title), MB_ICONQUESTION + MB_YESNOCANCEL) of
mrYes: Source := False;
mrNo: Source := True;
mrCancel: exit;
end;
end;
// install it
if (DirectoryExists(StandaloneServer + ePath)) then begin
jspInstallProgress.Show;
InstallDedicated(IncludeTrailingPathDelimiter(StandaloneServer + ePath), False, Source)
end
else begin
if DirectoryExists(StandaloneServer + ePath) then begin
jspInstallProgress.Show;
InstallDedicated(IncludeTrailingPathDelimiter(StandaloneServer + ePath), False)
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;
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;
{ Listen Server }
if frbListenServer.Checked then begin
if (frbListenServer.Checked) then begin
Source := True;
ePath := trvMods.Selected.Text;
if ePath = 'Counter-Strike:Source' then
if (ePath = 'Counter-Strike:Source') then
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\counter-strike source\cstrike'
else if ePath = 'Half-Life 2 Deathmatch' then
else if (ePath = 'Half-Life 2 Deathmatch') then
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\half-life 2 deathmatch\hl2mp'
else
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\day of defeat source\dod';
else if ePath = 'Day of Defeat:Source' then
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\day of defeat source\dod'
else begin
{ get games }
if (ePath = 'Team Fortress 2') then
ePath := SteamPath + 'SteamApps\' + trvMods.Selected.Parent.Text + '\team fortress 2\tf';
{ ask user, just in case }
case MessageBox(Handle, 'It looks like your server is using the OrangeBox engine. Would you like to install the appropriate binaries for it?', PChar(Application.Title), MB_ICONQUESTION + MB_YESNOCANCEL) of
mrYes: Source := False;
mrNo: Source := True;
mrCancel: exit;
end;
end;
if Pos(SteamPath, ePath) = 0 then
if (Pos(SteamPath, ePath) = 0) then
MessageBox(Handle, 'An error occured. Please report this bug to the Metamod:Source team and post a new thread on the forums of www.amxmodx.org.', PChar(Application.Title), MB_ICONSTOP)
else begin
if not FileExists(ePath + '\gameinfo.txt') then begin
if (not FileExists(ePath + '\gameinfo.txt')) then begin
MessageBox(Handle, 'You have to play this game once before installing Metamod:Source. Do that and try again.', PChar(Application.Title), MB_ICONWARNING);
exit;
end;
jspInstallProgress.Show;
InstallListen(IncludeTrailingPathDelimiter(ePath));
InstallListen(IncludeTrailingPathDelimiter(ePath), Source);
end;
end;
{ Custom mod below }
end
else if jplWizard.ActivePage <> jspInstallMethod then
jplWizard.NextPage
else begin
if frbDedicatedServer.Checked then begin // Dedicated Server
else if (jplWizard.ActivePage = jspInstallMethod) then begin
if (frbDedicatedServer.Checked) then begin // Dedicated Server
eRegistry := TRegistry.Create(KEY_READ);
try
eRegistry.RootKey := HKEY_CURRENT_USER;
@ -274,19 +341,21 @@ begin
SteamPath := ePath;
ePath := ePath + 'SteamApps\';
if DirectoryExists(ePath) then begin
if (DirectoryExists(ePath)) then begin
trvMods.Items.Clear;
// Check Mods
eStr := GetAllFiles(ePath + '*.*', faDirectory, False, True, False);
for i := 0 to eStr.Count -1 do begin
CurNode := trvMods.Items.Add(nil, eStr[i]);
if DirectoryExists(ePath + eStr[i] + '\source dedicated server\cstrike') then
if (DirectoryExists(ePath + eStr[i] + '\source dedicated server\cstrike')) then
trvMods.Items.AddChild(CurNode, 'Counter-Strike:Source');
if DirectoryExists(ePath + eStr[i] + '\source dedicated server\dod') then
if (DirectoryExists(ePath + eStr[i] + '\source dedicated server\dod')) then
trvMods.Items.AddChild(CurNode, 'Day of Defeat:Source');
if DirectoryExists(ePath + eStr[i] + '\source dedicated server\hl2mp') then
if (DirectoryExists(ePath + eStr[i] + '\source dedicated server\hl2mp')) then
trvMods.Items.AddChild(CurNode, 'Half-Life 2 Deatmatch');
if (DirectoryExists(ePath + eStr[i] + '\source 2007 dedicated server\tf')) then
trvMods.Items.AddChild(CurNode, 'Team Fortress 2');
if CurNode.Count = 0 then
CurNode.Free
@ -307,11 +376,11 @@ begin
eRegistry.Free;
end;
end
else if frbListenServer.Checked then begin // Listen Server
else if (frbListenServer.Checked) then begin // Listen Server
eRegistry := TRegistry.Create(KEY_READ);
try
eRegistry.RootKey := HKEY_CURRENT_USER;
if eRegistry.OpenKey('Software\Valve\Steam', False) then begin
if (eRegistry.OpenKey('Software\Valve\Steam', False)) then begin
ePath := eRegistry.ReadString('SteamPath');
ePath := IncludeTrailingPathDelimiter(StringReplace(ePath, '/', '\', [rfReplaceAll]));
SteamPath := ePath;
@ -330,6 +399,8 @@ begin
trvMods.Items.AddChild(CurNode, 'Day of Defeat:Source');
if DirectoryExists(ePath + eStr[i] + '\half-life 2 deathmatch') then
trvMods.Items.AddChild(CurNode, 'Half-Life 2 Deatmatch');
if DirectoryExists(ePath + eStr[i] + '\team fortress 2') then
trvMods.Items.AddChild(CurNode, 'Team Fortress 2');
if CurNode.Count = 0 then
CurNode.Free
@ -350,7 +421,7 @@ begin
eRegistry.Free;
end;
end
else if frbStandaloneServer.Checked then begin // Standalone Server
else if (frbStandaloneServer.Checked) then begin // Standalone Server
eRegistry := TRegistry.Create;
try
eRegistry.RootKey := HKEY_CURRENT_USER;
@ -362,6 +433,8 @@ begin
trvMods.Items.Add(nil, 'Day of Defeat:Source');
if DirectoryExists(StandaloneServer + 'hl2mp') then
trvMods.Items.Add(nil, 'Half-Life 2 Deatmatch');
if DirectoryExists(StandaloneServer + 'orangebox\tf') then
trvMods.Items.Add(nil, 'Team Fortress 2');
jspSelectMod.Show;
cmdNext.Enabled := False;
end
@ -371,16 +444,22 @@ begin
eRegistry.Free;
end;
end
else if frbSelectMod.Checked then begin
else if (frbSelectMod.Checked) then begin
{ Custom mod }
if frmSelectModPath.ShowModal = mrOk then begin
ePath := frmSelectModPath.trvDirectory.SelectedFolder.PathName;
{ install now }
jspInstallProgress.Show;
InstallCustom(IncludeTrailingPathDelimiter(frmSelectModPath.trvDirectory.SelectedFolder.PathName), osWindows);
InstallCustom(IncludeTrailingPathDelimiter(ePath), osWindows, not frmSelectModPath.chkUsesOrangebox.Checked);
end;
end
else if frbFTP.Checked then // FTP
else if (frbFTP.Checked) then begin // FTP
Height := FTPHeight;
jspFTP.Show;
end;
end;
end
else
jplWizard.NextPage
end;
procedure TfrmMain.CheckNext(Sender: TObject);
@ -390,8 +469,10 @@ end;
procedure TfrmMain.cmdBackClick(Sender: TObject);
begin
if jplWizard.ActivePage = jspFTP then
jspInstallMethod.Show
if jplWizard.ActivePage = jspFTP then begin
Height := NormalHeight;
jspInstallMethod.Show;
end
else begin
jplWizard.PrevPage;
cmdBack.Visible := jplWizard.ActivePageIndex <> 0;
@ -399,9 +480,9 @@ begin
end;
procedure TfrmMain.cmdConnectClick(Sender: TObject);
var i: integer;
var i, k: integer;
eStr: TStringList;
CurNode: TTreeNode;
CurNode, CurNode2: TTreeNode;
Path: String;
begin
if (Trim(txtHost.Text) = '') or (Trim(txtUsername.Text) = '') then
@ -432,7 +513,7 @@ begin
eStr := TStringList.Create;
eStr.Text := StringReplace(Path, '/', #13, [rfReplaceAll]);
for i := eStr.Count -1 downto 0 do begin
if eStr[i] = '' then
if (eStr[i] = '') then
eStr.Delete(i);
end;
if (Copy(Path, Length(Path) -1, 1) <> '/') then
@ -441,47 +522,39 @@ begin
trvDirectories.Enabled := True;
cmdConnect.Enabled := True;
cmdConnect.Caption := 'Disconnect';
// ... change to / and create all the directories ...
CurNode := nil;
if (Path <> '/') then begin
try
IdFTP.ChangeDir('/');
with GetAllDirs do begin
for i := 0 to Count -1 do begin
if (Assigned(CurNode)) then
trvDirectories.Items.AddChild(trvDirectories.Items.Add(nil, Strings[i]), 'Scanning...')
else begin
CurNode := trvDirectories.Items.Add(nil, Strings[i]);
trvDirectories.Items.AddChild(CurNode, 'Scanning...');
if (Pos('/' + CurNode.Text + '/', Path) = 0) then
CurNode := nil;
end
end;
Free;
end;
IdFTP.ChangeDir(Path);
except
if (IdFTP.Connected) then
IdFTP.ChangeDir(Path)
else
IdFTP.Connect;
end;
end;
// ... find directories in start path ...
if eStr.Count <> 0 then begin
for i := 0 to eStr.Count -1 do begin
if (not ((i = 0) and (Assigned(CurNode)))) then
CurNode := trvDirectories.Items.AddChild(CurNode, eStr[i]);
CurNode := nil;
CurNode2 := nil;
if (eStr.Count <> 0) then begin
IdFTP.ChangeDir('/');
for i := 0 to eStr.Count do begin
try
with GetAllDirs do begin
for 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;
trvDirectories.Selected := CurNode;
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
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:
1) Copy the latest MM:S dlls and hl2launch.exe into this folder
2) Run Attach.exe
3) Test MMS_Installer.exe once (should work but nobody wants bug releases, especially not in the installer)
4) If everything worked fine, release it, otherwise pm me (Basic-Master)
How to prepare a release:
1) Copy the latest MM:S dlls into this folder
2) Append .source to the Source binaries and .orangebox to the OrangeBox binaries
3) Run Attach.exe
4) Test MMS_Installer.exe once (recommended)
5) Release it or e-Mail me if you find a bug

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -153,6 +153,30 @@ public:
return npos;
}
int find_last_of(const char c, int index = npos) const
{
int len = static_cast<int>(size());
if (len < 1)
return npos;
if (index >= len || index < npos)
return npos;
int i;
if (index == npos)
i = len - 1;
else
i = index;
for (; i>=0; i--)
{
if (v[i] == c)
{
return i;
}
}
return npos;
}
bool is_space(int c) const
{
if (c == '\f' || c == '\n' ||

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/* ======== SourceHook ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -752,11 +752,6 @@ namespace SourceHook
bool CSourceHookImpl::ShouldContinue()
{
// If recall is true, we shall not continue either.
// This is because, if it's true and ShouldContinue is called, it suggests that the
// actual recall is done and that we are back in the original handler which shall return
// immediately.
// Post-recalls:
// The second element on the stack has recall set to Recall_Post1.
// This means that we want to skip this part and the original function calling thing, so
@ -778,7 +773,21 @@ namespace SourceHook
return m_HLIStack.front().shouldContinue;
}
}
return m_HLIStack.front().shouldContinue && !m_HLIStack.front().recall;
// 16.01.2008: We used to return false for recalls here.
// This caused the hook funcs to think that the whole iface has been destroyed
// (the original purpose of shouldcontinue was to notify the hookfuncs that everything has been
// invalidated by RemoveHook) so they did not release their iterator. -> Leaks
// Now, GetIter sets the iterator to END so it still gets released but the hooks don't continue.
// But: we have to return false in the post phase of pre recalls (ie. a pre hook made a recall).
if (m_HLIStack.front().recall == HookLoopInfo::Recall_Pre &&
static_cast<CIface*>(m_HLIStack.front().pCurIface)->m_PreHooks.RelFlagGet())
{
return false;
}
return m_HLIStack.front().shouldContinue;
}
void CSourceHookImpl::DoRecall()
@ -994,6 +1003,9 @@ namespace SourceHook
ret->Set(m_UsedIters); // m_UsedIters is the last returned and not released iterator
ret->Next(); // Use next instead of directly incrementing its m_Iter:
// skips paused plugins
// Set the last iterator to END!
m_UsedIters->GoToEnd();
}
ret->m_pNext = m_UsedIters;
@ -1008,6 +1020,8 @@ namespace SourceHook
}
void CSourceHookImpl::CHookList::ReleaseIter(IIter *pIter)
{
m_RelFlag = true;
CIter *pIter2 = static_cast<CIter*>(pIter);
// Unlink from m_UsedIters
@ -1017,7 +1031,7 @@ namespace SourceHook
if (pIter2->m_pPrev)
pIter2->m_pPrev->m_pNext = pIter2->m_pNext;
if (pIter2 == m_UsedIters)
m_UsedIters = NULL;
m_UsedIters = m_UsedIters->m_pNext;
// Link to m_FreeIters
@ -1048,6 +1062,11 @@ namespace SourceHook
SkipPaused();
}
void CSourceHookImpl::CHookList::CIter::GoToEnd()
{
m_Iter = m_pList->m_List.end();
}
bool CSourceHookImpl::CHookList::CIter::End()
{
if (!m_pList)
@ -1056,7 +1075,7 @@ namespace SourceHook
}
void CSourceHookImpl::CHookList::CIter::Next()
{
if (!m_pList)
if (!m_pList || m_Iter == m_pList->m_List.end())
return;
++m_Iter;
SkipPaused();

View File

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

View File

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

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
OPT_FLAGS = -O3 -funroll-loops -s -pipe

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@
#include "sourcehook_test.h"
#include "testbail.h"
static unsigned int n_calls = 0;
int EatYams_Handler2(int a)
{
@ -31,6 +32,18 @@ namespace N_TestBail
CHECK_COND(ret == 6, "Part 2.1");
n_calls++;
return true;
}
void UntestBail2()
{
while (n_calls)
{
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler3, false);
SH_REMOVE_HOOK_STATICFUNC(IGaben, EatYams, g_Gabgab, EatYams_Handler2, false);
n_calls--;
}
}
}

View File

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

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

View File

@ -222,5 +222,11 @@ bool TestRecall(std::string &error)
CHECK_COND(a == 0xDEADFC, "Part 5.1");
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost_Func2, true);
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, Handler2_Func2, false);
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, Handler1_Func22, false);
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost1_Func22, true);
SH_REMOVE_HOOK_STATICFUNC(Test, Func2, ptr, HandlerPost2_Func22, true);
return true;
}

View File

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

View File

@ -195,6 +195,14 @@ bool TestRefRet(std::string &error)
&hook.m_Var), // override ret was hook.m_Var
new State_Func2_Ret(&hook.m_Var), // really returned hook.m_Var
NULL), "Part 7");
SH_REMOVE_HOOK_MEMFUNC(Test, Func2, &test, &hook, &CHook::Func2_Post1, true);
SH_REMOVE_HOOK_MEMFUNC(Test, Func2, &test, &hook, &CHook::Func2_Pre1, false);
SH_REMOVE_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Pre1, false);
SH_REMOVE_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Post1, true);
SH_REMOVE_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Pre2, false);
SH_REMOVE_HOOK_MEMFUNC(Test, Func1, &test, &hook, &CHook::Func1_Post2, true);
return true;
}

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -12,6 +12,7 @@
#include "CSmmAPI.h"
#include "sourcemm.h"
#include "concommands.h"
#include "vsp_listener.h"
/**
* @brief Implements functions from CPlugin.h
@ -22,14 +23,14 @@ using namespace SourceMM;
#define ITER_PLEVENT(evn, plid) \
CPluginManager::CPlugin *_Xpl; \
SourceHook::List<IMetamodListener *>::iterator event; \
SourceHook::List<CPluginEventHandler>::iterator event; \
IMetamodListener *api; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
_Xpl = (*iter); \
if (_Xpl->m_Id == plid) \
continue; \
for (event=_Xpl->m_Events.begin(); event!=_Xpl->m_Events.end(); event++) { \
api = (*event); \
api = (*event).event; \
api->evn(plid); \
} \
}
@ -182,6 +183,38 @@ void CPluginManager::SetAllLoaded()
}
}
void CPluginManager::SetVSPAsLoaded()
{
PluginIter i;
CPlugin *pPlugin;
SourceHook::List<CPluginEventHandler>::iterator event;
for (i = m_Plugins.begin(); i != m_Plugins.end(); i++)
{
pPlugin = (*i);
if (pPlugin->m_Status < Pl_Paused)
{
continue;
}
/* Only valid for plugins >= 10 (v1:5, SourceMM 1.4) */
if (pPlugin->m_API->GetApiVersion() < 10)
{
continue;
}
for (event = pPlugin->m_Events.begin();
event != pPlugin->m_Events.end();
event++)
{
if ((*event).got_vsp)
{
continue;
}
(*event).got_vsp = true;
(*event).event->OnVSPListening(&g_VspListener);
}
}
}
bool CPluginManager::Pause(PluginId id, char *error, size_t maxlen)
{
CPlugin *pl = FindById(id);
@ -335,7 +368,7 @@ CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source
if (!pl->m_Lib)
{
if (error)
UTIL_Format(error, maxlen, "%s", dlerror());
UTIL_Format(error, maxlen, "[%d]", GetLastError());
pl->m_Status = Pl_Error;
} else {
CreateInterfaceFn pfn = (CreateInterfaceFn)(dlsym(pl->m_Lib, PL_EXPOSURE_C));
@ -373,6 +406,22 @@ CPluginManager::CPlugin *CPluginManager::_Load(const char *file, PluginId source
//if (pl->m_API->GetApiVersion() >= 4)
pl->m_API->AllPluginsLoaded();
}
if (g_VspListener.IsRootLoadMethod()
|| (g_VspListener.IsLoaded() && g_SmmAPI.VSPEnabled()))
{
SourceHook::List<CPluginEventHandler>::iterator event;
for (event = pl->m_Events.begin();
event != pl->m_Events.end();
event++)
{
if (pl->m_API->GetApiVersion() < 10 || (*event).got_vsp)
{
continue;
}
(*event).got_vsp = true;
(*event).event->OnVSPListening(&g_VspListener);
}
}
} else {
pl->m_Status = Pl_Refused;
}
@ -496,23 +545,17 @@ bool CPluginManager::UnloadAll()
{
PluginIter i;
SourceHook::List<SourceMM::CPluginManager::CPlugin *> remqueue;
for (i=m_Plugins.begin(); i!=m_Plugins.end(); i++)
remqueue.push_back( (*i) );
char error[128];
bool status = true;
for (i=remqueue.begin(); i!=remqueue.end(); i++)
while ((i = m_Plugins.begin()) != m_Plugins.end())
{
if ( !_Unload( (*i), true, error, sizeof(error)) )
{
status = false;
}
}
m_Plugins.clear();
remqueue.clear();
return status;
}
@ -622,3 +665,34 @@ void CPluginManager::UnregAllConCmds(CPlugin *pl)
pl->m_Cmds.clear();
}
const char *CPluginManager::GetStatusText(CPlugin *pl)
{
switch (pl->m_Status)
{
case Pl_NotFound:
return "NOFILE";
case Pl_Error:
return "ERROR";
case Pl_Refused:
return "FAILED";
case Pl_Paused:
return "PAUSED";
case Pl_Running:
{
if (pl->m_API && pl->m_API->QueryRunning(NULL, 0))
{
return "STOPPED";
} else {
return "RUNNING";
}
}
default:
return "-";
}
}
unsigned int CPluginManager::GetPluginCount()
{
return (unsigned int)m_Plugins.size();
}

View File

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

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -141,8 +141,12 @@ void CSmmAPI::ConPrintf(const char *fmt, ...)
void CSmmAPI::AddListener(ISmmPlugin *plugin, IMetamodListener *pListener)
{
CPluginManager::CPlugin *pl = g_PluginMngr.FindByAPI(plugin);
CPluginEventHandler cpeh;
pl->m_Events.push_back(pListener);
cpeh.event = pListener;
cpeh.got_vsp = false;
pl->m_Events.push_back(cpeh);
}
void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
@ -174,7 +178,7 @@ void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
}
CPluginManager::CPlugin *pl;
SourceHook::List<IMetamodListener *>::iterator event;
SourceHook::List<CPluginEventHandler>::iterator event;
IMetamodListener *api;
int ret = 0;
void *val = NULL;
@ -184,7 +188,7 @@ void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
pl = (*iter);
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++)
{
api = (*event);
api = (*event).event;
ret = IFACE_FAILED;
if ( (val=api->OnMetamodQuery(iface, &ret)) != NULL )
{
@ -221,22 +225,6 @@ void *CSmmAPI::MetaFactory(const char *iface, int *_ret, PluginId *id)
#define ENGINEW32_OFFS 38
#define IA32_CALL 0xE8
bool vcmp(const void *_addr1, const void *_addr2, size_t len)
{
unsigned char *addr1 = (unsigned char *)_addr1;
unsigned char *addr2 = (unsigned char *)_addr2;
for (size_t i=0; i<len; i++)
{
if (addr2[i] == '*')
continue;
if (addr1[i] != addr2[i])
return false;
}
return true;
}
//Thanks to fysh for the idea of extracting info from "echo" and for
// having the original offsets at hand!
bool CSmmAPI::CacheCmds()
@ -256,20 +244,20 @@ bool CSmmAPI::CacheCmds()
callback = ((ConCommand *)pBase)->GetCallback();
ptr = (unsigned char *)callback;
#ifdef OS_LINUX
if (vcmp(ptr, ENGINE486_SIG, SIGLEN))
if (UTIL_VerifySignature(ptr, ENGINE486_SIG, SIGLEN))
{
offs = ENGINE486_OFFS;
}
else if (vcmp(ptr, ENGINE686_SIG, SIGLEN))
else if (UTIL_VerifySignature(ptr, ENGINE686_SIG, SIGLEN))
{
offs = ENGINE686_OFFS;
}
else if (vcmp(ptr, ENGINEAMD_SIG, SIGLEN))
else if (UTIL_VerifySignature(ptr, ENGINEAMD_SIG, SIGLEN))
{
offs = ENGINEAMD_OFFS;
}
#elif defined OS_WIN32 // Only one Windows engine binary so far...
if (vcmp(ptr, ENGINEW32_SIG, SIGLEN))
if (UTIL_VerifySignature(ptr, ENGINEW32_SIG, SIGLEN))
{
offs = ENGINEW32_OFFS;
}
@ -454,16 +442,40 @@ void CSmmAPI::ClientConPrintf(edict_t *client, const char *fmt, ...)
void CSmmAPI::LoadAsVSP()
{
char command[350];
size_t len;
char engine_file[PATH_SIZE];
char rel_path[PATH_SIZE * 2];
GetFileOfAddress(g_Engine.engine, engine_file, sizeof(engine_file));
/* Chop off the "engine" file part */
len = strlen(engine_file);
for (size_t i = len - 1; i >= 0 && i < len; i--)
{
if (engine_file[i] == '/'
|| engine_file[i] == '\\')
{
engine_file[i] = '\0';
break;
}
}
const char *usepath = g_SmmPath.c_str();
if (UTIL_Relatize(rel_path, sizeof(rel_path), engine_file, g_SmmPath.c_str()))
{
usepath = rel_path;
}
char command[PATH_SIZE * 2];
g_VspListener.SetLoadable(true);
UTIL_Format(command, sizeof(command), "plugin_load \"%s\"\n", g_SmmPath.c_str());
UTIL_Format(command, sizeof(command), "plugin_load \"%s\"\n", usepath);
g_Engine.engine->ServerCommand(command);
}
void CSmmAPI::EnableVSPListener()
{
/* If GameInit already passed and we're not already enabled or loaded, go ahead and LoadAsVSP load */
if (bGameInit && !m_VSP && !g_VspListener.IsLoaded())
if (bGameInit && !m_VSP && !g_VspListener.IsLoaded() && !g_VspListener.IsRootLoadMethod())
{
LoadAsVSP();
}
@ -492,6 +504,11 @@ int CSmmAPI::GetGameDLLVersion()
#define MSGCLASS2_SIGLEN 16
#define MSGCLASS2_SIG "\x56\x8B\x74\x24\x2A\x85\xF6\x7C\x2A\x3B\x35\x2A\x2A\x2A\x2A\x7D"
#define MSGCLASS2_OFFS 11
/* Windows frame pointer sig */
#define MSGCLASS3_SIGLEN 18
#define MSGCLASS3_SIG "\x55\x8B\xEC\x51\x89\x2A\x2A\x8B\x2A\x2A\x50\x8B\x0D\x2A\x2A\x2A\x2A\xE8"
#define MSGCLASS3_OFFS 13
#elif defined OS_LINUX
/* No frame pointer sig */
#define MSGCLASS_SIGLEN 14
@ -508,45 +525,22 @@ int CSmmAPI::GetGameDLLVersion()
/* :TODO: Make this prettier */
bool CSmmAPI::CacheUserMessages()
{
SourceHook::MemFuncInfo info = {true, -1, 0, 0};
SourceHook::GetFuncInfo(&IServerGameDLL::GetUserMessageInfo, info);
/* Get address of original GetUserMessageInfo() */
char *vfunc = reinterpret_cast<char *>(g_GameDllPatch->GetOrigFunc(info.vtbloffs, info.vtblindex));
/* If we can't get original function, that means there's no hook */
if (vfunc == NULL)
{
/* Get virtual function address 'manually' then */
char *adjustedptr = reinterpret_cast<char *>(g_GameDll.pGameDLL) + info.thisptroffs + info.vtbloffs;
char **vtable = *reinterpret_cast<char ***>(adjustedptr);
vfunc = vtable[info.vtblindex];
}
/* Oh dear, we have a relative jump on our hands
* PVK II on Windows made me do this, but I suppose it doesn't hurt to check this on Linux too...
*/
if (*vfunc == '\xE9')
{
/* Get address from displacement...
*
* Add 5 because it's relative to next instruction:
* Opcode <1 byte> + 32-bit displacement <4 bytes>
*/
vfunc = vfunc + *reinterpret_cast<int *>(vfunc + 1) + 5;
}
UserMsgDict *dict = NULL;
char *vfunc = UTIL_GetOrigFunction(&IServerGameDLL::GetUserMessageInfo, g_GameDll.pGameDLL, g_GameDllPatch);
if (vcmp(vfunc, MSGCLASS_SIG, MSGCLASS_SIGLEN))
if (!vfunc)
{
return false;
}
if (UTIL_VerifySignature(vfunc, MSGCLASS_SIG, MSGCLASS_SIGLEN))
{
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
} else if (vcmp(vfunc, MSGCLASS2_SIG, MSGCLASS2_SIGLEN)) {
} else if (UTIL_VerifySignature(vfunc, MSGCLASS2_SIG, MSGCLASS2_SIGLEN)) {
#ifdef OS_WIN32
/* If we get here, the code is possibly inlined like in Dystopia */
@ -562,6 +556,14 @@ bool CSmmAPI::CacheUserMessages()
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
#ifdef OS_WIN32
} else if (UTIL_VerifySignature(vfunc, MSGCLASS3_SIG, MSGCLASS3_SIGLEN)) {
/* Get address of CUserMessages instance */
char **userMsgClass = *reinterpret_cast<char ***>(vfunc + MSGCLASS3_OFFS);
/* Get address of CUserMessages::m_UserMessages */
dict = reinterpret_cast<UserMsgDict *>(*userMsgClass);
#endif
}
if (dict)

View File

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

View File

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

View File

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

View File

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

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
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
HL2SDK = ../../hl2sdk
@ -34,7 +34,10 @@ endif
GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Werror -fPIC -fno-exceptions -fno-rtti -msse
CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \
-Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca \
-Dstrcmpi=strcasecmp -Wall -Wno-non-virtual-dtor -Wno-uninitialized -Werror -fPIC \
-fno-exceptions -fno-rtti -msse -m32
ifeq "$(GCC_VERSION)" "4"
CFLAGS += $(GCC4_FLAGS)
@ -55,7 +58,7 @@ all:
ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
sourcemm: $(OBJ_LINUX)
$(CPP) $(INCLUDE) $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
$(CPP) $(INCLUDE) -m32 $(CFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
debug:
$(MAKE) all DEBUG=true

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

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -9,31 +9,38 @@
*/
#include <ctype.h>
#include "convar_smm.h"
#include "CSmmAPI.h"
#include "concommands.h"
#include "CPlugin.h"
#include "sh_string.h"
#include "sh_list.h"
#include "vsp_listener.h"
/**
* @brief Console Command Implementations
* @file concommands.cpp
*/
CAlwaysRegisterableCommand g_EternalCommand;
SMConVarAccessor g_SMConVarAccessor;
SMConVarAccessor::SMConVarAccessor()
{
m_TopConCommandBase = NULL;
}
bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
{
// Add the FCVAR_GAMEDLL flag
// => No crash on exit!
// UPDATE: Do _not_ add the FCVAR_GAMEDLL flag here, as it
// causes the command to be unusable on listenservers until you load a map
// We will set the FCVAR_GAMEDLL flag on all commands we have registered once we are being unloaded
//pCommand->AddFlags(FCVAR_GAMEDLL);
/* Add the FCVAR_GAMEDLL flag
* => No crash on exit!
* UPDATE: Do _not_ add the FCVAR_GAMEDLL flag here, as it
* causes the command to be unusable on listen servers until you load a map
* We will set the FCVAR_GAMEDLL flag on all commands we have registered once we are being unloaded
*/
// pCommand->AddFlags(FCVAR_GAMEDLL);
m_RegisteredCommands.push_back(pCommand);
pCommand->SetNext( NULL );
pCommand->SetNext(NULL);
g_Engine.icvar->RegisterConCommandBase(pCommand);
return true;
@ -41,8 +48,8 @@ bool SMConVarAccessor::RegisterConCommandBase(ConCommandBase *pCommand)
bool SMConVarAccessor::Register(ConCommandBase *pCommand)
{
//simple, don't mark as part of sourcemm!
pCommand->SetNext( NULL );
/* Simple, don't mark as part of sourcemm! */
pCommand->SetNext(NULL);
g_Engine.icvar->RegisterConCommandBase(pCommand);
return true;
@ -59,67 +66,52 @@ void SMConVarAccessor::MarkCommandsAsGameDLL()
void SMConVarAccessor::Unregister(ConCommandBase *pCommand)
{
ICvar *cv = g_Engine.icvar;
ConCommandBase *ptr = cv->GetCommands();
ConCommandBase *pCur = NULL;
ConCommandBase *pPrev = NULL;
if (ptr == pCommand)
if (!pCommand || !pCommand->IsRegistered())
{
//first in list
g_EternalCommand.BringToFront();
g_EternalCommand.SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
} else {
//find us and unregister us
ConCommandBase *pPrev = NULL;
while (ptr)
{
if (ptr == pCommand)
break;
pPrev = ptr;
ptr = const_cast<ConCommandBase *>(ptr->GetNext());
}
if (pPrev && ptr == pCommand)
return;
}
pCur = g_Engine.icvar->GetCommands();
pCommand->SetRegistered(false);
if (!m_TopConCommandBase || !pCur)
{
return;
}
if (pCur == pCommand)
{
*m_TopConCommandBase = const_cast<ConCommandBase *>(pCommand->GetNext());
pCommand->SetNext(NULL);
return;
}
pPrev = pCur;
pCur = const_cast<ConCommandBase *>(pCur->GetNext());
while (pCur)
{
if (pCur == pCommand)
{
pPrev->SetNext(const_cast<ConCommandBase *>(pCommand->GetNext()));
pCommand->SetNext(NULL);
}
pPrev = pCur;
pCur = const_cast<ConCommandBase *>(pCur->GetNext());
}
}
void SMConVarAccessor::UnregisterGameDLLCommands()
{
ConCommandBase *begin = g_Engine.icvar->GetCommands();
ConCommandBase *iter = begin;
ConCommandBase *prev = NULL;
while (iter)
{
// watch out for the ETERNAL COMMAND!
if (iter != &g_EternalCommand && iter->IsBitSet(FCVAR_GAMEDLL))
{
// Remove it!
if (iter == begin)
{
g_EternalCommand.BringToFront();
iter = const_cast<ConCommandBase*>(iter->GetNext());
g_EternalCommand.SetNext(iter);
prev = &g_EternalCommand;
continue;
}
else
{
iter = const_cast<ConCommandBase*>(iter->GetNext());
prev->SetNext(iter);
continue;
}
}
prev = iter;
iter = const_cast<ConCommandBase*>(iter->GetNext());
}
}
ConVar metamod_version("metamod_version", SOURCEMM_VERSION, FCVAR_REPLICATED | FCVAR_SPONLY | FCVAR_NOTIFY, "Metamod:Source Version");
#if defined WIN32 || defined _WIN32
ConVar metamod_version("metamod_version", SOURCEMM_VERSION, FCVAR_SPONLY | FCVAR_NOTIFY, "Metamod:Source Version");
#ifdef OS_WIN32
ConVar mm_pluginsfile("mm_pluginsfile", "addons\\metamod\\metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File");
ConVar mm_basedir("mm_basedir", "addons\\metamod", FCVAR_SPONLY, "Metamod:Source base folder");
#else
ConVar mm_pluginsfile("mm_pluginsfile", "addons/metamod/metaplugins.ini", FCVAR_SPONLY, "Metamod:Source Plugins File");
ConVar mm_basedir("mm_basedir", "addons/metamod", FCVAR_SPONLY, "Metamod:Source base folder");
#endif
CON_COMMAND(meta, "Metamod:Source Menu")
@ -128,6 +120,12 @@ CON_COMMAND(meta, "Metamod:Source Menu")
int args = e->Cmd_Argc();
if (g_VspListener.IsRootLoadMethod() && !g_bLevelChanged)
{
CONMSG("WARNING: You must change the map to activate Metamod:Source.\n");
return;
}
if (args >= 2)
{
const char *command = e->Cmd_Argv(1);
@ -138,15 +136,23 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG(" GameDLL/Plugins: David \"BAILOPAN\" Anderson\n");
CONMSG(" GameDLL: Scott \"Damaged Soul\" Ehlert\n");
CONMSG("For more information, see the official website\n");
CONMSG("http://www.sourcemm.net/\n");
CONMSG("http://www.metamodsource.net/\n");
return;
} else if (strcmp(command, "version") == 0) {
CONMSG("Metamod:Source version %s\n", SOURCEMM_VERSION);
if (g_VspListener.IsRootLoadMethod())
{
CONMSG("Loaded As: Valve Server Plugin\n");
}
else
{
CONMSG("Loaded As: GameDLL (gameinfo.txt)\n");
}
CONMSG("Compiled on: %s\n", SOURCEMM_DATE);
CONMSG("Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION);
CONMSG("SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
CONMSG("http://www.sourcemm.net/\n");
CONMSG("http://www.metamodsource.net/\n");
return;
} else if (strcmp(command, "game") == 0) {
@ -191,59 +197,63 @@ CON_COMMAND(meta, "Metamod:Source Menu")
return;
} else if (strcmp(command, "list") == 0) {
SourceMM::CPluginManager::CPlugin *pl;
size_t len;
PluginIter i;
const char *status="";
const char *version=NULL;
const char *name=NULL;
const char *author=NULL;
char buffer[255];
ISmmPlugin *plapi;
const char *plname;
SourceMM::CPluginManager::CPlugin *pl;
unsigned int plnum = g_PluginMngr.GetPluginCount();
#define IS_STR_FILLED(var) (var != NULL && var[0] != '\0')
if (!plnum)
{
CONMSG("No plugins loaded.\n");
return;
}
else
{
CONMSG("Listing %d plugin%s:\n", plnum, (plnum > 1) ? "s" : "");
}
CONMSG("-Id- %-20.19s %-10.9s %-20.19s %-8.7s\n", "Name", "Version", "Author", "Status");
for (i=g_PluginMngr._begin(); i!=g_PluginMngr._end(); i++)
{
pl = (*i);
if (!pl)
{
break;
if (pl->m_Status == Pl_Paused)
{
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();
author = pl->m_API->GetAuthor();
name = pl->m_API->GetName();
} else {
version = "-";
author = "-";
name = "-";
len += UTIL_Format(buffer, sizeof(buffer), " [%02d] <%s>", pl->m_Id, g_PluginMngr.GetStatusText(pl));
}
else
{
len += UTIL_Format(buffer, sizeof(buffer), " [%02d]", pl->m_Id);
}
if (!version)
version = "-";
if (!author)
author = "-";
if (!name)
name = pl->m_File.c_str();
if ((plapi = pl->m_API))
{
plname = IS_STR_FILLED(plapi->GetName()) ? plapi->GetName() : pl->m_File.c_str();
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " %s", plname);
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;
} else if (strcmp(command, "cmds") == 0) {
if (args >= 3)
@ -625,53 +635,6 @@ CON_COMMAND(meta, "Metamod:Source Menu")
CONMSG(" version - Version information\n");
}
CAlwaysRegisterableCommand::CAlwaysRegisterableCommand()
{
Create("", NULL, FCVAR_UNREGISTERED|FCVAR_GAMEDLL);
m_pICvar = NULL;
}
bool CAlwaysRegisterableCommand::IsRegistered( void ) const
{
return false;
}
void CAlwaysRegisterableCommand::BringToFront()
{
if (!m_pICvar)
m_pICvar = g_Engine.icvar;
// First, let's try to find us!
ConCommandBase *pPtr = m_pICvar->GetCommands();
if (pPtr == this)
{
// We are already at the beginning; Nothing to do
return;
}
while (pPtr)
{
if (pPtr == this && pPtr->IsCommand() && stricmp(GetName(), pPtr->GetName()) == 0)
break;
ConCommandBase *pPrev = NULL;
while (pPtr)
{
if (pPtr == this)
break;
pPrev = pPtr;
pPtr = const_cast<ConCommandBase*>(pPtr->GetNext());
}
if (pPrev && pPtr == this)
{
pPrev->SetNext(m_pNext); // Remove us from the list
}
// Now, register us
SetNext(NULL);
m_pICvar->RegisterConCommandBase(this);
}
}
void ClientCommand_handler(edict_t *client)
{
IVEngineServer *e = g_Engine.engine;
@ -688,10 +651,10 @@ void ClientCommand_handler(edict_t *client)
{
CLIENT_CONMSG(client, "Metamod:Source was developed by:\n");
CLIENT_CONMSG(client, " SourceHook: Pavol \"PM OnoTo\" Marko\n");
CLIENT_CONMSG(client, " GameDLL/Plugins: David \"BAILOPAN\" Anderson\n");
CLIENT_CONMSG(client, " GameDLL: Scott \"Damaged Soul\" Ehlert\n");
CLIENT_CONMSG(client, " Core: David \"BAILOPAN\" Anderson\n");
CLIENT_CONMSG(client, " Core: Scott \"Damaged Soul\" Ehlert\n");
CLIENT_CONMSG(client, "For more information, see the official website\n");
CLIENT_CONMSG(client, "http://www.sourcemm.net/\n");
CLIENT_CONMSG(client, "http://www.metamodsource.net/\n");
RETURN_META(MRES_SUPERCEDE);
} else if(strcmp(subcmd, "version") == 0) {
@ -699,49 +662,53 @@ void ClientCommand_handler(edict_t *client)
CLIENT_CONMSG(client, "Compiled on: %s\n", SOURCEMM_DATE);
CLIENT_CONMSG(client, "Plugin interface version: %d:%d\n", PLAPI_VERSION, PLAPI_MIN_VERSION);
CLIENT_CONMSG(client, "SourceHook version: %d:%d\n", g_SourceHook.GetIfaceVersion(), g_SourceHook.GetImplVersion());
CLIENT_CONMSG(client, "http://www.sourcemm.net/\n");
CLIENT_CONMSG(client, "http://www.metamodsource.net/\n");
RETURN_META(MRES_SUPERCEDE);
} else if(strcmp(subcmd, "list") == 0) {
SourceMM::CPluginManager::CPlugin *pl;
Pl_Status st;
ISmmPlugin *plapi;
const char *plname;
PluginIter i;
const char *version = NULL;
const char *name = NULL;
const char *author = NULL;
const char *status = NULL;
char buffer[256];
int len = 0;
int plnum = 0;
CLIENT_CONMSG(client, "-Id- %-20.19s %-10.9s %-20.19s %6s\n", "Name", "Version", "Author", "Status");
for (i=g_PluginMngr._begin(); i!=g_PluginMngr._end(); i++)
for (i = g_PluginMngr._begin(); i != g_PluginMngr._end(); i++, len=0)
{
pl = (*i);
if (!pl)
break;
st = pl->m_Status;
/* Only show plugins that are running or paused */
if (pl->m_API && (st == Pl_Running || st == Pl_Paused))
if (pl && pl->m_Status == Pl_Running)
{
version = pl->m_API->GetVersion();
author = pl->m_API->GetAuthor();
name = pl->m_API->GetName();
if (st == Pl_Running && pl->m_API->QueryRunning(NULL, 0))
plapi = pl->m_API;
if (!plapi || !plapi->QueryRunning(NULL, 0))
{
status = "RUN";
} else {
status = "PAUSE";
continue;
}
plnum++;
len += UTIL_Format(buffer, sizeof(buffer), " [%02d]", plnum);
plname = IS_STR_FILLED(plapi->GetName()) ? plapi->GetName() : pl->m_File.c_str();
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " %s", plname);
if (IS_STR_FILLED(plapi->GetVersion()))
{
len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", plapi->GetVersion());
}
if (IS_STR_FILLED(plapi->GetAuthor()))
{
UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", plapi->GetAuthor());
}
if (!version || !author || !name)
break;
CLIENT_CONMSG(client, "[%02d] %-20.19s %-10.9s %-20.19s %6s\n", pl->m_Id, name, version, author, status);
CLIENT_CONMSG(client, "%s\n", buffer);
}
}
if (!plnum)
{
CLIENT_CONMSG(client, "No active plugins loaded.\n");
}
RETURN_META(MRES_SUPERCEDE);
}
}
@ -758,7 +725,79 @@ void ClientCommand_handler(edict_t *client)
RETURN_META(MRES_IGNORED);
}
void SMConVarAccessor::UnloadMetamodCommands()
{
Unregister(&metamod_version);
Unregister(&mm_pluginsfile);
Unregister(&mm_basedir);
Unregister(&meta_command);
}
const char *GetPluginsFile()
{
return mm_pluginsfile.GetString();
}
const char *GetMetamodBaseDir()
{
return mm_basedir.GetString();
}
/* Signature for ICvar::GetCommands() in vstdlib for Win32 and Linux.
*
* 20226EE0 A1 50 5C 5A 20 mov eax,dword ptr ds:[205A5C50h] <-- What we want
* 20226EE5 C3 ret
*/
#define CMDLIST_SIG "\xA1\x2A\x2A\x2A\x2A\xC3"
#define CMDLIST_SIGLEN 6
/* Linux symbol name of ConCommandBase list in vstdlib */
#define CMDLIST_SYMBOL "_ZN14ConCommandBase18s_pConCommandBasesE"
/* This function retrieves the address of the var that holds the top of the ConCommandBase list.
* Having this allows us to change the beginning of this list with ease.
*
* This craziness eliminates the need for the eternal command/cvar used previously which
* could have caused a crash as a result of registering commands/cvars more than once.
*/
bool SMConVarAccessor::InitConCommandBaseList()
{
char *vfunc = UTIL_GetOrigFunction(&ICvar::GetCommands, g_Engine.icvar, g_CvarPatch);
if (!vfunc)
{
return false;
}
#ifdef OS_WIN32
if (UTIL_VerifySignature(vfunc, CMDLIST_SIG, CMDLIST_SIGLEN))
{
/* Skip past 0xA1 and get addr of ConCommandBase list var */
m_TopConCommandBase = *reinterpret_cast<ConCommandBase ***>(vfunc + 1);
return true;
}
#elif defined OS_LINUX
/* Try dlsym first */
char path[PATH_SIZE];
if (GetFileOfAddress((void *)g_Engine.icvar, path, sizeof(path)))
{
void *handle = dlopen(path, RTLD_NOW);
if (handle)
{
m_TopConCommandBase = reinterpret_cast<ConCommandBase **>(dlsym(handle, CMDLIST_SYMBOL));
dlclose(handle);
return true;
}
}
/* If dlsym failed, then verify signature of function */
if (!m_TopConCommandBase && UTIL_VerifySignature(vfunc, CMDLIST_SIG, CMDLIST_SIGLEN))
{
/* Skip past 0xA1 and get addr of ConCommandBase list var */
m_TopConCommandBase = *reinterpret_cast<ConCommandBase ***>(vfunc + 1);
return true;
}
#endif
return false;
}

View File

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

View File

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

View File

@ -41,6 +41,7 @@
<Tool
Name="VCCLCompilerTool"
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"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@ -62,7 +63,7 @@
/>
<Tool
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"
LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
@ -126,6 +127,7 @@
Optimization="3"
FavorSizeOrSpeed="1"
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"
StringPooling="true"
ExceptionHandling="1"
@ -148,7 +150,7 @@
/>
<Tool
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"
LinkIncremental="1"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"
@ -273,6 +275,10 @@
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath="..\svn_version.tpl"
>
</File>
<File
RelativePath="..\version.rc"
>

View File

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

View File

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

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
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
HL2SDK = ../../../hl2sdk

View File

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

View File

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

View File

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

View File

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

View File

@ -41,6 +41,7 @@
<Tool
Name="VCCLCompilerTool"
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"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@ -62,7 +63,7 @@
/>
<Tool
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"
LinkIncremental="2"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmt.lib"
@ -122,6 +123,7 @@
/>
<Tool
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"
RuntimeLibrary="0"
RuntimeTypeInfo="false"
@ -142,7 +144,7 @@
/>
<Tool
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"
LinkIncremental="1"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -19,6 +19,8 @@
#include "CPlugin.h"
#include "util.h"
#include "vsp_listener.h"
#include "iplayerinfo.h"
#include <filesystem.h>
using namespace SourceMM;
@ -43,6 +45,8 @@ void DLLShutdown_handler();
void LevelShutdown_handler();
bool LevelInit_handler(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
bool GameInit_handler();
void LookForVDFs(const char *dir);
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID = NULL);
GameDllInfo g_GameDll = {false, NULL, NULL, NULL, NULL};
EngineInfo g_Engine;
@ -57,24 +61,28 @@ bool gParsedGameInfo = false;
bool bGameInit = false;
SourceHook::List<GameDllInfo *> gamedll_list;
SourceHook::CallClass<IServerGameDLL> *g_GameDllPatch;
SourceHook::CallClass<ICvar> *g_CvarPatch;
int g_GameDllVersion = 0;
const char VSPIFACE_001[] = "ISERVERPLUGINCALLBACKS001";
const char VSPIFACE_002[] = "ISERVERPLUGINCALLBACKS002";
const char GAMEINFO_PATH[] = "|gameinfo_path|";
IFileSystem *baseFs = NULL;
bool g_bLevelChanged = false;
void ClearGamedllList();
/* Helper Macro */
#define IFACE_MACRO(orig,nam) \
CPluginManager::CPlugin *pl; \
SourceHook::List<IMetamodListener *>::iterator event; \
SourceHook::List<CPluginEventHandler>::iterator event; \
IMetamodListener *api; \
int mret = 0; \
void *val = NULL; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
pl = (*iter); \
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
api = (*event); \
api = (*event).event; \
mret = IFACE_FAILED; \
if ( (val=api->On##nam##Query(iface, &mret)) != NULL ) { \
if (ret) *ret = mret; \
@ -86,12 +94,12 @@ void ClearGamedllList();
#define ITER_EVENT(evn, args) \
CPluginManager::CPlugin *pl; \
SourceHook::List<IMetamodListener *>::iterator event; \
SourceHook::List<CPluginEventHandler>::iterator event; \
IMetamodListener *api; \
for (PluginIter iter = g_PluginMngr._begin(); iter != g_PluginMngr._end(); iter++) { \
pl = (*iter); \
for (event=pl->m_Events.begin(); event!=pl->m_Events.end(); event++) { \
api = (*event); \
api = (*event).event; \
api->evn args; \
} \
}
@ -119,25 +127,34 @@ void InitMainStates()
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelShutdown, g_GameDll.pGameDLL, LevelShutdown_handler, true);
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, LevelInit, g_GameDll.pGameDLL, LevelInit_handler, true);
SH_ADD_HOOK_STATICFUNC(IServerGameDLL, GameInit, g_GameDll.pGameDLL, GameInit_handler, false);
if (g_GameDll.pGameClients)
{
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, g_GameDll.pGameClients, ClientCommand_handler, false);
} else {
/* If IServerGameClients isn't found, this really isn't a fatal error so... */
LogMessage("[META] Warning: Could not find IServerGameClients!");
LogMessage("[META] Warning: The 'meta' command will not be available to clients.");
}
}
bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals)
void DoInitialPluginLoads()
{
g_Engine.engineFactory = engineFactory;
g_Engine.fileSystemFactory = filesystemFactory;
g_Engine.physicsFactory = physicsFactory;
g_Engine.pGlobals = pGlobals;
const char *pluginFile = g_Engine.icvar->GetCommandLineValue("mm_pluginsfile");
const char *mmBaseDir = g_Engine.icvar->GetCommandLineValue("mm_basedir");
if (!pluginFile)
{
pluginFile = GetPluginsFile();
}
if (!mmBaseDir)
{
mmBaseDir = GetMetamodBaseDir();
}
char full_path[260];
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), pluginFile);
LoadPluginsFromFile(full_path);
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), mmBaseDir);
LookForVDFs(full_path);
}
bool StartupMetamod(CreateInterfaceFn engineFactory, bool bWaitForGameInit)
{
g_Engine.engine = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL));
if (!g_Engine.engine)
{
Error("Could not find IVEngineServer! Metamod cannot load.");
@ -152,10 +169,24 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory,
g_Engine.loaded = true;
/* Initialize our console hooks */
/* The Ship is the only game known at this time that uses the pre-Episode One engine */
g_Engine.original = strcmp(CommandLine()->ParmValue("-game", "hl2"), "ship") == 0;
ConCommandBaseMgr::OneTimeInit(static_cast<IConCommandBaseAccessor *>(&g_SMConVarAccessor));
g_GameDllPatch = SH_GET_CALLCLASS(g_GameDll.pGameDLL);
g_CvarPatch = SH_GET_CALLCLASS(g_Engine.icvar);
if (g_GameDll.pGameClients)
{
SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, g_GameDll.pGameClients, ClientCommand_handler, false);
}
else
{
/* If IServerGameClients isn't found, this really isn't a fatal error so... */
LogMessage("[META] Warning: Could not find IServerGameClients!");
LogMessage("[META] Warning: The 'meta' command will not be available to clients.");
}
if (!g_SmmAPI.CacheCmds())
{
@ -172,34 +203,127 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory,
LogMessage("[META] Warning: The 'meta game' command will not display user messages.");
}
const char *pluginFile = g_Engine.icvar->GetCommandLineValue("mm_pluginsfile");
if (!pluginFile)
baseFs = (IFileSystem *)((engineFactory)(FILESYSTEM_INTERFACE_VERSION, NULL));
if (baseFs == NULL)
{
pluginFile = GetPluginsFile();
LogMessage("[META] Failed to find filesystem interface, .vdf files will not be parsed.");
}
char full_path[260];
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), pluginFile);
if (!g_SMConVarAccessor.InitConCommandBaseList())
{
/* This is very unlikely considering it's old engine */
LogMessage("[META] Warning: Failed to find ConCommandBase list!");
LogMessage("[META] Warning: ConVars and ConCommands cannot be unregistered properly! Please file a bug report.");
}
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);
}
bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn serverFactory)
{
g_Engine.engineFactory = ifaceFactory;
g_Engine.fileSystemFactory = ifaceFactory;
g_Engine.physicsFactory = ifaceFactory;
IPlayerInfoManager *playerInfoManager = (IPlayerInfoManager *)serverFactory("PlayerInfoManager002", NULL);
if (playerInfoManager == NULL)
{
Error("Metamod:Source requires gameinfo.txt modification to load on this game.");
return false;
}
g_Engine.pGlobals = playerInfoManager->GetGlobalVars();
/* Now find the server */
g_GameDll.factory = serverFactory;
g_GameDll.lib = NULL;
char gamedll_iface[] = "ServerGameDLL000";
for (unsigned int i = 3; i <= 50; i++)
{
gamedll_iface[15] = '0' + i;
g_GameDll.pGameDLL = (IServerGameDLL *)serverFactory(gamedll_iface, NULL);
if (g_GameDll.pGameDLL != NULL)
{
g_GameDllVersion = i;
break;
}
}
if (g_GameDll.pGameDLL == NULL)
{
Error("Metamod:Source requires gameinfo.txt modification to load on this game.");
return false;
}
char gameclients_iface[] = "ServerGameClients000";
for (unsigned int i = 3; i <= 4; i++)
{
gameclients_iface[19] = '0' + i;
g_GameDll.pGameClients = (IServerGameClients *)serverFactory(gameclients_iface, NULL);
if (g_GameDll.pGameClients != NULL)
{
break;
}
}
char smm_path[PATH_SIZE];
const char *game_dir;
GetFileOfAddress((void *)AlternatelyLoadMetamod, smm_path, sizeof(smm_path));
g_SmmPath.assign(smm_path);
game_dir = CommandLine()->ParmValue("-game", "hl2");
abspath(smm_path, game_dir);
g_ModPath.assign(smm_path);
InitMainStates();
if (!StartupMetamod(ifaceFactory, true))
{
return false;
}
g_PluginMngr.SetAllLoaded();
return true;
}
bool GameInit_handler()
{
if (bGameInit)
{
return true;
RETURN_META_VALUE(MRES_IGNORED, true);
}
if (g_SmmAPI.VSPEnabled())
if (g_SmmAPI.VSPEnabled() && !g_VspListener.IsRootLoadMethod())
{
g_SmmAPI.LoadAsVSP();
}
if (g_VspListener.IsRootLoadMethod())
{
DoInitialPluginLoads();
//gaben
}
bGameInit = true;
RETURN_META_VALUE(MRES_IGNORED, true);
@ -217,7 +341,7 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
/* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */
if (strcmp(iface, PLAPI_NAME) == 0)
{
Warning("Do not try loading Metamod:Source as a SourceMM or Valve server plugin.\n");
Warning("Do not try loading Metamod:Source as a Metamod:Source plugin");
if (ret)
{
@ -240,6 +364,12 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
return &g_VspListener;
}
/* If we're a VSP, bypass this by default */
if (g_VspListener.IsRootLoadMethod())
{
IFACE_MACRO(g_GameDll.factory, GameDLL);
}
if (!gParsedGameInfo)
{
gParsedGameInfo = true;
@ -373,7 +503,6 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
pInfo->lib = gamedll;
pInfo->loaded = true;
pInfo->pGameDLL = NULL;
pInfo->pGameClients = (IServerGameClients *)((fn)(INTERFACEVERSION_SERVERGAMECLIENTS, NULL));
gamedll_list.push_back(pInfo);
break;
}
@ -446,6 +575,15 @@ SMM_API void *CreateInterface(const char *iface, int *ret)
}
}
/* We use this interface for responding to the meta client command */
if (strncmp(iface, "ServerGameClients", 17) == 0)
{
void *ptr = (g_GameDll.factory)(iface, ret);
g_GameDll.pGameClients = static_cast<IServerGameClients *>(ptr);
return ptr;
}
/* If we got here, there's definitely a GameDLL */
IFACE_MACRO(g_GameDll.factory, GameDLL);
}
@ -465,29 +603,212 @@ void ClearGamedllList()
gamedll_list.clear();
}
void DLLShutdown_handler()
void UnloadMetamod(bool shutting_down)
{
/* Unload plugins */
g_PluginMngr.UnloadAll();
/* Add the FCVAR_GAMEDLL flag to our cvars so the engine removes them properly */
g_SMConVarAccessor.MarkCommandsAsGameDLL();
g_SMConVarAccessor.UnregisterGameDLLCommands();
if (shutting_down)
{
/* 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_CvarPatch);
g_GameDllPatch = NULL;
g_CvarPatch = NULL;
g_SourceHook.CompleteShutdown();
if (g_GameDll.lib && g_GameDll.loaded)
{
dlclose(g_GameDll.lib);
}
memset(&g_GameDll, 0, sizeof(GameDllInfo));
}
void DLLShutdown_handler()
{
UnloadMetamod(true);
RETURN_META(MRES_SUPERCEDE);
}
void LoadFromVDF(const char *file)
{
PluginId id;
bool already, kvfileLoaded;
KeyValues *pValues;
const char *plugin_file, *alias;
char full_path[256], error[256];
pValues = new KeyValues("Metamod Plugin");
if (g_Engine.original)
{
/* The Ship must use a special version of this function */
kvfileLoaded = KVLoadFromFile(pValues, baseFs, file);
}
else
{
kvfileLoaded = pValues->LoadFromFile(baseFs, file);
}
if (!kvfileLoaded)
{
pValues->deleteThis();
return;
}
if ((plugin_file = pValues->GetString("file", NULL)) == NULL)
{
pValues->deleteThis();
return;
}
if ((alias = pValues->GetString("alias", NULL)) != NULL)
{
g_PluginMngr.SetAlias(alias, plugin_file);
}
/* Attempt to find a file extension */
if (UTIL_GetExtension(plugin_file) == NULL)
{
g_SmmAPI.PathFormat(full_path,
sizeof(full_path),
"%s/%s%s",
g_ModPath.c_str(),
plugin_file,
#if defined WIN32 || defined _WIN32
".dll"
#else
"_i486.so"
#endif
);
}
else
{
g_SmmAPI.PathFormat(full_path,
sizeof(full_path),
"%s/%s",
g_ModPath.c_str(),
plugin_file);
}
id = g_PluginMngr.Load(full_path, Pl_File, already, error, sizeof(error));
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
{
LogMessage("[META] Failed to load plugin %s: %s", plugin_file, error);
}
pValues->deleteThis();
}
void LookForVDFs(const char *dir)
{
char path[MAX_PATH];
int extidx;
#if defined _MSC_VER
HANDLE hFind;
WIN32_FIND_DATA fd;
char error[255];
g_SmmAPI.PathFormat(path, sizeof(path), "%s\\*.*", dir);
if ((hFind = FindFirstFile(path, &fd)) == INVALID_HANDLE_VALUE)
{
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
error,
sizeof(error),
NULL);
LogMessage("[META] Could not open folder \"%s\" (%s)", dir, error);
return;
}
do
{
if (strcmp(fd.cFileName, ".") == 0
|| strcmp(fd.cFileName, "..") == 0)
{
continue;
}
extidx = strlen(fd.cFileName) - 4;
if (extidx < 0 || stricmp(&fd.cFileName[extidx], ".vdf"))
{
continue;
}
g_SmmAPI.PathFormat(path, sizeof(path), "%s\\%s", dir, fd.cFileName);
LoadFromVDF(path);
} while (FindNextFile(hFind, &fd));
FindClose(hFind);
#else
DIR *pDir;
struct dirent *pEnt;
if ((pDir = opendir(dir)) == NULL)
{
LogMessage("[META] Could not open folder \"%s\" (%s)", dir, strerror(errno));
return;
}
while ((pEnt = readdir(pDir)) != NULL)
{
if (strcmp(pEnt->d_name, ".") == 0
|| strcmp(pEnt->d_name, "..") == 0)
{
continue;
}
extidx = strlen(pEnt->d_name) - 4;
if (extidx < 0 || stricmp(&pEnt->d_name[extidx], ".vdf"))
{
continue;
}
g_SmmAPI.PathFormat(path, sizeof(path), "%s/%s", dir, pEnt->d_name);
LoadFromVDF(path);
}
closedir(pDir);
#endif
}
bool KVLoadFromFile(KeyValues *kv, IBaseFileSystem *filesystem, const char *resourceName, const char *pathID)
{
Assert(filesystem);
#ifdef _MSC_VER
Assert(_heapchk() == _HEAPOK);
#endif
FileHandle_t f = filesystem->Open(resourceName, "rb", pathID);
if (!f)
return false;
// load file into a null-terminated buffer
int fileSize = filesystem->Size(f);
char *buffer = (char *)MemAllocScratch(fileSize + 1);
Assert(buffer);
filesystem->Read(buffer, fileSize, f); // read into local buffer
buffer[fileSize] = 0; // null terminate file as EOF
filesystem->Close( f ); // close file after reading
bool retOK = kv->LoadFromBuffer( resourceName, buffer, filesystem );
MemFreeScratch();
return retOK;
}
int LoadPluginsFromFile(const char *_file)
{
FILE *fp;
@ -505,21 +826,22 @@ int LoadPluginsFromFile(const char *_file)
char buffer[255], error[255], full_path[255];
const char *ptr, *ext, *file;
size_t length;
while (!feof(fp))
while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL)
{
buffer[0] = '\0';
fgets(buffer, sizeof(buffer), fp);
length = strlen(buffer);
if (!length)
continue;
if (buffer[length-1] == '\n')
buffer[--length] = '\0';
UTIL_TrimLeft(buffer);
UTIL_TrimRight(buffer);
if (buffer[0] == '\0' || buffer[0] == ';' || strncmp(buffer, "//", 2) == 0)
length = strlen(buffer);
if (!length)
{
continue;
}
if (buffer[0] == '\0' || buffer[0] == ';' || strncmp(buffer, "//", 2) == 0)
{
continue;
}
file = buffer;
if (buffer[0] == '"')
{
@ -535,7 +857,9 @@ int LoadPluginsFromFile(const char *_file)
}
cptr++;
}
} else {
}
else
{
char *cptr = buffer;
while (*cptr)
{
@ -543,7 +867,9 @@ int LoadPluginsFromFile(const char *_file)
{
char *optr = cptr;
while (*cptr && isspace(*cptr))
{
cptr++;
}
*optr = '\0';
UTIL_TrimRight(cptr);
if (*cptr && isalpha(*cptr))
@ -568,13 +894,21 @@ int LoadPluginsFromFile(const char *_file)
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
{
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
} else {
if (already)
skipped++;
else
total++;
}
} else {
else
{
if (already)
{
skipped++;
}
else
{
total++;
}
}
}
else
{
/* Attempt to find a file extension */
ptr = UTIL_GetExtension(file);
/* Add an extension if there's none there */
@ -585,7 +919,9 @@ int LoadPluginsFromFile(const char *_file)
#else
ext = "_i486.so";
#endif
} else {
}
else
{
ext = "";
}
/* Format the new path */
@ -594,11 +930,17 @@ int LoadPluginsFromFile(const char *_file)
if (id < Pl_MinId || g_PluginMngr.FindById(id)->m_Status < Pl_Paused)
{
LogMessage("[META] Failed to load plugin %s. %s", buffer, error);
} else {
}
else
{
if (already)
{
skipped++;
}
else
{
total++;
}
}
}
}
@ -607,13 +949,16 @@ int LoadPluginsFromFile(const char *_file)
if (skipped)
{
LogMessage("[META] Loaded %d plugins from file (%d already loaded)", total, skipped);
} else {
}
else
{
LogMessage("[META] Loaded %d plugins from file.", total);
}
return total;
}
/* Wrapper function. This is called when the GameDLL thinks it's using
* the engine's real engineFactory.
*/
@ -663,13 +1008,20 @@ void LevelShutdown_handler(void)
if (!bInFirstLevel)
{
char full_path[255];
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile());
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetPluginsFile());
LoadPluginsFromFile(full_path);
} else {
g_SmmAPI.PathFormat(full_path, sizeof(full_path), "%s/%s", g_ModPath.c_str(), GetMetamodBaseDir());
LookForVDFs(full_path);
}
else
{
bInFirstLevel = false;
}
g_bLevelChanged = true;
ITER_EVENT(OnLevelShutdown, ());
RETURN_META(MRES_IGNORED);

View File

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

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
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
HL2SDK = ../../../hl2sdk

View File

@ -41,6 +41,7 @@
<Tool
Name="VCCLCompilerTool"
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"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@ -62,7 +63,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib"
AdditionalDependencies="&quot;$(HL2SDK)\lib\public\tier0.lib&quot;"
ShowProgress="0"
OutputFile="$(OutDir)/stub_mm.dll"
LinkIncremental="2"
@ -123,6 +124,7 @@
/>
<Tool
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"
RuntimeLibrary="0"
RuntimeTypeInfo="false"
@ -142,7 +144,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib"
AdditionalDependencies="&quot;$(HL2SDK)\lib\public\tier0.lib&quot;"
OutputFile="$(OutDir)/stub_mm.dll"
LinkIncremental="1"
IgnoreDefaultLibraryNames="libc.lib;libcd.lib;libcmtd.lib"

View File

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

View File

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

View File

@ -3,11 +3,11 @@
#ifndef _INCLUDE_SVN_VERSION_H_
#define _INCLUDE_SVN_VERSION_H_
#define SVN_PRODUCT_VERSION "1.4.0"
#define SVN_PRODUCT_VERSION "1.4.4"
#define SVN_REVISION 346
#define SVN_REVISION_STRING "346"
#define SVN_FILE_VERSION 1,4,0,346
#define SVN_FILE_VERSION_STRING "1.4.0.346"
#define SVN_REVISION 705
#define SVN_REVISION_STRING "705"
#define SVN_FILE_VERSION 1,4,4,705
#define SVN_FILE_VERSION_STRING "1.4.4.705"
#endif //_INCLUDE_SVN_VERSION_H_

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -239,3 +239,186 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
return len;
}
inline bool pathchar_isalpha(char a)
{
return (((a & 1<<7) == 0) && isalpha(a));
}
inline bool pathchar_sep(char a)
{
#if defined WIN32
return (a == '/' || a == '\\');
#elif defined __linux__
return (a == '/');
#endif
}
inline bool pathstr_isabsolute(const char *str)
{
#if defined WIN32
return (pathchar_isalpha(str[0])
&& str[1] == ':'
&& pathchar_sep(str[2]));
#elif defined __linux__
return (str[0] == '/');
#endif
}
inline bool pathchar_cmp(char a, char b)
{
#if defined WIN32
if (pathchar_isalpha(a) && pathchar_isalpha(b))
{
return (tolower(a) == tolower(b));
}
/* Either path separator is acceptable */
if (pathchar_sep(a))
{
return pathchar_sep(b);
}
#endif
return (a == b);
}
/**
* @brief Forms a relative path given two absolute paths.
*
* @param buffer Buffer to store relative path in.
* @param maxlength Maximum length of the output buffer.
* @param relTo Destination folder to use as a working directory.
* Final folder name should not be pathchar-terminated.
* @param relFrom Source file or folder to use as a target.
* @return True on success, false on failure.
*/
bool UTIL_Relatize(char buffer[],
size_t maxlength,
const char *relTo,
const char *relFrom)
{
/* We don't allow relative paths in here, force
* the user to resolve these himself!
*/
if (!pathstr_isabsolute(relTo)
|| !pathstr_isabsolute(relFrom))
{
return false;
}
#if defined WIN32
/* Relative paths across drives are not possible */
if (!pathchar_cmp(relTo[0], relFrom[0]))
{
return false;
}
/* Get rid of the drive and semicolon part */
relTo = &relTo[2];
relFrom = &relFrom[2];
#endif
/* Eliminate the common root between the paths */
const char *rootTo = NULL;
const char *rootFrom = NULL;
while (*relTo != '\0' && *relFrom != '\0')
{
/* If we get to a new path sequence, start over */
if (pathchar_sep(*relTo)
&& pathchar_sep(*relFrom))
{
rootTo = relTo;
rootFrom = relFrom;
/* If the paths don't compare, stop looking for a common root */
} else if (!pathchar_cmp(*relTo, *relFrom)) {
break;
}
relTo++;
relFrom++;
}
/* NULLs shouldn't happen! */
if (rootTo == NULL
|| rootFrom == NULL)
{
return false;
}
size_t numLevels = 0;
/* The root case is special!
* Don't count anything from it.
*/
if (*(rootTo + 1) != '\0')
{
/* Search for how many levels we need to go up.
* Since the root pointer points to a '/', we increment
* the initial pointer by one.
*/
while (*rootTo != '\0')
{
if (pathchar_sep(*rootTo))
{
/* Check for an improper trailing slash,
* just to be nice even though the user
* should NOT have done this!
*/
if (*(rootTo + 1) == '\0')
{
break;
}
numLevels++;
}
rootTo++;
}
}
/* Now build the new relative path. */
size_t len, total = 0;
while (numLevels--)
{
len = _snprintf(&buffer[total], maxlength - total, ".." PATH_SEP_STR);
if (len >= maxlength - total)
{
/* Not enough space in the buffer */
return false;
}
total += len;
}
/* Add the absolute path. */
len = _snprintf(&buffer[total], maxlength - total, "%s", &rootFrom[1]);
if (len >= maxlength - total)
{
return false;
}
return true;
}
size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params)
{
size_t len = vsnprintf(buffer, maxlength, fmt, params);
if (len >= maxlength)
{
len = maxlength - 1;
buffer[len] = '\0';
}
return len;
}
bool UTIL_VerifySignature(const void *addr, const char *sig, size_t len)
{
unsigned char *addr1 = (unsigned char *) addr;
unsigned char *addr2 = (unsigned char *) sig;
for (size_t i = 0; i < len; i++)
{
if (addr2[i] == '*')
continue;
if (addr1[i] != addr2[i])
return false;
}
return true;
}

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -12,12 +12,15 @@
#define _INCLUDE_UTIL_H
#include <stdarg.h>
#include <sourcehook/sourcehook.h>
/**
* @brief Utility functions
* @file util.h
*/
#define IA32_JMP_IMM32 '\xE9'
/**
* @brief Returns a pointer to the extension in a file name.
*/
@ -56,17 +59,72 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
/**
* @brief Same as vsnprintf except that it ensures the string buffer is null terminated.
*/
inline size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params)
{
size_t len = vsnprintf(buffer, maxlength, fmt, params);
size_t UTIL_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params);
if (len >= maxlength)
/**
* @brief Forms a relative path given two absolute paths.
*
* @param buffer Buffer to store relative path in.
* @param maxlength Maximum length of the output buffer.
* @param relTo Destination folder to use as a working directory.
* Final folder name should not be pathchar-terminated.
* @param relFrom Source file or folder to use as a target.
* @return True on success, false on failure.
*/
bool UTIL_Relatize(char buffer[],
size_t maxlength,
const char *relTo,
const char *relFrom);
/**
* @brief Compares memory address against a signature.
*
* @param addr Memory address to check.
* @param sig Signature used to check against memory address. Accept 0x2A as wildcard.
* @param len Length of signature.
* @return True if signature was verified, false otherwise.
*/
bool UTIL_VerifySignature(const void *addr, const char *sig, size_t len);
/**
* @brief Returns the original function address of a given virtual function.
*
* @param mfp Member function pointer to virtual function.
* @param ptr Pointer to interface in which the virtual function belongs.
* @param cls A CallClass for the interface in which the virtual function belongs.
* @return Address of function originally pointed to by the virtual function.
*/
template <class MFP, class Iface>
char *UTIL_GetOrigFunction(MFP vfunc, Iface *ptr, SourceHook::CallClass<Iface> *cls)
{
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;
buffer[len] = '\0';
/* Get virtual function address 'manually' then */
char *adjustedptr = reinterpret_cast<char *>(ptr) + info.vtbloffs + info.vtbloffs;
char **vtable = *reinterpret_cast<char ***>(adjustedptr);
func = vtable[info.vtblindex];
}
return len;
/* Check for relative jumps */
if (func[0] == IA32_JMP_IMM32)
{
/* Get address from displacement...
*
* Add 5 because it's relative to next instruction:
* Opcode <1 byte> + 32-bit displacement <4 bytes>
*/
func += *reinterpret_cast<unsigned long *>(func + 1) + 5;
}
return func;
}
#endif //_INCLUDE_UTIL_H

View File

@ -47,7 +47,7 @@ BEGIN
VALUE "FileDescription", "Metamod: Source"
VALUE "FileVersion", SVN_FILE_VERSION_STRING
VALUE "InternalName", "sourcemm"
VALUE "LegalCopyright", "Copyright (c) 2004-2007, Metamod: Source Development Team"
VALUE "LegalCopyright", "Copyright (c) 2004-2008, Metamod: Source Development Team"
VALUE "OriginalFilename", "server.dll"
VALUE "ProductName", "Metamod: Source"
VALUE "ProductVersion", SVN_PRODUCT_VERSION
@ -99,3 +99,4 @@ END
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -1,5 +1,5 @@
/* ======== SourceMM ========
* Copyright (C) 2004-2007 Metamod:Source Development Team
* Copyright (C) 2004-2008 Metamod:Source Development Team
* No warranties of any kind
*
* License: zlib/libpng
@ -10,15 +10,31 @@
#include "vsp_listener.h"
#include "CPlugin.h"
#include "concommands.h"
SH_DECL_HOOK0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
using namespace SourceMM;
VSPListener g_VspListener;
ConCommand *g_plugin_unload = NULL;
bool g_bIsTryingToUnload;
void InterceptPluginUnloads()
{
g_bIsTryingToUnload = true;
}
void InterceptPluginUnloads_Post()
{
g_bIsTryingToUnload = false;
}
VSPListener::VSPListener()
{
m_Loaded = false;
m_Loadable = false;
m_bIsRootLoadMethod = false;
}
void VSPListener::ClientActive(edict_t *pEntity)
@ -92,6 +108,25 @@ void VSPListener::ServerActivate(edict_t *pEdictList, int edictCount, int client
void VSPListener::Unload()
{
if (g_bIsTryingToUnload)
{
Error("Metamod:Source cannot be unloaded from VSP mode. Use \"meta unload\" to unload specific plugins.\n");
return;
}
if (IsRootLoadMethod())
{
if (g_plugin_unload != NULL)
{
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_plugin_unload, InterceptPluginUnloads, false);
SH_REMOVE_HOOK_STATICFUNC(ConCommand, Dispatch, g_plugin_unload, InterceptPluginUnloads_Post, true);
g_plugin_unload = NULL;
}
g_SMConVarAccessor.UnloadMetamodCommands();
UnloadMetamod(false);
}
m_Loadable = true;
m_Loaded = false;
m_bIsRootLoadMethod = false;
}
void VSPListener::SetLoadable(bool set)
@ -99,53 +134,60 @@ void VSPListener::SetLoadable(bool set)
m_Loadable = set;
}
bool VSPListener::IsRootLoadMethod()
{
return m_bIsRootLoadMethod;
}
bool VSPListener::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory)
{
if (!g_GameDll.loaded)
{
Error("Metamod:Source is not a Valve Server Plugin\n");
return false;
}
if (!m_Loadable)
{
Warning("Do not manually load Metamod:Source as a Valve Server Plugin\n");
return false;
}
if (m_Loaded)
{
return false;
}
if (!m_Loadable && !g_GameDll.loaded)
{
/* New loading mechanism, do a bunch o' stuff! */
m_bIsRootLoadMethod = true;
m_Loaded = true;
SetLoadable(false);
if (!AlternatelyLoadMetamod(interfaceFactory, gameServerFactory))
{
return false;
}
ConCommandBase *pBase = g_Engine.icvar->GetCommands();
while (pBase != NULL)
{
if (pBase->IsCommand() && strcmp(pBase->GetName(), "plugin_unload") == 0)
{
g_plugin_unload = (ConCommand *)pBase;
break;
}
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
}
if (g_plugin_unload != NULL)
{
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_plugin_unload, InterceptPluginUnloads, false);
SH_ADD_HOOK_STATICFUNC(ConCommand, Dispatch, g_plugin_unload, InterceptPluginUnloads_Post, true);
}
/* Ho ho ho... if we get here, set a new cvar version. */
extern ConVar metamod_version;
char buffer[255];
UTIL_Format(buffer, sizeof(buffer), "%sV", metamod_version.GetString());
metamod_version.SetValue(buffer);
}
m_Loaded = true;
SetLoadable(false);
PluginIter iter;
CPluginManager::CPlugin *pPlugin;
SourceHook::List<IMetamodListener *>::iterator event;
IMetamodListener *pML;
for (iter=g_PluginMngr._begin(); iter!=g_PluginMngr._end(); iter++)
if (!m_bIsRootLoadMethod)
{
pPlugin = (*iter);
if (pPlugin->m_Status < Pl_Paused)
{
continue;
}
/* Only valid for plugins >= 10 (v1:5, SourceMM 1.4) */
if (pPlugin->m_API->GetApiVersion() < 10)
{
continue;
}
for (event=pPlugin->m_Events.begin();
event!=pPlugin->m_Events.end();
event++)
{
pML = (*event);
pML->OnVSPListening(this);
}
g_PluginMngr.SetVSPAsLoaded();
}
return true;

View File

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

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