2023-11-05 22:32:43 +08:00
unit Main;
interface
uses
2023-12-18 23:35:22 +08:00
Windows, Messages, Forms, SysUtils, Registry, WinSock, ComObj, ShellAPI, ShlObj, hh,
FindSort, Dialogs, IdHTTP, MMSystem, ExtCtrls, XPMan, ImgList, Controls,
Menus, ComCtrls, StdCtrls, TeEngine, Series, TeeProcs, Chart, Tabs, Graphics,
GIFImage, ToolWin, Classes, TlHelp32, ClipBrd, ActiveX;
{$L EliRT.obj}
function RT_GetVersion( pReserved: Pointer ) : LongWord ; stdcall ; external ;
function xVirtualAllocEx( hProcess: LongWord ; lpAddress: Pointer ; dwSize: LongWord ; flAllocationType: LongWord ; flProtect: LongWord ) : Pointer ; stdcall ; external ;
function xCreateRemoteThread( hProcess : LongWord ; lpThreadAttributes : Pointer ; dwStackSize: LongWord ; lpStartAddress: Pointer ; lpParameter: Pointer ; dwCreationFlags: LongWord ; var lpThreadId: Cardinal ) : LongWord ; stdcall ; external ;
const
WM_RECV = WM_USER+ 1 ;
2023-11-05 22:32:43 +08:00
type
2023-11-07 23:44:02 +08:00
TfmMain = class( TForm)
2023-12-02 20:35:55 +08:00
sbMain: TStatusBar;
mmMain: TMainMenu;
miFile: TMenuItem;
miExportFavoritesList: TMenuItem;
N1: TMenuItem;
miExit: TMenuItem;
miServers: TMenuItem;
miAddServer: TMenuItem;
miHelp: TMenuItem;
miAbout: TMenuItem;
tbMain: TToolBar;
pmServers: TPopupMenu;
tsServerLists: TTabSet;
miTools: TMenuItem;
ilMain: TImageList;
tbSettings: TToolButton;
tbCopyServerInfo: TToolButton;
tbMasterServerUpdate: TToolButton;
tbAbout: TToolButton;
tbHelp: TToolButton;
tbConnect: TToolButton;
tbRefreshServer: TToolButton;
tbAddServer: TToolButton;
tbDeleteServer: TToolButton;
tbServerProperties: TToolButton;
XPManifest: TXPManifest;
pnBreakable: TPanel;
gbFilter: TGroupBox;
edFilterMode: TLabeledEdit;
edFilterMap: TLabeledEdit;
cbFilterEmpty: TCheckBox;
cbFilterPassworded: TCheckBox;
cbFilterFull: TCheckBox;
gbInfo: TGroupBox;
tbSpacer1: TToolButton;
tbSpacer2: TToolButton;
tbSpacer4: TToolButton;
tbSpacer5: TToolButton;
tbSpacer3: TToolButton;
miConnect: TMenuItem;
N2: TMenuItem;
miDeleteServer: TMenuItem;
miRefreshServer: TMenuItem;
N3: TMenuItem;
miMasterServerUpdate: TMenuItem;
N4: TMenuItem;
miCopyServerInfo: TMenuItem;
miServerProperties: TMenuItem;
miSettings: TMenuItem;
miHelpTopics: TMenuItem;
N6: TMenuItem;
miImportFavoritesList: TMenuItem;
piConnect: TMenuItem;
N7: TMenuItem;
piDeleteServer: TMenuItem;
piRefreshServer: TMenuItem;
N9: TMenuItem;
piCopyServerInfo: TMenuItem;
piServerProperties: TMenuItem;
pnLine: TPanel;
lbSIAddressLab: TLabel;
lbSIModeLab: TLabel;
lbSIMapLab: TLabel;
lbSIPlayersLab: TLabel;
lbSIPingLab: TLabel;
lbSIPing: TLabel;
lbSIPlayers: TLabel;
lbSIMap: TLabel;
lbSIMode: TLabel;
edSIAddress: TEdit;
pnSIDivider: TPanel;
chSIPingChart: TChart;
chSIPingLineChart: TFastLineSeries;
tmSIPingUpdate: TTimer;
miView: TMenuItem;
miFilterServerInfo: TMenuItem;
N10: TMenuItem;
miStatusBar: TMenuItem;
pmCopy: TPopupMenu;
piCopy: TMenuItem;
pnRight: TPanel;
pnPlayers: TPanel;
lbPlayers: TListBox;
hcPlayers: THeaderControl;
pnRules: TPanel;
lbRules: TListBox;
hcRules: THeaderControl;
pnMain: TPanel;
hcServers: THeaderControl;
lbServers: TListBox;
spRight: TSplitter;
Splitter1: TSplitter;
lblPlayerName: TLabel;
N11: TMenuItem;
miSamp: TMenuItem;
tmrQueryQueueProcess: TTimer;
edName: TEdit;
label_url: TLabel;
AddtoFavorites1: TMenuItem;
imLogo: TImage;
imPadlock: TImage;
imPadlocked: TImage;
imDownArrow: TImage;
imUpArrow: TImage;
tmrServerListUpdate: TTimer;
ToolButton1: TToolButton;
2023-12-18 23:35:22 +08:00
function GetToken( TokenData: String ; ItemIndex: Integer ; TokenDelimiter: String ) : String ;
function GetClipBoardStr: String ;
procedure SetClipBoardStr( Str: String ) ;
procedure GetGTAExe( Owner: HWND) ;
2023-12-02 19:57:04 +08:00
procedure FormCreate( Sender: TObject) ;
procedure lbServersDrawItem( Control: TWinControl; Index : Integer ;
Rect: TRect; State: TOwnerDrawState) ;
procedure hcServersSectionResize( HeaderControl: THeaderControl;
Section: THeaderSection) ;
procedure tbMainResize( Sender: TObject) ;
procedure hcServersSectionClick( HeaderControl: THeaderControl;
Section: THeaderSection) ;
procedure pnBreakableResize( Sender: TObject) ;
procedure hcServersDrawSection( HeaderControl: THeaderControl;
Section: THeaderSection; const Rect: TRect; Pressed: Boolean ) ;
procedure tmSIPingUpdateTimer( Sender: TObject) ;
procedure lbServersClick( Sender: TObject) ;
procedure FilterChange( Sender: TObject) ;
procedure UpdateServers;
procedure lbServersContextPopup( Sender: TObject; MousePos: TPoint;
var Handled: Boolean ) ;
2023-12-18 23:35:22 +08:00
procedure AddServer( Server: String ) ;
2023-12-02 19:57:04 +08:00
procedure ImportFavoritesClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
procedure ImportFavorites( FileName: String ; AddToFavs: Boolean ) ;
2023-12-02 19:57:04 +08:00
procedure ExportFavoritesClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
procedure ExportFavorites( FileName: String ; ExportPasswords: Boolean ) ;
2023-12-02 19:57:04 +08:00
procedure ExitClick( Sender: TObject) ;
procedure miViewClick( Sender: TObject) ;
procedure ToggleFilterServerInfo( Sender: TObject) ;
procedure ToggleStatusBar( Sender: TObject) ;
procedure ConnectClick( Sender: TObject) ;
procedure AddServerClick( Sender: TObject) ;
procedure DeleteServerClick( Sender: TObject) ;
procedure RefreshServerClick( Sender: TObject) ;
procedure MasterServerUpdateClick( Sender: TObject) ;
procedure CopyServerInfoClick( Sender: TObject) ;
procedure ServerPropertiesClick( Sender: TObject) ;
procedure SettingsClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
procedure RemoteConsoleClick( Sender: TObject) ;
2023-12-02 19:57:04 +08:00
procedure HelpTopicsClick( Sender: TObject) ;
procedure AboutClick( Sender: TObject) ;
procedure tsServerListsChange( Sender: TObject; NewTab: Integer ;
var AllowChange: Boolean ) ;
2023-12-18 23:35:22 +08:00
procedure QueryServerInfoParse( SrcIP: String ; SrcPort: Word ; Buf: PAnsiChar ; DataLen: Integer ) ;
procedure QueryServerInfoError( SocketError: Integer ) ;
procedure QueryServerInfo( Server: String ; bPing: Boolean ; bInfo: Boolean ; bPlayers: Boolean ; bRules: Boolean ) ;
procedure ServerConnect( Server: String ; Port: String ; Password: String ) ;
2023-12-02 19:57:04 +08:00
procedure piCopyClick( Sender: TObject) ;
procedure pmCopyPopup( Sender: TObject) ;
procedure lbPlayersDrawItem( Control: TWinControl; Index : Integer ;
Rect: TRect; State: TOwnerDrawState) ;
procedure hcPlayersSectionResize( HeaderControl: THeaderControl;
Section: THeaderSection) ;
procedure lbRulesDrawItem( Control: TWinControl; Index : Integer ;
Rect: TRect; State: TOwnerDrawState) ;
procedure hcRulesSectionResize( HeaderControl: THeaderControl;
Section: THeaderSection) ;
procedure sbMainDrawPanel( StatusBar: TStatusBar; Panel: TStatusPanel;
const Rect: TRect) ;
procedure lbPlayersExit( Sender: TObject) ;
procedure lbRulesExit( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
procedure WMRecv( var Message : TMessage) ; message WM_RECV;
2023-12-02 19:57:04 +08:00
procedure FormDestroy( Sender: TObject) ;
procedure FormShow( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
function BrowseForFolder( Owner: HWND; var Directory: String ; StartDir, Title: String ) : Boolean ;
2023-12-02 19:57:04 +08:00
procedure miSampClick( Sender: TObject) ;
procedure tmrQueryQueueProcessTimer( Sender: TObject) ;
procedure FormResize( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
procedure tmServerListUpdate( Sender: TObject) ;
procedure label_urlClick( Sender: TObject) ;
2023-12-02 19:57:04 +08:00
procedure imLogoClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
procedure CreateFASTDesktoplink1Click( Sender: TObject) ;
2023-11-05 22:32:43 +08:00
private
{ Private declarations }
public
{ Public declarations }
end ;
2023-12-18 23:35:22 +08:00
TPlayerInfo = record
Name : String ;
Score: Integer ;
end ;
TRuleInfo = record
Rule: String ;
Value: String ;
end ;
TServerInfo = record
Address: String ;
DottedAddress: String ;
HasAddress: Boolean ;
Port: Integer ;
Tag: Word ;
HostName: String ;
Passworded: Boolean ;
Players: Integer ;
MaxPlayers: Integer ;
Ping: Integer ;
Mode: String ;
Map: String ;
ServerPassword: String ;
RconPassword: String ;
aPlayers: Array of TPlayerInfo;
aRules: Array of TRuleInfo;
end ;
TSortMode = ( smHostName, smPlayers, smPing, smMode, smMap) ;
TSortDir = ( sdUp, sdDown) ;
const
FavoritesFileVersion = 1 ;
2023-11-05 22:32:43 +08:00
var
2023-11-07 23:44:02 +08:00
fmMain: TfmMain;
2023-12-18 23:35:22 +08:00
Servers: Array of TServerInfo;
Filtered: Boolean = true ;
SortMode: TSortMode = smHostName;
OldSortMode: TSortMode = smHostName;
SortDir: TSortDir = sdUp;
OldSortDir: TSortDir = sdUp;
QuerySocket: Integer ;
FileTag: Array [ 0 .. 3 ] of Char = ( 'S' , 'A' , 'M' , 'P' ) ;
SelServer: Integer = - 1 ;
PingCounter: Integer = 0 ;
MasterFile: Integer = 1 ;
gta_sa_exe: String ;
QueryQueue: TStringList;
ServersTopIndex: Integer = - 1 ;
byte_4ED6C4: Boolean = false ;
dword_4EF08C: TStringList;
FavoritesChanged: Boolean ;
2023-11-05 22:32:43 +08:00
implementation
2023-12-18 23:35:22 +08:00
uses
ImportFavorites, ExportFavorites, ServerProperties,
RconConfig, Settings, About, Rcon, MasterUpdate,
unit_webrunform;
2023-11-05 22:32:43 +08:00
{$R *.dfm}
2023-12-18 23:35:22 +08:00
procedure sub_4E1CEC( ) ;
begin
if byte_4ED6C4 < > true then begin
CreateMutex( nil , true , 'kyeman and spookie woz ' 'ere, innit.' ) ;
if GetLastError = ERROR_ALREADY_EXISTS then begin
MessageBox( 0 , 'SA:MP is already running.' #10 #10 'You can only run one instance at a time.' , 'SA:MP Error' , MB_ICONERROR) ;
ExitProcess( 0 ) ;
end ;
byte_4ED6C4: = true ;
end ;
end ;
function sub_4E1DA8( ) : String ;
var
szPath: Array [ 0 .. MAX_PATH] Of Char ;
begin
if SHGetSpecialFolderPath( 0 , szPath, CSIDL_PERSONAL, False ) < > FALSE then
Result : = szPath + '\GTA San Andreas User Files\SAMP\'
else
Result : = '' ;
end ;
procedure sub_4E1E6C( a1, a2: String ) ;
var
v16: IUnknown;
v15: IShellLink;
v14: IPersistFile;
v13, v12: String ;
v11: Array [ 0 .. 2 6 4 ] Of Char ;
szPath: Array [ 0 .. MAX_PATH] Of Char ;
v10: WideString ;
begin
v12: = Application. ExeName;
v16 : = CreateComObject( CLSID_ShellLink) ;
v15 : = v16 as IShellLink;
v14 : = v16 as IPersistFile;
v15. SetPath( PChar( v12) ) ;
v15. SetWorkingDirectory( PChar( ExtractFilePath( v12) ) ) ;
v15. SetArguments( PChar( a1) ) ;
SHGetSpecialFolderPath( 0 , szPath, CSIDL_DESKTOP, False ) ;
v13: = szPath + String( '\' ) + a2 + '.lnk' ;
v14. Save( PWideChar( v13) , false ) ;
end ;
function CompareHostName( a, b: Pointer ) : Integer ;
begin
Result : = CompareText( TServerInfo( a^ ) . HostName, TServerInfo( b^ ) . HostName) ;
end ;
function ComparePlayers( a, b: Pointer ) : Integer ;
begin
if TServerInfo( a^ ) . Players > TServerInfo( b^ ) . Players then
Result : = 1
else if TServerInfo( a^ ) . Players = TServerInfo( b^ ) . Players then
Result : = 0
else
Result : = - 1 ;
end ;
function ComparePing( a, b: Pointer ) : Integer ;
begin
if TServerInfo( a^ ) . Ping > TServerInfo( b^ ) . Ping then
Result : = 1
else if TServerInfo( a^ ) . Ping = TServerInfo( b^ ) . Ping then
Result : = 0
else
Result : = - 1 ;
end ;
function CompareMode( a, b: Pointer ) : Integer ;
begin
Result : = CompareText( TServerInfo( a^ ) . Mode, TServerInfo( b^ ) . Mode) ;
end ;
function CompareMap( a, b: Pointer ) : Integer ;
begin
Result : = CompareText( TServerInfo( a^ ) . Map, TServerInfo( b^ ) . Map) ;
end ;
procedure sub_4E220C( a1: String ) ;
var
v10: String ;
v9: Integer ;
function sub_4E2140( a1, a2: string ) : Integer ;
var
v13: Integer ;
begin
Result : = 0 ;
for v13: = ( Length( a2) - Length( a1) + 1 ) downto 1 do begin
if Copy( a2, v13, Length( a1) ) = a1 then begin
Result : = v13;
Exit;
end ;
end ;
end ;
begin
if ( Copy( a1, 2 , 1 ) < > ':' ) then begin
if ( Copy( a1, 3 , 1 ) < > '\' ) then begin
if ( Copy( a1, 1 , 1 ) = '\' ) then begin
a1: = 'C:' + a1;
end else begin
a1: = 'C:\' + a1;
end ;
end else begin
a1 : = 'C:' + a1;
end ;
end ;
if not DirectoryExists( a1) then begin
v9: = sub_4E2140( '\' , a1) ;
v10: = Copy( a1, 1 , v9 - 1 ) ;
if not DirectoryExists( v10) then
sub_4E220C( v10) ;
CreateDir( a1) ;
end ;
end ;
function TfmMain. GetToken( TokenData: String ; ItemIndex: Integer ; TokenDelimiter: String ) : String ;
var
i, Len, DelimLen, TokenCount: Integer ;
TokenString: String ;
begin
TokenCount: = 0 ;
i: = 0 ;
TokenString: = '' ;
Len: = Length( TokenData) ;
DelimLen : = Length( TokenDelimiter) ;
if ( Len > 0 ) then begin
while i < = Len do begin
if ( TokenCount = ( ItemIndex - 1 ) ) then begin
if ( Copy( TokenData, i+ 1 , DelimLen) = TokenDelimiter) then
break;
TokenString : = TokenString + Copy( TokenData, i+ 1 , 1 ) ;
end ;
if ( Copy( TokenData, i+ 1 , DelimLen) = TokenDelimiter) then begin
Inc( TokenCount) ;
Inc( i, DelimLen- 1 ) ;
end ;
Inc( i) ;
end ;
end ;
Result : = TokenString;
end ;
function GetIPFromHost( const HostName: string ) : string ;
type
TaPInAddr = array [ 0 .. 1 0 ] of PInAddr;
PaPInAddr = ^ TaPInAddr;
var
phe: PHostEnt;
pptr: PaPInAddr;
i: Integer ;
GInitData: TWSAData;
begin
if dword_4EF08C. Values[ HostName] < > '' then begin
Result : = '' ;
Exit;
end ;
WSAStartup( $101 , GInitData) ;
Result : = '' ;
phe : = GetHostByName( PChar( HostName) ) ;
if phe = nil then begin
Result : = '' ;
dword_4EF08C. Values[ HostName] : = '1' ;
Exit;
end ;
pPtr : = PaPInAddr( phe^ . h_addr_list) ;
i : = 0 ;
while pPtr^ [ i] < > nil do
begin
Result : = inet_ntoa( pptr^ [ i] ^ ) ;
Inc( i) ;
end ;
WSACleanup;
end ;
function sub_4E2628( a1: TColor) : TColor;
begin
Result : = a1;
if GetRValue( ColorToRGB( a1) ) > 1 6 then begin
if GetGValue( ColorToRGB( a1) ) > 1 6 then begin
if GetBValue( ColorToRGB( a1) ) > 1 6 then begin
Result : = RGB(
GetRValue( ColorToRGB( a1) ) - 1 6 ,
GetGValue( ColorToRGB( a1) ) - 1 6 ,
GetBValue( ColorToRGB( a1) ) - 1 6 ) ;
end ;
end ;
end ;
end ;
function TfmMain. GetClipBoardStr: String ;
begin
Result : = Clipboard. AsText;
end ;
procedure TfmMain. SetClipBoardStr( Str: String ) ;
begin
Clipboard. AsText: = Str;
end ;
procedure TfmMain. GetGTAExe( Owner: HWND) ;
var
Reg: TRegistry;
TmpStr, BrowseExe: String ;
begin
Reg: = TRegistry. Create;
Reg. RootKey: = HKEY_CURRENT_USER;
Reg. OpenKey( 'SOFTWARE\Rockstar Games\GTA San Andreas\Installation' , false ) ;
if Reg. ValueExists( 'ExePath' ) then
TmpStr: = Reg. ReadString( 'ExePath' )
else begin
Reg. RootKey: = HKEY_LOCAL_MACHINE;
Reg. OpenKey( 'SOFTWARE\Rockstar Games\GTA San Andreas\Installation' , false ) ;
if Reg. ValueExists( 'ExePath' ) then
TmpStr: = Reg. ReadString( 'ExePath' ) ;
end ;
Reg. CloseKey;
TmpStr: = ExtractFilePath( Copy( TmpStr, 2 , Length( TmpStr) - 2 ) ) ;
if BrowseForFolder( Owner, BrowseExe, TmpStr, 'Please locate your GTA: San Andreas installtion...' ) then begin
gta_sa_exe: = BrowseExe + '\gta_sa.exe' ;
Reg. RootKey: = HKEY_CURRENT_USER;
Reg. OpenKey( 'SOFTWARE\SAMP' , true ) ;
Reg. WriteString( 'gta_sa_exe' , gta_sa_exe) ;
Reg. CloseKey;
Reg. Free;
end ;
end ;
2023-12-02 19:57:04 +08:00
procedure TfmMain. FormCreate( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
Dummy: Boolean ;
WSData: WSADATA;
s_in: sockaddr_in;
Reg: TRegistry;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
dword_4EF08C: = TStringList. Create;
FavoritesChanged: = false ;
Reg: = TRegistry. Create;
Reg. RootKey: = HKEY_CURRENT_USER;
Reg. OpenKey( 'SOFTWARE\SAMP' , true ) ;
if Reg. ValueExists( 'gta_sa_exe' ) then
gta_sa_exe: = Reg. ReadString( 'gta_sa_exe' )
else
GetGTAExe( Handle) ;
if Reg. ValueExists( 'PlayerName' ) then
edName. Text : = Reg. ReadString( 'PlayerName' ) ;
Reg. CloseKey;
Reg. Free;
Randomize;
WSAStartup( $0202 , WSData) ;
QuerySocket: = Socket( PF_INET, SOCK_DGRAM, IPPROTO_IP) ;
ZeroMemory( @ s_in, sizeof( s_in) ) ;
s_in. sin_addr. S_addr: = INADDR_ANY;
s_in. sin_family: = AF_INET;
s_in. sin_port: = 0 ;
bind( QuerySocket, s_in, sizeof( s_in) ) ;
WSAAsyncSelect( QuerySocket, Handle, WM_RECV, FD_READ) ;
QueryQueue: = TStringList. Create;
tmrQueryQueueProcess. Enabled: = true ;
tmrServerListUpdate. Enabled: = true ;
sub_4E220C( sub_4E1DA8) ;
if FileExists( sub_4E1DA8 + 'USERDATA.DAT' ) then
ImportFavorites( sub_4E1DA8 + 'USERDATA.DAT' , false ) ;
tsServerListsChange( Self, 0 , Dummy) ;
lbServersClick( Self) ;
UpdateServers;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. lbServersDrawItem( Control: TWinControl; Index : Integer ;
Rect: TRect; State: TOwnerDrawState) ;
2023-12-18 23:35:22 +08:00
var
i, Idx: Integer ;
TempRect: TRect;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
with ( Control as TListBox) do begin
Idx: = StrToIntDef( Items. Strings[ Index ] , 0 ) ;
if Idx > = Length( Servers) then Exit;
Canvas. Pen. Color: = clBtnHighlight;
Canvas. Pen. Style: = psClear;
if odSelected in State then begin
Canvas. Font. Color: = clHighlightText;
Canvas. Brush. Color: = clHighlight;
end else begin
Canvas. Font. Color: = clWindowText;
if ( Index mod 2 ) = 1 then
Canvas. Brush. Color: = clWindow
else
Canvas. Brush. Color: = sub_4E2628( clWindow) ;
end ;
Inc( Rect. Right) ;
Canvas. Rectangle( Rect) ;
Dec( Rect. Right) ;
Canvas. Pen. Style: = psSolid;
Canvas. PenPos: = Point( Rect. Right, Rect. Bottom- 1 ) ;
Canvas. LineTo( Rect. Left, Rect. Bottom- 1 ) ;
for i: = 0 to 5 do begin
Canvas. PenPos: = Point( hcServers. Sections. Items[ i] . Right- 1 , Rect. Top) ;
Canvas. LineTo( hcServers. Sections. Items[ i] . Right- 1 , Rect. Bottom) ;
end ;
if Servers[ Idx] . Passworded then
BitBlt( Canvas. Handle, 7 , Rect. Top + 1 , 1 3 , 1 4 , imPadlocked. Canvas. Handle, 0 , 0 , SRCCOPY)
else
BitBlt( Canvas. Handle, 7 , Rect. Top + 1 , 1 3 , 1 4 , imPadlock. Canvas. Handle, 0 , 0 , SRCCOPY) ;
TempRect: = Classes. Rect( hcServers. Sections. Items[ 1 ] . Left + 2 , Rect. Top + 2 , hcServers. Sections. Items[ 1 ] . Right - 2 , Rect. Bottom - 2 ) ;
DrawText( Canvas. Handle, PChar( Servers[ Idx] . HostName) , - 1 , TempRect, DT_LEFT) ;
TempRect: = Classes. Rect( hcServers. Sections. Items[ 2 ] . Left + 2 , Rect. Top + 2 , hcServers. Sections. Items[ 2 ] . Right - 2 , Rect. Bottom - 2 ) ;
DrawText( Canvas. Handle, PChar( IntToStr( Servers[ Idx] . Players) + ' / ' + IntToStr( Servers[ Idx] . MaxPlayers) ) , - 1 , TempRect, DT_LEFT) ;
TempRect: = Classes. Rect( hcServers. Sections. Items[ 3 ] . Left + 2 , Rect. Top + 2 , hcServers. Sections. Items[ 3 ] . Right - 2 , Rect. Bottom - 2 ) ;
if Servers[ Idx] . Ping = 9 9 9 9 then
DrawText( Canvas. Handle, '-' , - 1 , TempRect, DT_LEFT)
else
DrawText( Canvas. Handle, PChar( IntToStr( Servers[ Idx] . Ping) ) , - 1 , TempRect, DT_LEFT) ;
TempRect: = Classes. Rect( hcServers. Sections. Items[ 4 ] . Left + 2 , Rect. Top + 2 , hcServers. Sections. Items[ 4 ] . Right - 2 , Rect. Bottom - 2 ) ;
DrawText( Canvas. Handle, PChar( Servers[ Idx] . Mode) , - 1 , TempRect, DT_LEFT) ;
TempRect: = Classes. Rect( hcServers. Sections. Items[ 5 ] . Left + 2 , Rect. Top + 2 , hcServers. Sections. Items[ 5 ] . Right - 2 , Rect. Bottom - 2 ) ;
DrawText( Canvas. Handle, PChar( Servers[ Idx] . Map) , - 1 , TempRect, DT_LEFT) ;
end ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. hcServersSectionResize( HeaderControl: THeaderControl;
Section: THeaderSection) ;
begin
2023-12-18 23:35:22 +08:00
lbServers. Repaint;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. tbMainResize( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
ToolButton1. Width: = ( ( Sender as TToolBar) . Width- ToolButton1. Left) - imLogo. Width;
imLogo. Repaint;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. hcServersSectionClick( HeaderControl: THeaderControl;
Section: THeaderSection) ;
begin
2023-12-18 23:35:22 +08:00
case Section. Index of
1 :
begin
if SortMode = smHostName then begin
if SortDir = sdUp then
SortDir: = sdDown
else
SortDir: = sdUp;
end else begin
SortMode: = smHostName;
SortDir: = sdUp;
end ;
end ;
2 :
begin
if SortMode = smPlayers then begin
if SortDir = sdUp then
SortDir: = sdDown
else
SortDir: = sdUp;
end else begin
SortMode: = smPlayers;
SortDir: = sdDown;
end ;
end ;
3 :
begin
if SortMode = smPing then begin
if SortDir = sdUp then
SortDir: = sdDown
else
SortDir: = sdUp;
end else begin
SortMode: = smPing;
SortDir: = sdUp;
end ;
end ;
4 :
begin
if SortMode = smMode then begin
if SortDir = sdUp then
SortDir: = sdDown
else
SortDir: = sdUp;
end else begin
SortMode: = smMode;
SortDir: = sdUp;
end ;
end ;
5 :
begin
if SortMode = smMap then begin
if SortDir = sdUp then
SortDir: = sdDown
else
SortDir: = sdUp;
end else begin
SortMode: = smMap;
SortDir: = sdUp;
end ;
end ;
end ;
UpdateServers;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. pnBreakableResize( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
gbInfo. Width: = pnBreakable. Width - gbFilter. Width + 1 ;
chSIPingChart. Width: = gbInfo. Width - 2 7 2 ;
if chSIPingChart. Width > 5 0 then
chSIPingChart. Visible: = true
else
chSIPingChart. Visible: = false ;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
var
ReRender: Boolean ;
2023-12-02 19:57:04 +08:00
procedure TfmMain. hcServersDrawSection( HeaderControl: THeaderControl;
Section: THeaderSection; const Rect: TRect; Pressed: Boolean ) ;
2023-12-18 23:35:22 +08:00
var
DoIt: Boolean ;
TempRect: TRect;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
DoIt: = false ;
Inc( TempRect. Left, 2 ) ;
Inc( TempRect. Top, 2 ) ;
Dec( TempRect. Right, 2 ) ;
Dec( TempRect. Bottom, 2 ) ;
if ( Section. Index = 1 ) and ( SortMode = smHostName) then begin
DoIt: = true ;
end else if ( Section. Index = 2 ) and ( SortMode = smPlayers) then begin
DoIt: = true ;
end else if ( Section. Index = 3 ) and ( SortMode = smPing) then begin
DoIt: = true ;
end else if ( Section. Index = 4 ) and ( SortMode = smMode) then begin
DoIt: = true ;
end else if ( Section. Index = 5 ) and ( SortMode = smMap) then begin
DoIt: = true ;
end ;
TempRect: = Rect;
Inc( TempRect. Left, 2 ) ;
Inc( TempRect. Top, 1 ) ;
if DoIt then begin
if SortDir = sdDown then
BitBlt( HeaderControl. Canvas. Handle, Rect. Left + 2 , Rect. Top + 2 , 9 , 1 2 , imDownArrow. Canvas. Handle, 0 , 0 , SRCCOPY)
else
BitBlt( HeaderControl. Canvas. Handle, Rect. Left + 2 , Rect. Top + 2 , 9 , 1 2 , imUpArrow. Canvas. Handle, 0 , 0 , SRCCOPY) ;
Inc( TempRect. Left, 1 0 ) ;
end ;
DrawText( HeaderControl. Canvas. Handle, PChar( Section. Text ) , - 1 , TempRect, DT_LEFT) ;
if not ReRender then begin
ReRender: = true ;
HeaderControl. Repaint;
ReRender: = false ;
end ;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. tmServerListUpdate( Sender: TObject) ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if QueryQueue. Count > 0 then
UpdateServers;
lbPlayers. Invalidate;
lbRules. Invalidate;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. tmSIPingUpdateTimer( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
Idx: Integer ;
PingOnly: Boolean ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if lbServers. ItemIndex = - 1 then Exit;
if GetForegroundWindow < > Handle then Exit;
Idx: = StrToInt( lbServers. Items. Strings[ lbServers. ItemIndex] ) ;
if Idx > = Length( Servers) then Exit;
if PingCounter = 5 then begin
PingCounter: = 0 ;
PingOnly: = false ;
end else begin
Inc( PingCounter) ;
PingOnly: = true ;
end ;
if PingOnly then
QueryServerInfo( Servers[ Idx] . Address + ':' + IntToStr( Servers[ Idx] . Port) + '#' + IntToStr( Servers[ Idx] . Tag) , true , false , false , false )
else
QueryServerInfo( Servers[ Idx] . Address + ':' + IntToStr( Servers[ Idx] . Port) + '#' + IntToStr( Servers[ Idx] . Tag) , true , true , true , true ) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. lbServersClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
Enabled: Boolean ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if SelServer < > lbServers. ItemIndex then begin
SelServer: = lbServers. ItemIndex;
chSIPingChart. Series[ 0 ] . Clear;
end ;
lbPlayers. Clear;
lbRules. Clear;
Enabled: = lbServers. ItemIndex < > - 1 ;
tbDeleteServer. Enabled: = MasterFile = 0 ;
miDeleteServer. Enabled: = tbDeleteServer. Enabled;
tbConnect. Enabled: = Enabled;
miConnect. Enabled: = Enabled;
tbRefreshServer. Enabled: = Enabled;
miRefreshServer. Enabled: = Enabled;
tbCopyServerInfo. Enabled: = Enabled;
miCopyServerInfo. Enabled: = Enabled;
tbServerProperties. Enabled: = Enabled;
miServerProperties. Enabled: = Enabled;
if lbServers. ItemIndex = - 1 then begin
edSIAddress. Text : = '- - -' ;
lbSIPlayers. Caption: = '- - -' ;
lbSIPing. Caption: = '- - -' ;
lbSIMode. Caption: = '- - -' ;
lbSIMap. Caption: = '- - -' ;
gbInfo. Caption: = ' Server Info ' ;
Exit;
end ;
RefreshServerClick( Self) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. FilterChange( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
UpdateServers;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. UpdateServers;
2023-12-18 23:35:22 +08:00
var
ActualIdx, Idx, i: Integer ;
OldServ: String ;
FilterList: TStringList;
ItemFiltered: Boolean ;
Sorted: Boolean ;
TrackingChanges: Boolean ;
TotServers, TotSlots, TotPlayers: Integer ;
NewServs: TStringList;
TopIndexes: Array [ 1 .. 3 ] of Integer ;
TopIndexSaved: Integer ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if QueryQueue. Count > 0 then begin
lbServers. Items. BeginUpdate;
TrackingChanges: = true ;
end ;
2023-12-02 19:57:04 +08:00
2023-12-18 23:35:22 +08:00
TopIndexSaved: = lbServers. TopIndex;
NewServs: = TStringList. Create;
ServersTopIndex: = lbServers. TopIndex;
TopIndexes[ 1 ] : = lbServers. TopIndex;
TopIndexes[ 2 ] : = lbPlayers. TopIndex;
TopIndexes[ 3 ] : = lbRules. TopIndex;
Idx: = - 1 ;
ActualIdx: = lbServers. ItemIndex;
if ActualIdx < > - 1 then begin
Idx: = StrToInt( lbServers. Items. Strings[ ActualIdx] ) ;
if Idx < Length( Servers) then
OldServ: = Servers[ Idx] . Address + ':' + IntToStr( Servers[ Idx] . Port) ;
end ;
Sorted: = false ;
if ( OldSortMode < > SortMode) or ( OldSortDir < > SortDir) then begin
OldSortMode: = SortMode;
OldSortDir: = SortDir;
Sorted: = true ;
case SortMode of
smHostName: SortArray( Servers[ 0 ] , 0 , SizeOf( TServerInfo) , 0 , Length( Servers) - 1 , CompareHostName) ;
smPlayers : SortArray( Servers[ 0 ] , 0 , SizeOf( TServerInfo) , 0 , Length( Servers) - 1 , ComparePlayers) ;
smPing : SortArray( Servers[ 0 ] , 0 , SizeOf( TServerInfo) , 0 , Length( Servers) - 1 , ComparePing) ;
smMode : SortArray( Servers[ 0 ] , 0 , SizeOf( TServerInfo) , 0 , Length( Servers) - 1 , CompareMode) ;
smMap : SortArray( Servers[ 0 ] , 0 , SizeOf( TServerInfo) , 0 , Length( Servers) - 1 , CompareMap) ;
end ;
end ;
if Filtered then begin
FilterList: = TStringList. Create;
for i: = 0 to Length( Servers) - 1 do begin
ItemFiltered: = false ;
// Check the mode filter...
if edFilterMode. Text < > '' then
if Pos( Lowercase( edFilterMode. Text ) , Lowercase( Servers[ i] . Mode) ) = 0 then
ItemFiltered: = true ;
// Check the mode filter...
if edFilterMap. Text < > '' then
if Pos( Lowercase( edFilterMap. Text ) , Lowercase( Servers[ i] . Map) ) = 0 then
ItemFiltered: = true ;
// Check the "Not Full" filter...
if cbFilterFull. Checked then
if Servers[ i] . Players = Servers[ i] . MaxPlayers then
ItemFiltered: = true ;
// Check the "Not Empty" filter...
if cbFilterEmpty. Checked then
if Servers[ i] . Players = 0 then
ItemFiltered: = true ;
// Check the "Not Passworded" filter...
if cbFilterPassworded. Checked then
if Servers[ i] . Passworded then
ItemFiltered: = true ;
// Server hasn't responded yet.
if ( Servers[ i] . MaxPlayers < 1 ) and ( MasterFile < > 0 ) then
ItemFiltered: = true ;
// If this server hasn't been filtered...
if not ItemFiltered then
FilterList. Add( IntToStr( i) ) ;
end ;
if SortDir = sdDown then begin
for i: = FilterList. Count - 1 downto 0 do
NewServs. Add( FilterList. Strings[ i] ) ;
end else
NewServs. Text : = FilterList. Text ;
FilterList. Free;
end else begin
if SortDir = sdDown then begin
for i: = Length( Servers) - 1 downto 0 do
if ( Servers[ i] . MaxPlayers > 0 ) or ( MasterFile = 0 ) then
NewServs. Add( IntToStr( i) ) ;
end else begin
for i: = 0 to Length( Servers) - 1 do
if ( Servers[ i] . MaxPlayers > 0 ) or ( MasterFile = 0 ) then
NewServs. Add( IntToStr( i) ) ;
end ;
end ;
if lbServers. Items. Text < > NewServs. Text then begin
lbServers. Items. Text : = NewServs. Text ;
lbServers. TopIndex: = TopIndexes[ 1 ] ;
end ;
if ( ActualIdx < > - 1 ) and ( Idx < > - 1 ) and ( Idx < Length( Servers) ) then begin
NewServs. Clear;
for i: = 0 to Length( Servers[ Idx] . aPlayers) - 1 do
NewServs. Add( IntToStr( i) ) ;
if lbPlayers. Items. Text < > NewServs. Text then begin
lbPlayers. Items. Text : = NewServs. Text ;
lbPlayers. TopIndex: = TopIndexes[ 2 ] ;
end ;
NewServs. Clear;
label_url. Caption: = '' ;
for i: = 0 to Length( Servers[ Idx] . aRules) - 1 do begin
NewServs. Add( IntToStr( i) ) ;
if Servers[ Idx] . aRules[ i] . Rule = 'weburl' then
label_url. Caption: = Trim( Servers[ Idx] . aRules[ i] . Value) ;
end ;
if lbRules. Items. Text < > NewServs. Text then begin
lbRules. Items. Text : = NewServs. Text ;
lbRules. TopIndex: = TopIndexes[ 3 ] ;
end ;
end ;
NewServs. Free;
if Sorted then begin
for i: = 0 to lbServers. Count - 1 do begin
Idx: = StrToInt( lbServers. Items. Strings[ i] ) ;
if Servers[ Idx] . Address + ':' + IntToStr( Servers[ Idx] . Port) = OldServ then begin
lbServers. ItemIndex: = i;
//lbServersClick(Self);
break;
end ;
end ;
end else
if ActualIdx < > - 1 then
if ActualIdx < lbServers. Items. Count then
lbServers. ItemIndex: = ActualIdx;
if Filtered then begin
if lbServers. ItemIndex < > - 1 then begin
Idx: = StrToInt( lbServers. Items. Strings[ lbServers. ItemIndex] ) ;
if Idx < Length( Servers) then begin
edSIAddress. Text : = Servers[ Idx] . Address + ':' + IntToStr( Servers[ Idx] . Port) ;
lbSIPlayers. Caption: = IntToStr( Servers[ Idx] . Players) + ' / ' + IntToStr( Servers[ Idx] . MaxPlayers) ;
lbSIPing. Caption: = IntToStr( Servers[ Idx] . Ping) ;
lbSIMode. Caption: = Servers[ Idx] . Mode;
lbSIMap. Caption: = Servers[ Idx] . Map;
gbInfo. Caption: = ' Server Info: ' + Servers[ Idx] . HostName + ' ' ;
end ;
end ;
end ;
TotServers: = lbServers. Items. Count;
TotSlots: = 0 ;
TotPlayers: = 0 ;
for i: = 0 to Length( Servers) - 1 do begin
Inc( TotSlots, Servers[ i] . MaxPlayers) ;
Inc( TotPlayers, Servers[ i] . Players) ;
end ;
sbMain. SimpleText: = 'Servers: ' + IntToStr( TotPlayers) + ' players, playing on ' + IntToStr( TotServers) + ' servers. (' + IntToStr( TotSlots) + ' player slots available)' ;
if lbServers. ItemIndex = - 1 then
lbServers. ItemIndex: = 0 ;
if lbServers. Items. Count > = TopIndexSaved then
lbServers. TopIndex: = TopIndexSaved;
if TrackingChanges = true then
lbServers. Items. EndUpdate;
Application. ProcessMessages;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. lbServersContextPopup( Sender: TObject; MousePos: TPoint;
2023-12-02 19:57:04 +08:00
var Handled: Boolean ) ;
begin
2023-12-18 23:35:22 +08:00
Handled: = lbServers. ItemIndex = - 1 ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. ImportFavoritesClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
OD: TOpenDialog;
fmImportFavorites: TfmImportFavorites;
AddToFavs: Boolean ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
tsServerLists. TabIndex: = 0 ;
OD: = TOpenDialog. Create( Self) ;
OD. DefaultExt: = 'fav' ;
OD. Filter: = 'SA-MP Favorites List (*.fav)|*.fav' ;
OD. Options: = [ ofEnableSizing, ofFileMustExist] ;
OD. Title: = 'Import Favorites' ;
if not OD. Execute then begin
OD. Free;
Exit;
end ;
2023-12-02 19:57:04 +08:00
2023-12-18 23:35:22 +08:00
fmImportFavorites: = TfmImportFavorites. Create( Application) ;
fmImportFavorites. ShowModal;
AddToFavs: = fmImportFavorites. rbAddToCurrent. Checked;
fmImportFavorites. Free;
ImportFavorites( OD. FileName, AddToFavs) ;
OD. Free;
ExportFavorites( sub_4E1DA8 + 'USERDATA.DAT' , true ) ;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. ImportFavorites( FileName: String ; AddToFavs: Boolean ) ;
var
ImportFile: File ;
Temp, Temp2, i, j, x: Integer ;
Dubble: Boolean ;
ThisTag: Array [ 0 .. 3 ] of Char ;
begin
AssignFile( ImportFile, FileName) ;
FileMode: = 0 ;
Reset( ImportFile, 1 ) ;
BlockRead( ImportFile, ThisTag[ 0 ] , 4 ) ;
if ThisTag < > FileTag then begin
MessageDlg( 'Invalid SA-MP file.' , mtError, [ mbOk] , 0 ) ;
CloseFile( ImportFile) ;
Exit;
end ;
BlockRead( ImportFile, Temp, 4 ) ;
if Temp < > FavoritesFileVersion then begin
MessageDlg( 'Bad SA-MP favorites file version.' #13 #10 #13 #10 'Your client may need updating.' , mtError, [ mbOk] , 0 ) ;
CloseFile( ImportFile) ;
Exit;
end ;
2023-12-02 19:57:04 +08:00
2023-12-18 23:35:22 +08:00
// Number of servers in file
BlockRead( ImportFile, Temp2, 4 ) ;
if not AddToFavs then
SetLength( Servers, 0 ) ;
for j: = 1 to Temp2 do begin
Dubble: = false ;
i: = Length( Servers) ;
SetLength( Servers, i+ 1 ) ;
// Address
BlockRead( ImportFile, Temp, 4 ) ;
SetLength( Servers[ i] . Address, Temp) ;
if Temp < > 0 then
BlockRead( ImportFile, Servers[ i] . Address[ 1 ] , Temp) ;
// Port
BlockRead( ImportFile, Servers[ i] . Port, 4 ) ;
for x: = 0 to Length( Servers) - 2 do begin
if ( Servers[ x] . Address = Servers[ i] . Address) and ( Servers[ x] . Port = Servers[ i] . Port) then begin
Dubble: = true ;
Break;
end ;
end ;
// Hostname
BlockRead( ImportFile, Temp, 4 ) ;
SetLength( Servers[ i] . HostName, Temp) ;
BlockRead( ImportFile, Servers[ i] . HostName[ 1 ] , Temp) ;
// Server password
BlockRead( ImportFile, Temp, 4 ) ;
SetLength( Servers[ i] . ServerPassword, Temp) ;
if Temp < > 0 then
BlockRead( ImportFile, Servers[ i] . ServerPassword[ 1 ] , Temp) ;
// Rcon password
BlockRead( ImportFile, Temp, 4 ) ;
SetLength( Servers[ i] . RconPassword, Temp) ;
if Temp < > 0 then
BlockRead( ImportFile, Servers[ i] . RconPassword[ 1 ] , Temp) ;
Servers[ i] . Ping: = 9 9 9 9 ;
Servers[ i] . Tag: = Random( $FFFF ) ;
if Dubble then
SetLength( Servers, i)
else
QueryQueue. Add( Servers[ i] . Address + ':' + IntToStr( Servers[ i] . Port) + '#' + IntToStr( Servers[ i] . Tag) ) ;
//QueryServerInfo(Servers[i].Address + ':' + IntToStr(Servers[i].Port), true, true, false, false);
end ;
CloseFile( ImportFile) ;
2023-12-02 19:57:04 +08:00
2023-12-18 23:35:22 +08:00
UpdateServers;
end ;
2023-12-02 19:57:04 +08:00
procedure TfmMain. ExportFavoritesClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
SD: TSaveDialog;
fmExportFavorites: TfmExportFavorites;
ExportPasswords: Boolean ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
tsServerLists. TabIndex: = 0 ;
SD: = TSaveDialog. Create( Self) ;
SD. DefaultExt: = 'fav' ;
SD. Filter: = 'SA-MP Favorites List (*.fav)|*.fav' ;
SD. Options: = [ ofHideReadOnly, ofEnableSizing] ;
SD. Title: = 'Export Favorites' ;
if not SD. Execute then begin
SD. Free;
Exit;
end else begin
if FileExists( SD. FileName) then begin
if MessageDlg( 'File ' '' + SD. FileName+ '' ' already exists. Overwrite?' , mtConfirmation, [ mbYes, mbNo] , 0 ) = mrNo then begin
SD. Free;
Exit;
end ;
end ;
end ;
fmExportFavorites: = TfmExportFavorites. Create( Application) ;
fmExportFavorites. ShowModal;
ExportPasswords: = fmExportFavorites. cbIncludeSavedPasswords. Checked;
fmExportFavorites. Free;
ExportFavorites( SD. FileName, ExportPasswords) ;
SD. Free;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. ExportFavorites( FileName: String ; ExportPasswords: Boolean ) ;
var
ExportFile: File ;
Temp, i: Integer ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
AssignFile( ExportFile, FileName) ;
FileMode: = 1 ;
Rewrite( ExportFile, 1 ) ;
BlockWrite( ExportFile, FileTag[ 0 ] , 4 ) ;
Temp: = FavoritesFileVersion;
BlockWrite( ExportFile, Temp, 4 ) ;
Temp: = Length( Servers) ;
BlockWrite( ExportFile, Temp, 4 ) ;
for i: = 0 to Length( Servers) - 1 do begin
Temp: = Length( Servers[ i] . Address) ;
BlockWrite( ExportFile, Temp, 4 ) ;
if Temp < > 0 then
BlockWrite( ExportFile, Servers[ i] . Address[ 1 ] , Temp) ;
BlockWrite( ExportFile, Servers[ i] . Port, 4 ) ;
Temp: = Length( Servers[ i] . HostName) ;
BlockWrite( ExportFile, Temp, 4 ) ;
BlockWrite( ExportFile, Servers[ i] . HostName[ 1 ] , Temp) ;
if ExportPasswords then begin
Temp: = Length( Servers[ i] . ServerPassword) ;
BlockWrite( ExportFile, Temp, 4 ) ;
if Temp < > 0 then
BlockWrite( ExportFile, Servers[ i] . ServerPassword[ 1 ] , Temp) ;
Temp: = Length( Servers[ i] . RconPassword) ;
BlockWrite( ExportFile, Temp, 4 ) ;
if Temp < > 0 then
BlockWrite( ExportFile, Servers[ i] . RconPassword[ 1 ] , Temp) ;
end else begin
Temp: = 0 ;
BlockWrite( ExportFile, Temp, 4 ) ;
BlockWrite( ExportFile, Temp, 4 ) ;
end ;
end ;
CloseFile( ExportFile) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. ExitClick( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
Close;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. miViewClick( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
miFilterServerInfo. Checked: = Filtered;
miStatusBar. Checked: = sbMain. Visible;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. ToggleFilterServerInfo( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
if Filtered then begin
Filtered: = false ;
pnBreakable. Height: = 1 6 ;
gbInfo. Caption: = ' Server Info ' ;
end else begin
Filtered: = true ;
pnBreakable. Height: = 1 0 0 ;
pnBreakable. Top: = 0 ;
if lbServers. ItemIndex < > - 1 then
gbInfo. Caption: = ' Server Info: ' + Servers[ StrToInt( lbServers. Items. Strings[ lbServers. ItemIndex] ) ] . HostName + ' ' ;
end ;
UpdateServers;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. ToggleStatusBar( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
sbMain. Visible: = not sbMain. Visible;
sbMain. Top: = 1 0 0 0 0 ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. ConnectClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
Idx: Integer ;
SrvPwd: String ;
NickName: String ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if lbServers. ItemIndex = - 1 then Exit;
Idx: = StrToInt( lbServers. Items. Strings[ lbServers. ItemIndex] ) ;
if Idx > = Length( Servers) then Exit;
SrvPwd: = Servers[ Idx] . ServerPassword;
if Servers[ Idx] . Passworded then
if not InputQuery( 'Server Password' , 'This server requires a password...' , SrvPwd) then
Exit;
if edName. Text = '' then begin
if not InputQuery( 'Who are you?' , 'Enter your nickname/handle...' , NickName) then
Exit;
if NickName = '' then
Exit;
edName. Text : = NickName;
end ;
ServerConnect( Servers[ Idx] . Address, IntToStr( Servers[ Idx] . Port) , SrvPwd) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. AddServerClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
Server: String ;
Dummy: Boolean ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
Server: = GetClipBoardStr;
if ( MasterFile < > 0 ) and ( lbServers. ItemIndex < > - 1 ) then begin
Server: = Servers[ StrToIntDef( lbServers. Items. Strings[ lbServers. ItemIndex] , 0 ) ] . Address + ':' +
IntToStr( Servers[ StrToIntDef( lbServers. Items. Strings[ lbServers. ItemIndex] , 0 ) ] . Port) ;
tsServerLists. TabIndex: = 0 ;
tsServerListsChange( tsServerLists, 0 , Dummy) ;
end ;
if InputQuery( 'Add Server' , 'Enter new server HOST:PORT...' , Server) then
if Server < > '' then begin
AddServer( Server) ;
end ;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. AddServer( Server: String ) ;
var
i, j: Integer ;
Dupe: Boolean ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
Server: = Trim( Server) ;
i: = Length( Servers) ;
SetLength( Servers, i + 1 ) ;
if Pos( ':' , Server) < > 0 then begin
Servers[ i] . Address: = Copy( Server, 1 , Pos( ':' , Server) - 1 ) ;
Servers[ i] . Port: = StrToIntDef( Copy( Server, Pos( ':' , Server) + 1 , 5 ) , 7 7 7 7 ) ;
end else begin
Servers[ i] . Address: = Server;
Servers[ i] . Port: = 7 7 7 7 ;
end ;
Servers[ i] . HostName: = '(Retrieving info...) ' + Servers[ i] . Address + ':' + IntToStr( Servers[ i] . Port) ;
Dupe: = False ;
for j: = 0 to i- 1 do
if ( Servers[ j] . Address = Servers[ i] . Address) and ( Servers[ j] . Port = Servers[ i] . Port) then begin
SetLength( Servers, i) ;
MessageDlg( 'This server is already on your list.' , mtError, [ mbOk] , 0 ) ;
Dupe: = True ;
end ;
if not Dupe then begin
//QueryServerInfo(Server, true, true, false, false);
QueryQueue. Add( Server) ;
ExportFavorites( sub_4E1DA8 + 'USERDATA.DAT' , true ) ;
FavoritesChanged: = true ;
end ;
UpdateServers;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. DeleteServerClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
Idx, i: Integer ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if lbServers. ItemIndex = - 1 then Exit;
if tsServerLists. TabIndex < > 0 then Exit;
Idx: = StrToInt( lbServers. Items. Strings[ lbServers. ItemIndex] ) ;
lbServers. Items. Delete( lbServers. ItemIndex) ;
for i: = Idx to Length( Servers) - 2 do
Servers[ i] : = Servers[ i+ 1 ] ;
SetLength( Servers, Length( Servers) - 1 ) ;
UpdateServers;
ExportFavorites( sub_4E1DA8 + 'USERDATA.DAT' , true ) ;
FavoritesChanged: = true ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. RefreshServerClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
Idx: Integer ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if lbServers. ItemIndex = - 1 then Exit;
Idx: = StrToInt( lbServers. Items. Strings[ lbServers. ItemIndex] ) ;
if Idx > = Length( Servers) then Exit;
QueryServerInfo( Servers[ Idx] . Address + ':' + IntToStr( Servers[ Idx] . Port) + '#' + IntToStr( Servers[ Idx] . Tag) , true , true , true , true ) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. MasterServerUpdateClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
SL: TStringList;
i: Integer ;
IdHTTP: TIdHTTP;
fmMasterUpdate: TfmMasterUpdate;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
fmMasterUpdate: = TfmMasterUpdate. Create( Application) ;
fmMasterUpdate. Show;
Enabled: = false ;
Application. ProcessMessages;
IdHTTP: = TIdHTTP. Create( Application) ;
with IdHTTP do begin
ReadTimeout: = 2 0 0 0 0 ; // 20secs
AllowCookies: = true ;
ProxyParams. BasicAuthentication: = False ;
ProxyParams. ProxyPort: = 0 ;
Port: = 8 0 ;
Host: = 'lists.sa-mp.com' ;
Request. Host: = IdHTTP. Host;
Request. ContentLength: = - 1 ;
Request. ContentRangeEnd: = 0 ;
Request. ContentRangeStart: = 0 ;
Request. ContentType: = 'text/html' ;
Request. Accept: = 'text/html, */*' ;
Request. BasicAuthentication: = False ;
Request. UserAgent: = 'Mozilla/3.0 (compatible; SA:MP v0.3.7)' ;
HTTPOptions: = [ hoForceEncodeParams] ;
end ;
SL: = TStringList. Create;
try
if MasterFile = 1 then
SL. Text : = IdHTTP. Get( '/0.3.7/internet' )
else if MasterFile = 2 then
SL. Text : = IdHTTP. Get( '/0.3.7/hosted' ) ;
except
// STATUS: BAD RESPONCE FROM MASTER SERVER
end ;
IdHTTP. Free;
lbServers. Clear;
lbPlayers. Clear;
lbRules. Clear;
SetLength( Servers, 0 ) ;
tmrQueryQueueProcess. Enabled : = false ;
tmrServerListUpdate. Enabled : = false ;
SetLength( Servers, SL. Count) ;
Enabled: = true ;
fmMasterUpdate. Close;
fmMasterUpdate. Free;
for i: = 0 to SL. Count - 1 do begin
//Application.ProcessMessages;
Servers[ i] . HostName: = '(Retrieving info...) ' + SL. Strings[ i] ;
Servers[ i] . Address: = Copy( SL. Strings[ i] , 1 , Pos( ':' , SL. Strings[ i] ) - 1 ) ;
Servers[ i] . Port: = StrToIntDef( Copy( SL. Strings[ i] , Pos( ':' , SL. Strings[ i] ) + 1 , 5 ) , 7 7 7 7 ) ;
Servers[ i] . Ping: = 9 9 9 9 ;
Servers[ i] . Tag: = Random( $FFFF ) ;
//QueryServerInfo(SL.Strings[i], true, true, false, false);
//Sleep(10);
QueryQueue. Add( SL. Strings[ i] + '#' + IntToStr( Servers[ i] . Tag) ) ;
end ;
tmrQueryQueueProcess. Enabled : = true ;
tmrServerListUpdate. Enabled : = true ;
SL. Free;
dword_4EF08C. Clear;
//UpdateServers;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. CopyServerInfoClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
Idx: Integer ;
Str: String ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if lbServers. ItemIndex = - 1 then Exit;
Idx: = StrToInt( lbServers. Items. Strings[ lbServers. ItemIndex] ) ;
if Idx > = Length( Servers) then Exit;
Str: = 'HostName: ' + Servers[ Idx] . HostName + #13 #10 +
'Address: ' + Servers[ Idx] . Address + ':' + IntToStr( Servers[ Idx] . Port) + #13 #10 +
'Players: ' + IntToStr( Servers[ Idx] . Players) + ' / ' + IntToStr( Servers[ Idx] . MaxPlayers) + #13 #10 +
'Ping: ' + IntToStr( Servers[ Idx] . Ping) + #13 #10 +
'Mode: ' + Servers[ Idx] . Mode + #13 #10 +
'Language: ' + Servers[ Idx] . Map;
SetClipBoardStr( Str) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. ServerPropertiesClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
fmServerProperties: TfmServerProperties;
Idx: Integer ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if lbServers. ItemIndex = - 1 then Exit;
Idx: = StrToInt( lbServers. Items. Strings[ lbServers. ItemIndex] ) ;
if Idx > = Length( Servers) then Exit;
fmServerProperties: = TfmServerProperties. Create( Application) ;
with fmServerProperties do begin
lbHostName. Caption: = Servers[ Idx] . HostName;
edAddress. Text : = Servers[ Idx] . Address + ':' + IntToStr( Servers[ Idx] . Port) ;
lbPlayers. Caption: = IntToStr( Servers[ Idx] . Players) + ' / ' + IntToStr( Servers[ Idx] . MaxPlayers) ;
lbPing. Caption: = IntToStr( Servers[ Idx] . Ping) ;
lbMode. Caption: = Servers[ Idx] . Mode;
lbMap. Caption: = Servers[ Idx] . Map;
edServerPassword. Text : = Servers[ Idx] . ServerPassword;
edRconPassword. Text : = Servers[ Idx] . RconPassword;
edServerPassword. Enabled: = Servers[ Idx] . Passworded;
if not Servers[ Idx] . Passworded then
edServerPassword. Color: = clBtnFace;
ShowModal;
Free;
end ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. RemoteConsoleClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
fmRconConfig: TfmRconConfig;
Idx: Integer ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
fmRconConfig: = TfmRconConfig. Create( Application) ;
if lbServers. ItemIndex < > - 1 then begin
Idx: = StrToInt( lbServers. Items. Strings[ lbServers. ItemIndex] ) ;
fmRconConfig. edHost. Text : = Servers[ Idx] . Address + ':' + IntToStr( Servers[ Idx] . Port) ;
fmRconConfig. edPassword. Text : = Servers[ Idx] . RconPassword;
end ;
fmRconConfig. ShowModal;
fmRconConfig. Free;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. SettingsClick( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
fmSettings: TfmSettings;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
fmSettings: = TfmSettings. Create( Application) ;
fmSettings. ShowModal;
fmSettings. Free;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. HelpTopicsClick( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
ShellExecute( Handle, 'open' , 'http://wiki.sa-mp.com/' , nil , nil , SW_SHOWNORMAL) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. AboutClick( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
fmAbout. ShowModal;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. tsServerListsChange( Sender: TObject; NewTab: Integer ;
var AllowChange: Boolean ) ;
begin
2023-12-18 23:35:22 +08:00
if ( tsServerLists. TabIndex = 0 ) and ( FavoritesChanged = True ) then begin
ExportFavorites( sub_4E1DA8 + 'USERDATA.DAT' , true ) ;
FavoritesChanged: = False ;
end ;
QueryQueue. Clear;
lbServers. Clear;
lbPlayers. Clear;
lbRules. Clear;
SetLength( Servers, 0 ) ;
if NewTab = 0 then begin
if FileExists( sub_4E1DA8 + 'USERDATA.DAT' ) then
ImportFavorites( sub_4E1DA8 + 'USERDATA.DAT' , false ) ;
end ;
{
if NewTab < > 0 then begin
lbServers. Clear;
SetLength( Servers, 0 ) ;
end ;
}
UpdateServers;
tbMasterServerUpdate. Enabled: = NewTab < > 0 ;
miMasterServerUpdate. Enabled: = NewTab < > 0 ;
//tbAddServer.Enabled:= NewTab = 0;
miAddServer. Enabled: = NewTab = 0 ;
tbDeleteServer. Enabled: = NewTab = 0 ;
miDeleteServer. Enabled: = NewTab = 0 ;
piDeleteServer. Visible: = NewTab = 0 ;
if lbServers. Count > 0 then
lbServers. ItemIndex: = 0 ;
MasterFile: = NewTab;
lbServersClick( Self) ;
if NewTab < > 0 then
MasterServerUpdateClick( Self) ;
dword_4EF08C. Clear;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. QueryServerInfoParse( SrcIP: String ; SrcPort: Word ; Buf: PAnsiChar ; DataLen: Integer ) ;
var
StrIP: String ;
Tag: Word ;
i, j, Idx: Integer ;
Magic: array [ 0 .. 3 ] of char ;
ping: Cardinal ;
TempWord: Word ;
TempCard: Cardinal ;
TempByte: Byte ;
BufPos: Integer ;
Value: Double ;
RepaintServerList,
RepaintPlayerList,
RepaintRulesList: Boolean ;
TempInt: Integer ;
Port: Word ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if DataLen < 1 1 then Exit; // 10b is min size: 4b magic, 4b ip, 2b port, 1b id
Move( Buf[ 0 ] , Magic[ 0 ] , 4 ) ;
if Magic < > 'SAMP' then Exit;
StrIP: = IntToStr( Byte( Buf[ 4 ] ) ) + '.' + IntToStr( Byte( Buf[ 5 ] ) ) + '.' +
IntToStr( Byte( Buf[ 6 ] ) ) + '.' + IntToStr( Byte( Buf[ 7 ] ) ) ;
Move( Buf[ 8 ] , Port, 2 ) ;
Tag: = SrcPort;
if SrcIP < > StrIP then Exit;
Idx: = - 1 ;
for i: = 0 to Length( Servers) - 1 do begin
if Servers[ i] . DottedAddress = '' then begin
if not Servers[ i] . HasAddress then begin
Servers[ i] . DottedAddress: = GetIPFromHost( Servers[ i] . Address) ;
Servers[ i] . HasAddress: = true ;
end ;
end ;
if ( Servers[ i] . Address = SrcIP) or ( Servers[ i] . DottedAddress = SrcIP) then begin
if Servers[ i] . Port = SrcPort then begin
Idx: = i;
break;
end ;
end ;
if ( Servers[ i] . Address = SrcIP) and ( Servers[ i] . Port = SrcPort) then begin
Idx: = i;
break;
end ;
end ;
if Idx = - 1 then begin
//fmMain.Caption:= 'Server not found ' + StrIP;
Exit;
end ;
if ( Servers[ i] . Tag < > 0 ) and ( Servers[ i] . Tag < > Port) then begin
//fmMain.Caption:= 'Invalid tag for ' + StrIP;
Exit;
end ;
RepaintServerList: = false ;
RepaintPlayerList: = false ;
RepaintRulesList: = false ;
case Buf[ 1 0 ] of // PacketID
'p' : // Ping
begin
//OutputDebugString(PChar('[P] Packet from ' + Servers[Idx].Address + ':' + IntToStr(Servers[Idx].Port)));
if DataLen = 1 5 then begin
Move( Buf[ 1 1 ] , ping, 4 ) ;
timeBeginPeriod( 5 ) ;
Servers[ Idx] . Ping: = timeGetTime - ping;
Value: = Servers[ Idx] . Ping;
if Value < 1 then Value: = 1 ;
i: = chSIPingChart. Series[ 0 ] . AddY( Value, '' , clBlue) ;
if i > 6 0 then begin
for j: = 1 to 6 1 do begin
chSIPingChart. Series[ 0 ] . YValue[ j- 1 ] : = chSIPingChart. Series[ 0 ] . YValue[ j] ;
end ;
chSIPingChart. Series[ 0 ] . Delete( 6 1 ) ;
end ;
chSIPingChart. LeftAxis. Maximum: = chSIPingChart. Series[ 0 ] . MaxYValue / 2 * 3 ;
timeEndPeriod( 5 ) ;
RepaintServerList: = true ;
end ;
end ;
'i' : // Info
begin
BufPos: = 1 1 ;
//OutputDebugString(PChar('[I] Packet from ' + Servers[Idx].Address + ':' + IntToStr(Servers[Idx].Port)));
Move( Buf[ BufPos] , TempByte, 1 ) ;
Inc( BufPos, 1 ) ;
Servers[ Idx] . Passworded: = TempByte < > 0 ;
Move( Buf[ BufPos] , TempWord, 2 ) ;
if TempWord > 1 0 0 0 then TempWord: = 1 0 0 0 ;
Inc( BufPos, 2 ) ;
Servers[ Idx] . Players: = TempWord;
Move( Buf[ BufPos] , TempWord, 2 ) ;
if TempWord > 1 0 0 0 then TempWord: = 1 0 0 0 ;
Inc( BufPos, 2 ) ;
Servers[ Idx] . MaxPlayers: = TempWord;
if Servers[ Idx] . Players > Servers[ Idx] . MaxPlayers then
Servers[ Idx] . Players: = Servers[ Idx] . MaxPlayers;
Servers[ Idx] . HostName: = '-' ;
Servers[ Idx] . Mode: = '-' ;
Servers[ Idx] . Map: = '-' ;
Move( Buf[ BufPos] , TempCard, 4 ) ;
if ( TempCard > 0 ) and ( TempCard < 6 4 ) then begin
Inc( BufPos, 4 ) ;
SetLength( Servers[ Idx] . HostName, TempCard) ;
Move( Buf[ BufPos] , Servers[ Idx] . HostName[ 1 ] , TempCard) ;
Inc( BufPos, TempCard) ;
Move( Buf[ BufPos] , TempCard, 4 ) ;
if ( TempCard > 0 ) and ( TempCard < 4 0 ) then begin
Inc( BufPos, 4 ) ;
SetLength( Servers[ Idx] . Mode, TempCard) ;
Move( Buf[ BufPos] , Servers[ Idx] . Mode[ 1 ] , TempCard) ;
Inc( BufPos, TempCard) ;
Move( Buf[ BufPos] , TempCard, 4 ) ;
if ( TempCard > 0 ) and ( TempCard < 4 0 ) then begin
Inc( BufPos, 4 ) ;
SetLength( Servers[ Idx] . Map, TempCard) ;
Move( Buf[ BufPos] , Servers[ Idx] . Map[ 1 ] , TempCard) ;
//Inc(BufPos, TempCard);
end ;
end ;
end ;
RepaintServerList: = true ;
QueryServerInfo( Servers[ Idx] . Address+ ':' + IntToStr( Servers[ Idx] . Port) + '#' + IntToStr( Servers[ Idx] . Tag) , true , false , false , false ) ;
end ;
'c' : // Players
begin
BufPos: = 1 1 ;
//OutputDebugString(PChar('[C] Packet from ' + Servers[Idx].Address + ':' + IntToStr(Servers[Idx].Port)));
Move( Buf[ BufPos] , TempWord, 2 ) ;
if TempWord > 1 0 0 then TempWord: = 1 0 0 ;
Inc( BufPos, 2 ) ;
Servers[ Idx] . Players: = TempWord;
SetLength( Servers[ Idx] . aPlayers, TempWord) ;
for i: = 0 to TempWord - 1 do begin
Move( Buf[ BufPos] , TempByte, 1 ) ;
Inc( BufPos, 1 ) ;
if BufPos > DataLen then break;
SetLength( Servers[ Idx] . aPlayers[ i] . Name , TempByte) ;
Move( Buf[ BufPos] , Servers[ Idx] . aPlayers[ i] . Name [ 1 ] , TempByte) ;
Inc( BufPos, TempByte) ;
if BufPos > DataLen then break;
Move( Buf[ BufPos] , TempInt, 4 ) ;
if TempInt > 1 0 0 0 0 0 0 then TempInt: = 1 0 0 0 0 0 0 ;
if TempInt < 0 then TempInt: = 0 ;
Servers[ Idx] . aPlayers[ i] . Score: = TempInt;
Inc( BufPos, 4 ) ;
if BufPos > DataLen then break;
end ;
RepaintPlayerList: = true ;
end ;
'r' : // Rules
begin
BufPos: = 1 1 ;
//OutputDebugString(PChar('[R] Packet from ' + Servers[Idx].Address + ':' + IntToStr(Servers[Idx].Port)));
Move( Buf[ BufPos] , TempWord, 2 ) ;
if TempWord > 3 0 then TempWord: = 3 0 ;
Inc( BufPos, 2 ) ;
SetLength( Servers[ Idx] . aRules, TempWord) ;
for i: = 0 to TempWord - 1 do begin
if BufPos > DataLen then break;
Move( Buf[ BufPos] , TempByte, 1 ) ;
Inc( BufPos, 1 ) ;
if BufPos > DataLen then break;
SetLength( Servers[ Idx] . aRules[ i] . Rule, TempByte) ;
Move( Buf[ BufPos] , Servers[ Idx] . aRules[ i] . Rule[ 1 ] , TempByte) ;
Inc( BufPos, TempByte) ;
if BufPos > DataLen then break;
Move( Buf[ BufPos] , TempByte, 1 ) ;
Inc( BufPos, 1 ) ;
if BufPos > DataLen then break;
SetLength( Servers[ Idx] . aRules[ i] . Value, TempByte) ;
Move( Buf[ BufPos] , Servers[ Idx] . aRules[ i] . Value[ 1 ] , TempByte) ;
Inc( BufPos, TempByte) ;
end ;
RepaintRulesList: = true ;
end ;
end ;
if QueryQueue. Count < = 0 then
UpdateServers;
if RepaintServerList then
lbServers. Invalidate;
if RepaintPlayerList then
lbPlayers. Invalidate;
if RepaintRulesList then
lbRules. Invalidate;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. QueryServerInfoError( SocketError: Integer ) ;
var
err: array [ 0 .. 5 1 2 ] of Char ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, nil , SocketError, 0 , @ err, 5 1 2 , nil ) ;
MessageDlg( err, mtError, [ mbOk] , 0 ) ;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. QueryServerInfo( Server: String ; bPing: Boolean ; bInfo: Boolean ; bPlayers: Boolean ; bRules: Boolean ) ;
var
Buf: PByteArray ;
Ticks: Cardinal ;
ToAddr: TSockAddr;
ToLen: Integer ;
Host: String ;
Port: Word ;
Tag: Word ;
ColPos, TagPos: Integer ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
Tag: = 0 ;
if Pos( ':' , Server) < > 0 then begin
if Pos( '#' , Server) < > 0 then begin
ColPos: = Pos( ':' , Server) ;
TagPos: = Pos( '#' , Server) ;
Host: = Copy( Server, 1 , ColPos- 1 ) ;
Port: = StrToIntDef( Copy( Server, ColPos+ 1 , TagPos- ( ColPos+ 1 ) ) , 7 7 7 7 ) ;
Tag: = StrToIntDef( Copy( Server, TagPos+ 1 , Length( Server) - TagPos) , 0 ) ;
end else begin
ColPos: = Pos( ':' , Server) ;
Host: = Copy( Server, 1 , ColPos- 1 ) ;
Port: = StrToIntDef( Copy( Server, ColPos+ 1 , Length( Server) - ColPos+ 1 ) , 7 7 7 7 ) ;
end ;
end else begin
Host: = Server;
Port: = 7 7 7 7 ;
end ;
if Tag = 0 then
Tag: = Port;
Host: = GetIPFromHost( Host) ;
if ( Length( Host) < 7 ) or ( Length( Host) > 1 5 ) then
Exit;
GetMem( Buf, 1 5 ) ;
Buf[ 0 ] : = Byte( 'S' ) ; // Magic
Buf[ 1 ] : = Byte( 'A' ) ;
Buf[ 2 ] : = Byte( 'M' ) ;
Buf[ 3 ] : = Byte( 'P' ) ;
Buf[ 4 ] : = StrToIntDef( GetToken( Host, 1 , '.' ) , 0 ) ; // IP
Buf[ 5 ] : = StrToIntDef( GetToken( Host, 2 , '.' ) , 0 ) ;
Buf[ 6 ] : = StrToIntDef( GetToken( Host, 3 , '.' ) , 0 ) ;
Buf[ 7 ] : = StrToIntDef( GetToken( Host, 4 , '.' ) , 0 ) ;
//Move(Port, Buf[8], 2); // Port
ZeroMemory( @ ToAddr, SizeOf( ToAddr) ) ;
ToAddr. sin_family: = AF_INET;
ToAddr. sin_port: = htons( Port) ;
ToAddr. sin_addr. S_addr: = inet_addr( PChar( Host) ) ;
ToLen: = SizeOf( ToAddr) ;
Move( Tag, Buf[ 8 ] , 2 ) ; // Tag
if bInfo = true then begin
Buf[ 1 0 ] : = Byte( 'i' ) ; // Info Packet Id
sendto( QuerySocket, Buf[ 0 ] , 1 1 , 0 , ToAddr, ToLen) ;
Sleep( 1 ) ;
end ;
if bPing = true then begin
Buf[ 1 0 ] : = Byte( 'p' ) ; // Ping Packet Id
timeBeginPeriod( 1 ) ;
Ticks: = timeGetTime;
timeEndPeriod( 1 ) ;
Move( Ticks, Buf[ 1 1 ] , 4 ) ;
sendto( QuerySocket, Buf[ 0 ] , 1 5 , 0 , ToAddr, ToLen) ;
Sleep( 1 ) ;
end ;
if bPlayers = true then begin
Buf[ 1 0 ] : = Byte( 'c' ) ; // Players Packet Id
sendto( QuerySocket, Buf[ 0 ] , 1 1 , 0 , ToAddr, ToLen) ;
Sleep( 1 ) ;
end ;
if bRules = true then begin
Buf[ 1 0 ] : = Byte( 'r' ) ; // Rules Packet Id
sendto( QuerySocket, Buf[ 0 ] , 1 1 , 0 , ToAddr, ToLen) ;
Sleep( 1 ) ;
end ;
FreeMem( Buf, 1 5 ) ;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. ServerConnect( Server: String ; Port: String ; Password: String ) ;
procedure GetDebugPrivs;
var
hToken: THandle;
xTokenPriv: TTokenPrivileges;
iRetLen: DWord;
begin
If OpenProcessToken( GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) Then Begin
LookupPrivilegeValue( nil , 'SeDebugPrivilege' , xTokenPriv. Privileges[ 0 ] . Luid) ;
xTokenPriv. PrivilegeCount: = 1 ;
xTokenPriv. Privileges[ 0 ] . Attributes: = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges( hToken, False , xTokenPriv, 0 , nil , iRetLen) ;
End ;
end ;
const
ACL_REVISION = 2 ;
var
StartInfo: TStartupInfo;
ProcInfo: TProcessInformation;
Created: Boolean ;
hThread: THandle;
pLibRemote: Pointer ;
NumBytes, ThreadID: Cardinal ;
CmdLine, SAMP_DLL: String ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if not FileExists( gta_sa_exe) then begin
MessageDlg( 'GTA: San Andreas executable not found.' #13 #10 '(' + gta_sa_exe+ ')' #13 #10 #13 #10 'Please locate it now.' , mtError, [ mbOk] , 0 ) ;
GetGTAExe( Handle) ;
end ;
if not FileExists( gta_sa_exe) then begin
MessageDlg( 'GTA: San Andreas executable STILL not found.' #13 #10 '(' + gta_sa_exe+ ')' #13 #10 #13 #10 'Aborting launch.' , mtError, [ mbOk] , 0 ) ;
Exit;
end ;
FillChar( StartInfo, SizeOf( TStartupInfo) , 0 ) ;
FillChar( ProcInfo, SizeOf( TProcessInformation) , 0 ) ;
StartInfo. cb: = SizeOf( TStartupInfo) ;
CmdLine: = ' -c -n ' + edName. Text + ' -h ' + GetIPFromHost( Server) + ' -p ' + Port;
if Password < > '' then
CmdLine: = CmdLine + ' -z ' + Password;
Created: = CreateProcess( nil , PChar( '"' + gta_sa_exe + '"' + CmdLine) , {@SA} nil , nil , false ,
CREATE_NEW_PROCESS_GROUP+ NORMAL_PRIORITY_CLASS+ CREATE_SUSPENDED,
nil , PChar( ExtractFilePath( gta_sa_exe) ) , StartInfo, ProcInfo) ;
if not Created then begin
MessageDlg( 'Unable to execute.' , mtError, [ mbOk] , 0 ) ;
Exit;
end ;
if RT_GetVersion( nil ) shr 3 1 = 0 then
GetDebugPrivs;
SAMP_DLL: = ExtractFilePath( gta_sa_exe) + 'samp.dll' ;
SetLength( SAMP_DLL, Length( SAMP_DLL) + 1 ) ;
SAMP_DLL[ Length( SAMP_DLL) ] : = #0 ;
pLibRemote: = xVirtualAllocEx( ProcInfo. hProcess, nil , MAX_PATH, MEM_COMMIT, PAGE_READWRITE) ;
WriteProcessMemory( ProcInfo. hProcess, pLibRemote, PChar( SAMP_DLL) , Length( SAMP_DLL) , NumBytes) ;
hThread: = xCreateRemoteThread( ProcInfo. hProcess, nil , 0 , GetProcAddress( GetModuleHandle( 'kernel32' ) , 'LoadLibraryA' ) , pLibRemote, 0 , ThreadID) ;
WaitForSingleObject( hThread, 2 0 0 0 ) ;
CloseHandle( hThread) ;
VirtualFreeEx( ProcInfo. hProcess, pLibRemote, MAX_PATH, MEM_RELEASE) ;
ResumeThread( ProcInfo. hThread) ;
//CloseHandle(ProcInfo.hProcess);
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. piCopyClick( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
SetClipBoardStr( edSIAddress. Text ) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. pmCopyPopup( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
piCopy. Enabled: = edSIAddress. Text < > '- - -' ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. lbPlayersDrawItem( Control: TWinControl; Index : Integer ;
Rect: TRect; State: TOwnerDrawState) ;
2023-12-18 23:35:22 +08:00
var
Idx: Integer ;
TempRect: TRect;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if lbServers. ItemIndex = - 1 then Exit;
with ( Control as TListBox) do begin
Idx: = StrToIntDef( lbServers. Items. Strings[ lbServers. ItemIndex] , 0 ) ;
if Idx > = Length( Servers) then Exit;
if Index > = Length( Servers[ Idx] . aPlayers) then
Exit;
Canvas. Pen. Color: = clBtnHighlight;
Canvas. Pen. Style: = psClear;
if odSelected in State then begin
Canvas. Font. Color: = clHighlightText;
Canvas. Brush. Color: = clHighlight;
end else begin
Canvas. Font. Color: = clWindowText;
if ( Index mod 2 ) = 1 then
Canvas. Brush. Color: = clWindow
else
Canvas. Brush. Color: = sub_4E2628( clWindow) ;
end ;
Inc( Rect. Right) ;
Canvas. Rectangle( Rect) ;
Dec( Rect. Right) ;
Canvas. Pen. Style: = psSolid;
Canvas. PenPos: = Point( Rect. Right, Rect. Bottom- 1 ) ;
Canvas. LineTo( Rect. Left, Rect. Bottom- 1 ) ;
Canvas. PenPos: = Point( hcPlayers. Sections. Items[ 0 ] . Right- 2 , Rect. Top) ;
Canvas. LineTo( hcPlayers. Sections. Items[ 0 ] . Right- 2 , Rect. Bottom) ;
Canvas. PenPos: = Point( hcPlayers. Sections. Items[ 1 ] . Right- 2 , Rect. Top) ;
Canvas. LineTo( hcPlayers. Sections. Items[ 1 ] . Right- 2 , Rect. Bottom) ;
TempRect: = Classes. Rect( hcPlayers. Sections. Items[ 0 ] . Left + 2 , Rect. Top + 2 , hcPlayers. Sections. Items[ 0 ] . Right - 2 , Rect. Bottom - 2 ) ;
DrawText( Canvas. Handle, PChar( Servers[ Idx] . aPlayers[ Index ] . Name ) , - 1 , TempRect, DT_LEFT) ;
TempRect: = Classes. Rect( hcPlayers. Sections. Items[ 1 ] . Left + 2 , Rect. Top + 2 , hcPlayers. Sections. Items[ 1 ] . Right - 2 , Rect. Bottom - 2 ) ;
DrawText( Canvas. Handle, PChar( IntToStr( Servers[ Idx] . aPlayers[ Index ] . Score) ) , - 1 , TempRect, DT_LEFT) ;
end ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. hcPlayersSectionResize( HeaderControl: THeaderControl;
Section: THeaderSection) ;
begin
2023-12-18 23:35:22 +08:00
lbPlayers. Repaint;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. lbRulesDrawItem( Control: TWinControl; Index : Integer ;
Rect: TRect; State: TOwnerDrawState) ;
2023-12-18 23:35:22 +08:00
var
Idx: Integer ;
TempRect: TRect;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if lbServers. ItemIndex = - 1 then Exit;
with ( Control as TListBox) do begin
Idx: = StrToIntDef( lbServers. Items. Strings[ lbServers. ItemIndex] , 0 ) ;
if Idx > = Length( Servers) then Exit;
if Index > = Length( Servers[ Idx] . aRules) then
Exit;
Canvas. Pen. Color: = clBtnHighlight;
Canvas. Pen. Style: = psClear;
if odSelected in State then begin
Canvas. Font. Color: = clHighlightText;
Canvas. Brush. Color: = clHighlight;
end else begin
Canvas. Font. Color: = clWindowText;
if ( Index mod 2 ) = 1 then
Canvas. Brush. Color: = clWindow
else
Canvas. Brush. Color: = sub_4E2628( clWindow) ;
end ;
Inc( Rect. Right) ;
Canvas. Rectangle( Rect) ;
Dec( Rect. Right) ;
Canvas. Pen. Style: = psSolid;
Canvas. PenPos: = Point( Rect. Right, Rect. Bottom- 1 ) ;
Canvas. LineTo( Rect. Left, Rect. Bottom- 1 ) ;
Canvas. PenPos: = Point( hcRules. Sections. Items[ 0 ] . Right- 2 , Rect. Top) ;
Canvas. LineTo( hcRules. Sections. Items[ 0 ] . Right- 2 , Rect. Bottom) ;
Canvas. PenPos: = Point( hcRules. Sections. Items[ 1 ] . Right- 2 , Rect. Top) ;
Canvas. LineTo( hcRules. Sections. Items[ 1 ] . Right- 2 , Rect. Bottom) ;
TempRect: = Classes. Rect( hcRules. Sections. Items[ 0 ] . Left + 2 , Rect. Top + 2 , hcRules. Sections. Items[ 0 ] . Right - 2 , Rect. Bottom - 2 ) ;
DrawText( Canvas. Handle, PChar( Servers[ Idx] . aRules[ Index ] . Rule) , - 1 , TempRect, DT_LEFT) ;
TempRect: = Classes. Rect( hcRules. Sections. Items[ 1 ] . Left + 2 , Rect. Top + 2 , hcRules. Sections. Items[ 1 ] . Right - 2 , Rect. Bottom - 2 ) ;
DrawText( Canvas. Handle, PChar( Servers[ Idx] . aRules[ Index ] . Value) , - 1 , TempRect, DT_LEFT) ;
end ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. hcRulesSectionResize( HeaderControl: THeaderControl;
Section: THeaderSection) ;
begin
2023-12-18 23:35:22 +08:00
lbRules. Repaint;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. sbMainDrawPanel( StatusBar: TStatusBar;
Panel: TStatusPanel; const Rect: TRect) ;
2023-12-18 23:35:22 +08:00
var
Pcnt: Integer ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
StatusBar. Canvas. Brush. Color: = clBtnFace;
StatusBar. Canvas. Rectangle( Rect) ;
StatusBar. Canvas. Brush. Color: = $00804000 ;
Pcnt: = Round( ( ( Rect. Right- Rect. Left) / 100.0 ) * 75.0 ) ;
StatusBar. Canvas. Rectangle( Rect. Left, Rect. Top, Rect. Left+ Pcnt, Rect. Bottom) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. lbPlayersExit( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
lbPlayers. ItemIndex: = - 1 ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. lbRulesExit( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
lbRules. ItemIndex: = - 1 ;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. WMRecv( var Message : TMessage) ;
var
lpBuffer: Array [ 0 .. 2 0 4 8 ] of Char ;
BufLen: Integer ;
FromAddr: TSockAddr;
FromLen: Integer ;
SrcAddr: String ;
SrcPort: Word ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
ZeroMemory( @ lpBuffer, sizeof( lpBuffer) ) ;
ZeroMemory( @ FromAddr, sizeof( FromAddr) ) ;
FromAddr. sin_family: = AF_INET;
FromLen: = SizeOf( FromAddr) ;
BufLen: = recvfrom( QuerySocket, lpBuffer, 2 0 4 8 , 0 , FromAddr, FromLen) ;
SrcAddr: = inet_ntoa( FromAddr. sin_addr) ;
SrcPort: = htons( FromAddr. sin_port) ;
while ( BufLen > 0 ) do begin
//OutputDebugString( PChar('[*] of size ' + IntToStr(BufLen)) );
QueryServerInfoParse( SrcAddr, SrcPort, lpBuffer, BufLen) ;
ZeroMemory( @ lpBuffer, sizeof( lpBuffer) ) ;
BufLen: = recvfrom( QuerySocket, lpBuffer, 2 0 4 8 , 0 , FromAddr, FromLen) ;
SrcAddr: = inet_ntoa( FromAddr. sin_addr) ;
SrcPort: = htons( FromAddr. sin_port) ;
end ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. FormDestroy( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
Reg: TRegistry;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
Reg: = TRegistry. Create;
Reg. RootKey: = HKEY_CURRENT_USER;
Reg. OpenKey( 'SOFTWARE\SAMP' , true ) ;
Reg. WriteString( 'PlayerName' , edName. Text ) ;
Reg. CloseKey;
Reg. Free;
CloseSocket( QuerySocket) ;
ShutDown( QuerySocket, 0 ) ;
WSACleanup;
QueryQueue. Free;
if ( tsServerLists. TabIndex = 0 ) and ( FavoritesChanged = True ) then begin
ExportFavorites( sub_4E1DA8 + 'USERDATA.DAT' , True ) ;
FavoritesChanged: = False ;
end ;
Sleep( 0 ) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. FormShow( Sender: TObject) ;
2023-12-18 23:35:22 +08:00
var
ServFull, ServAddr, ServPort, ServPass: String ;
NewServer: String ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
//SetProcessAffinityMask(GetCurrentProcess(),1);
lbServers. DoubleBuffered: = true ;
lbPlayers. DoubleBuffered: = true ;
lbRules. DoubleBuffered: = true ;
lbServers. SetFocus;
if ParamCount > 0 then begin
ServFull: = ParamStr( 1 ) ;
if Copy( ServFull, 0 , 7 ) = 'samp://' then begin
if ParamCount > 1 then
ServPass: = ParamStr( 2 ) ;
ServFull: = StringReplace( ServFull, 'samp://' , '' , [ rfReplaceAll, rfIgnoreCase] ) ;
ServFull: = StringReplace( ServFull, '/' , '' , [ rfReplaceAll, rfIgnoreCase] ) ;
if Pos( ':' , ServFull) < > 0 then begin
ServAddr: = Copy( ServFull, 0 , Pos( ':' , ServFull) - 1 ) ;
///////////////////////////////////////////////
//
// Delphi 7 compiler bug(?)
//
// With this structure:
// ServPort:= IntToStr(StrToIntDef(Copy(ServFull, Pos(':', ServFull)+1, Length(ServFull)-Pos(':', ServFull)+1), 7777));
// the compiler seems to gets confused and will not generate
// LStrLAsg call after Sysutils::IntToStr to set ServPort variable.
// Workaround is to break down the structure.
//
///////////////////////////////////////////////
ServPort: = Copy( ServFull, Pos( ':' , ServFull) + 1 , Length( ServFull) - Pos( ':' , ServFull) + 1 ) ;
ServPort: = IntToStr( StrToIntDef( ServPort, 7 7 7 7 ) ) ;
end else begin
ServAddr: = Copy( ServFull, 0 , Length( ServFull) ) ;
ServPort: = '7777' ;
end ;
wnd_webrunform. Label1. Caption: = 'Do you want to add ' + ServAddr + ':' + ServPort + ' to your favorites ' + #13 #10 + 'or play on this server now?' ;
Case wnd_webrunform. ShowModal Of
mrOk: begin
ServerConnect( ServAddr, ServPort, ServPass) ;
Application. Terminate;
end ;
mrYes: begin
sub_4E1CEC;
NewServer: = ServAddr + ':' + ServPort;
if InputQuery( 'Add Server' , 'Enter new server HOST:PORT...' , NewServer) < > False then
if NewServer < > '' then
AddServer( NewServer) ;
end ;
mrCancel: ;
end ;
end else begin
ServFull: = ParamStr( 1 ) ;
if ParamCount > 1 then
ServPass: = ParamStr( 2 ) ;
if Pos( ':' , ServFull) < > 0 then begin
ServAddr: = Copy( ServFull, 1 , Pos( ':' , ServFull) - 1 ) ;
ServPort: = IntToStr( StrToIntDef( Copy( ServFull, Pos( ':' , ServFull) + 1 , 5 ) , 7 7 7 7 ) ) ;
end else begin
ServAddr: = ServFull;
ServPort: = '7777' ;
end ;
ServerConnect( ServAddr, ServPort, ServPass) ;
Application. Terminate;
end ;
end ;
sub_4E1CEC;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
function BrowseCallbackProc( hwnd: HWND; uMsg: UINT; lParam, lpData: LPARAM) : Integer ; stdcall ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
case uMsg of
BFFM_INITIALIZED:
Begin
SetWindowText( hWnd, 'GTA: San Andreas Installation' ) ;
SendMessage( hwnd, BFFM_SETSELECTION, 1 , lpData) ;
End ;
end ;
Result : = 0 ;
end ;
function TfmMain. BrowseForFolder( Owner: HWND; var Directory: String ; StartDir, Title: String ) : Boolean ;
var
BrowseInfo: TBrowseInfo;
DisplayName: Array [ 0 .. MAX_PATH] Of Char ;
TempPath : Array [ 0 .. MAX_PATH] Of Char ;
begin
Result : = False ;
FillChar( BrowseInfo, SizeOf( TBrowseInfo) , #0 ) ;
With BrowseInfo Do Begin
hwndOwner: = Owner;
pidlRoot: = nil ;
pszDisplayName: = @ DisplayName;
lpszTitle: = PChar( Title) ;
ulFlags: = BIF_RETURNONLYFSDIRS;
lParam: = Integer( PChar( StartDir) ) ;
lpfn: = BrowseCallbackProc;
End ;
If SHGetPathFromIDList( SHBrowseForFolder( BrowseInfo) , TempPath) Then Begin
Directory: = TempPath;
Result : = True ;
End ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. miSampClick( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
ShellExecute( Handle, 'open' , 'http://www.sa-mp.com/' , nil , nil , SW_SHOWNORMAL) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. tmrQueryQueueProcessTimer( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
//Application.ProcessMessages;
if QueryQueue. Count > 0 then begin
QueryServerInfo( QueryQueue. Strings[ 0 ] , false , true , false , false ) ;
//QueryServerInfo(QueryQueue.Strings[0], true, false, false, false);
//UpdateServers;
QueryQueue. Delete( 0 ) ;
end ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. label_urlClick( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
ShellExecute( 0 , 'open' , PAnsiChar( 'http://' + ( Sender as TLabel) . Caption) , '' , '' , SW_SHOWNORMAL) ;
2023-12-02 19:57:04 +08:00
end ;
2023-12-18 23:35:22 +08:00
procedure TfmMain. CreateFASTDesktoplink1Click( Sender: TObject) ;
var
Idx: Integer ;
2023-12-02 19:57:04 +08:00
begin
2023-12-18 23:35:22 +08:00
if lbServers. ItemIndex = - 1 then Exit;
Idx: = StrToInt( lbServers. Items. Strings[ lbServers. ItemIndex] ) ;
if Idx > = Length( Servers) then Exit;
sub_4E1E6C( Servers[ Idx] . Address + ':' + IntToStr( Servers[ Idx] . Port) , Servers[ Idx] . HostName) ;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. FormResize( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
imLogo. Left: = fmMain. Width - imLogo. Width;
imLogo. Repaint;
2023-12-02 19:57:04 +08:00
end ;
procedure TfmMain. imLogoClick( Sender: TObject) ;
begin
2023-12-18 23:35:22 +08:00
fmAbout. ShowModal;
2023-12-02 19:57:04 +08:00
end ;
2023-11-05 22:32:43 +08:00
end .
2023-12-18 23:35:22 +08:00