diff --git a/exgui/EliRT.obj b/exgui/EliRT.obj new file mode 100644 index 0000000..983ba2d Binary files /dev/null and b/exgui/EliRT.obj differ diff --git a/exgui/Main.dfm b/exgui/Main.dfm index f8ab12c..180610e 100644 Binary files a/exgui/Main.dfm and b/exgui/Main.dfm differ diff --git a/exgui/Main.pas b/exgui/Main.pas index c2b86e9..25887b8 100644 --- a/exgui/Main.pas +++ b/exgui/Main.pas @@ -3,9 +3,19 @@ unit Main; interface uses - Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, - Dialogs, ExtCtrls, XPMan, ImgList, Menus, ComCtrls, StdCtrls, TeEngine, - Series, TeeProcs, Chart, Tabs, ToolWin, GIFImage; + 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; type TfmMain = class(TForm) @@ -116,6 +126,11 @@ type tmrServerListUpdate: TTimer; ToolButton1: TToolButton; + function GetToken(TokenData: String; ItemIndex: Integer; TokenDelimiter: String): String; + function GetClipBoardStr: String; + procedure SetClipBoardStr(Str: String); + + procedure GetGTAExe(Owner: HWND); procedure FormCreate(Sender: TObject); procedure lbServersDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); @@ -127,41 +142,38 @@ type procedure pnBreakableResize(Sender: TObject); procedure hcServersDrawSection(HeaderControl: THeaderControl; Section: THeaderSection; const Rect: TRect; Pressed: Boolean); - procedure tmrServerListUpdateTimer(Sender: TObject); procedure tmSIPingUpdateTimer(Sender: TObject); procedure lbServersClick(Sender: TObject); procedure FilterChange(Sender: TObject); procedure UpdateServers; procedure lbServersContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); - procedure gbInfoContextPopup(Sender: TObject; MousePos: TPoint; - var Handled: Boolean); + procedure AddServer(Server: String); procedure ImportFavoritesClick(Sender: TObject); - procedure ImportFavorites; + procedure ImportFavorites(FileName: String; AddToFavs: Boolean); procedure ExportFavoritesClick(Sender: TObject); - procedure ExportFavorites; + procedure ExportFavorites(FileName: String; ExportPasswords: Boolean); 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 AddServer; procedure DeleteServerClick(Sender: TObject); procedure RefreshServerClick(Sender: TObject); procedure MasterServerUpdateClick(Sender: TObject); procedure CopyServerInfoClick(Sender: TObject); procedure ServerPropertiesClick(Sender: TObject); - procedure RemoteConsoleClick(Sender: TObject); procedure SettingsClick(Sender: TObject); + procedure RemoteConsoleClick(Sender: TObject); procedure HelpTopicsClick(Sender: TObject); procedure AboutClick(Sender: TObject); procedure tsServerListsChange(Sender: TObject; NewTab: Integer; var AllowChange: Boolean); - procedure QueryServerInfoParse; - procedure QueryServerInfoError; - procedure QueryServerInfo; - procedure ServerConnect; + 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); procedure piCopyClick(Sender: TObject); procedure pmCopyPopup(Sender: TObject); procedure lbPlayersDrawItem(Control: TWinControl; Index: Integer; @@ -176,332 +188,2102 @@ type const Rect: TRect); procedure lbPlayersExit(Sender: TObject); procedure lbRulesExit(Sender: TObject); - procedure WMRecv; + procedure WMRecv(var Message: TMessage); message WM_RECV; procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); - procedure BrowseForFolder; + function BrowseForFolder(Owner: HWND; var Directory: String; StartDir, Title: String): Boolean; procedure miSampClick(Sender: TObject); procedure tmrQueryQueueProcessTimer(Sender: TObject); - procedure label_urlClick(Sender: TObject); - procedure CreateFASTDesktoplink1Click; procedure FormResize(Sender: TObject); + procedure tmServerListUpdate(Sender: TObject); + procedure label_urlClick(Sender: TObject); procedure imLogoClick(Sender: TObject); + procedure CreateFASTDesktoplink1Click(Sender: TObject); + private { Private declarations } public { Public declarations } end; + 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; + var fmMain: TfmMain; + 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; implementation +uses + ImportFavorites, ExportFavorites, ServerProperties, + RconConfig, Settings, About, Rcon, MasterUpdate, + unit_webrunform; + {$R *.dfm} -procedure TfmMain.FormCreate(Sender: TObject); +procedure sub_4E1CEC(); begin - // TODO: TfmMain.FormCreate + 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..264] 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..10] 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)) > 16 then begin + if GetGValue(ColorToRGB(a1)) > 16 then begin + if GetBValue(ColorToRGB(a1)) > 16 then begin + Result:= RGB( + GetRValue(ColorToRGB(a1))-16, + GetGValue(ColorToRGB(a1))-16, + GetBValue(ColorToRGB(a1))-16); + 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; + +procedure TfmMain.FormCreate(Sender: TObject); +var + Dummy: Boolean; + WSData: WSADATA; + s_in: sockaddr_in; + Reg: TRegistry; +begin + 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; end; procedure TfmMain.lbServersDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); +var + i, Idx: Integer; + TempRect: TRect; begin - // TODO: TfmMain.lbServersDrawItem + 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, 13, 14, imPadlocked.Canvas.Handle, 0, 0, SRCCOPY) + else + BitBlt(Canvas.Handle, 7, Rect.Top + 1, 13, 14, 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 = 9999 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; end; procedure TfmMain.hcServersSectionResize(HeaderControl: THeaderControl; Section: THeaderSection); begin - // TODO: TfmMain.hcServersSectionResize + lbServers.Repaint; end; procedure TfmMain.tbMainResize(Sender: TObject); begin - // TODO: TfmMain.tbMainResize + ToolButton1.Width:= ((Sender as TToolBar).Width-ToolButton1.Left)-imLogo.Width; + imLogo.Repaint; end; procedure TfmMain.hcServersSectionClick(HeaderControl: THeaderControl; Section: THeaderSection); begin - // TODO: TfmMain.hcServersSectionClick + 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; end; procedure TfmMain.pnBreakableResize(Sender: TObject); begin - // TODO: TfmMain.pnBreakableResize + gbInfo.Width:= pnBreakable.Width - gbFilter.Width + 1; + chSIPingChart.Width:= gbInfo.Width - 272; + if chSIPingChart.Width > 50 then + chSIPingChart.Visible:= true + else + chSIPingChart.Visible:= false; end; +var + ReRender: Boolean; procedure TfmMain.hcServersDrawSection(HeaderControl: THeaderControl; Section: THeaderSection; const Rect: TRect; Pressed: Boolean); +var + DoIt: Boolean; + TempRect: TRect; begin - // TODO: TfmMain.hcServersDrawSection + 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, 12, imDownArrow.Canvas.Handle, 0, 0, SRCCOPY) + else + BitBlt(HeaderControl.Canvas.Handle, Rect.Left + 2, Rect.Top + 2, 9, 12, imUpArrow.Canvas.Handle, 0, 0, SRCCOPY); + Inc(TempRect.Left, 10); + end; + + DrawText(HeaderControl.Canvas.Handle, PChar(Section.Text), -1, TempRect, DT_LEFT); + + if not ReRender then begin + ReRender:= true; + HeaderControl.Repaint; + ReRender:= false; + end; end; -procedure TfmMain.tmrServerListUpdateTimer(Sender: TObject); +procedure TfmMain.tmServerListUpdate(Sender: TObject); begin - // TODO: TfmMain.tmrServerListUpdateTimer + if QueryQueue.Count > 0 then + UpdateServers; + lbPlayers.Invalidate; + lbRules.Invalidate; end; procedure TfmMain.tmSIPingUpdateTimer(Sender: TObject); +var + Idx: Integer; + PingOnly: Boolean; begin - // TODO: TfmMain.tmSIPingUpdateTimer + 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); end; procedure TfmMain.lbServersClick(Sender: TObject); +var + Enabled: Boolean; begin - // TODO: TfmMain.lbServersClick + 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); end; procedure TfmMain.FilterChange(Sender: TObject); begin - // TODO: TfmMain.FilterChange + UpdateServers; end; procedure TfmMain.UpdateServers; +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; begin - // TODO: TfmMain.UpdateServers + if QueryQueue.Count > 0 then begin + lbServers.Items.BeginUpdate; + TrackingChanges:= true; + end; + + 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; end; procedure TfmMain.lbServersContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); begin - // TODO: TfmMain.lbServersContextPopup -end; - -procedure TfmMain.gbInfoContextPopup(Sender: TObject; MousePos: TPoint; - var Handled: Boolean); -begin - // TODO: TfmMain.gbInfoContextPopup + Handled:= lbServers.ItemIndex = -1; end; procedure TfmMain.ImportFavoritesClick(Sender: TObject); +var + OD: TOpenDialog; + fmImportFavorites: TfmImportFavorites; + AddToFavs: Boolean; begin - // TODO: TfmMain.ImportFavoritesClick + 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; + + fmImportFavorites:= TfmImportFavorites.Create(Application); + fmImportFavorites.ShowModal; + AddToFavs:= fmImportFavorites.rbAddToCurrent.Checked; + fmImportFavorites.Free; + + ImportFavorites(OD.FileName, AddToFavs); + OD.Free; + + ExportFavorites(sub_4E1DA8 + 'USERDATA.DAT', true); end; -procedure TfmMain.ImportFavorites; +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 - // TODO: TfmMain.ImportFavorites + 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; + + // 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:= 9999; + 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); + + UpdateServers; end; - - - procedure TfmMain.ExportFavoritesClick(Sender: TObject); +var + SD: TSaveDialog; + fmExportFavorites: TfmExportFavorites; + ExportPasswords: Boolean; begin - // TODO: TfmMain.ExportFavoritesClick + 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; end; -procedure TfmMain.ExportFavorites; +procedure TfmMain.ExportFavorites(FileName: String; ExportPasswords: Boolean); +var + ExportFile: File; + Temp, i: Integer; begin - // TODO: TfmMain.ExportFavorites + 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); end; procedure TfmMain.ExitClick(Sender: TObject); begin - // TODO: TfmMain.ExitClick + Close; end; procedure TfmMain.miViewClick(Sender: TObject); begin - // TODO: TfmMain.miViewClick + miFilterServerInfo.Checked:= Filtered; + miStatusBar.Checked:= sbMain.Visible; end; procedure TfmMain.ToggleFilterServerInfo(Sender: TObject); begin - // TODO: TfmMain.ToggleFilterServerInfo + if Filtered then begin + Filtered:= false; + pnBreakable.Height:= 16; + gbInfo.Caption:= ' Server Info '; + end else begin + Filtered:= true; + pnBreakable.Height:= 100; + pnBreakable.Top:= 0; + if lbServers.ItemIndex <> -1 then + gbInfo.Caption:= ' Server Info: ' + Servers[StrToInt(lbServers.Items.Strings[lbServers.ItemIndex])].HostName + ' '; + end; + UpdateServers; end; procedure TfmMain.ToggleStatusBar(Sender: TObject); begin - // TODO: TfmMain.ToggleStatusBar + sbMain.Visible:= not sbMain.Visible; + sbMain.Top:= 10000; end; procedure TfmMain.ConnectClick(Sender: TObject); +var + Idx: Integer; + SrvPwd: String; + NickName: String; begin - // TODO: TfmMain.ConnectClick + 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); end; procedure TfmMain.AddServerClick(Sender: TObject); +var + Server: String; + Dummy: Boolean; begin - // TODO: TfmMain.AddServerClick + 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; end; -procedure TfmMain.AddServer; +procedure TfmMain.AddServer(Server: String); +var + i, j: Integer; + Dupe: Boolean; begin - // TODO: TfmMain.AddServer + 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), 7777); + end else begin + Servers[i].Address:= Server; + Servers[i].Port:= 7777; + 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; end; procedure TfmMain.DeleteServerClick(Sender: TObject); +var + Idx, i: Integer; begin - // TODO: TfmMain.DeleteServerClick + 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; end; procedure TfmMain.RefreshServerClick(Sender: TObject); +var + Idx: Integer; begin - // TODO: TfmMain.RefreshServerClick + 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); end; procedure TfmMain.MasterServerUpdateClick(Sender: TObject); +var + SL: TStringList; + i: Integer; + IdHTTP: TIdHTTP; + fmMasterUpdate: TfmMasterUpdate; begin - // TODO: TfmMain.MasterServerUpdateClick + fmMasterUpdate:= TfmMasterUpdate.Create(Application); + fmMasterUpdate.Show; + Enabled:= false; + Application.ProcessMessages; + + IdHTTP:= TIdHTTP.Create(Application); + with IdHTTP do begin + ReadTimeout:= 20000; // 20secs + AllowCookies:= true; + + ProxyParams.BasicAuthentication:= False; + ProxyParams.ProxyPort:= 0; + + Port:= 80; + 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), 7777); + Servers[i].Ping:= 9999; + 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; + end; procedure TfmMain.CopyServerInfoClick(Sender: TObject); +var + Idx: Integer; + Str: String; begin - // TODO: TfmMain.CopyServerInfoClick + 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); end; procedure TfmMain.ServerPropertiesClick(Sender: TObject); +var + fmServerProperties: TfmServerProperties; + Idx: Integer; begin - // TODO: TfmMain.ServerPropertiesClick + 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; end; procedure TfmMain.RemoteConsoleClick(Sender: TObject); +var + fmRconConfig: TfmRconConfig; + Idx: Integer; begin - // TODO: TfmMain.RemoteConsoleClick + 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; end; procedure TfmMain.SettingsClick(Sender: TObject); +var + fmSettings: TfmSettings; begin - // TODO: TfmMain.SettingsClick + fmSettings:= TfmSettings.Create(Application); + fmSettings.ShowModal; + fmSettings.Free; end; procedure TfmMain.HelpTopicsClick(Sender: TObject); begin - // TODO: TfmMain.HelpTopicsClick + ShellExecute(Handle, 'open', 'http://wiki.sa-mp.com/', nil, nil, SW_SHOWNORMAL); end; procedure TfmMain.AboutClick(Sender: TObject); begin - // TODO: TfmMain.AboutClick + fmAbout.ShowModal; end; procedure TfmMain.tsServerListsChange(Sender: TObject; NewTab: Integer; var AllowChange: Boolean); begin - // TODO: TfmMain.tsServerListsChange + 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; end; -procedure TfmMain.QueryServerInfoParse; +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; begin - // TODO: TfmMain.QueryServerInfoParse + + + if DataLen < 11 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[10] of // PacketID + 'p': // Ping + begin + //OutputDebugString(PChar('[P] Packet from ' + Servers[Idx].Address + ':' + IntToStr(Servers[Idx].Port))); + if DataLen = 15 then begin + Move(Buf[11], 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 > 60 then begin + for j:= 1 to 61 do begin + chSIPingChart.Series[0].YValue[j-1]:= chSIPingChart.Series[0].YValue[j]; + end; + chSIPingChart.Series[0].Delete(61); + end; + + chSIPingChart.LeftAxis.Maximum:= chSIPingChart.Series[0].MaxYValue / 2 * 3; + + timeEndPeriod(5); + + RepaintServerList:= true; + end; + end; + + 'i': // Info + begin + BufPos:= 11; + + //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 > 1000 then TempWord:= 1000; + Inc(BufPos, 2); + Servers[Idx].Players:= TempWord; + + Move(Buf[BufPos], TempWord, 2); + if TempWord > 1000 then TempWord:= 1000; + 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 < 64) 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 < 40) 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 < 40) 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:= 11; + //OutputDebugString(PChar('[C] Packet from ' + Servers[Idx].Address + ':' + IntToStr(Servers[Idx].Port))); + Move(Buf[BufPos], TempWord, 2); + if TempWord > 100 then TempWord:= 100; + 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 > 1000000 then TempInt:= 1000000; + 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:= 11; + //OutputDebugString(PChar('[R] Packet from ' + Servers[Idx].Address + ':' + IntToStr(Servers[Idx].Port))); + Move(Buf[BufPos], TempWord, 2); + if TempWord > 30 then TempWord:= 30; + 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; end; -procedure TfmMain.QueryServerInfoError; +procedure TfmMain.QueryServerInfoError(SocketError: Integer); +var + err: array[0..512] of Char; begin - // TODO: TfmMain.QueryServerInfoError + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil, SocketError, 0, @err, 512, nil); + MessageDlg(err, mtError, [mbOk], 0); end; -procedure TfmMain.QueryServerInfo; +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; begin - // TODO: TfmMain.QueryServerInfo + 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)), 7777); + 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), 7777); + end; + end else begin + Host:= Server; + Port:= 7777; + end; + + if Tag = 0 then + Tag:= Port; + + Host:= GetIPFromHost(Host); + if (Length(Host) < 7) or (Length(Host) > 15) then + Exit; + + GetMem(Buf, 15); + 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[10]:= Byte('i'); // Info Packet Id + sendto(QuerySocket, Buf[0], 11, 0, ToAddr, ToLen); + Sleep(1); + end; + + if bPing = true then begin + Buf[10]:= Byte('p'); // Ping Packet Id + timeBeginPeriod(1); + Ticks:= timeGetTime; + timeEndPeriod(1); + Move(Ticks, Buf[11], 4); + sendto(QuerySocket, Buf[0], 15, 0, ToAddr, ToLen); + Sleep(1); + end; + + if bPlayers = true then begin + Buf[10]:= Byte('c'); // Players Packet Id + sendto(QuerySocket, Buf[0], 11, 0, ToAddr, ToLen); + Sleep(1); + end; + + if bRules = true then begin + Buf[10]:= Byte('r'); // Rules Packet Id + sendto(QuerySocket, Buf[0], 11, 0, ToAddr, ToLen); + Sleep(1); + end; + + FreeMem(Buf, 15); end; -procedure TfmMain.ServerConnect; +procedure TfmMain.ServerConnect(Server: String; Port: String; Password: String); +procedure GetDebugPrivs; +var + hToken: THandle; + xTokenPriv: TTokenPrivileges; + iRetLen: DWord; begin - // TODO: TfmMain.ServerConnect + 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; +begin + 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 31 = 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, 2000); + CloseHandle(hThread); + VirtualFreeEx(ProcInfo.hProcess, pLibRemote, MAX_PATH, MEM_RELEASE); + ResumeThread(ProcInfo.hThread); + //CloseHandle(ProcInfo.hProcess); end; procedure TfmMain.piCopyClick(Sender: TObject); begin - // TODO: TfmMain.piCopyClick + SetClipBoardStr(edSIAddress.Text); end; procedure TfmMain.pmCopyPopup(Sender: TObject); begin - // TODO: TfmMain.pmCopyPopup + piCopy.Enabled:= edSIAddress.Text <> '- - -'; end; procedure TfmMain.lbPlayersDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); +var + Idx: Integer; + TempRect: TRect; begin - // TODO: TfmMain.lbPlayersDrawItem + 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; end; procedure TfmMain.hcPlayersSectionResize(HeaderControl: THeaderControl; Section: THeaderSection); begin - // TODO: TfmMain.hcPlayersSectionResize + lbPlayers.Repaint; end; procedure TfmMain.lbRulesDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); +var + Idx: Integer; + TempRect: TRect; begin - // TODO: TfmMain.lbRulesDrawItem + 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; end; procedure TfmMain.hcRulesSectionResize(HeaderControl: THeaderControl; Section: THeaderSection); begin - // TODO: TfmMain.hcRulesSectionResize + lbRules.Repaint; end; procedure TfmMain.sbMainDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); +var + Pcnt: Integer; begin - // TODO: TfmMain.sbMainDrawPanel + 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); end; procedure TfmMain.lbPlayersExit(Sender: TObject); begin - // TODO: TfmMain.lbPlayersExit + lbPlayers.ItemIndex:= -1; end; procedure TfmMain.lbRulesExit(Sender: TObject); begin - // TODO: TfmMain.lbRulesExit + lbRules.ItemIndex:= -1; end; -procedure TfmMain.WMRecv; +procedure TfmMain.WMRecv(var Message: TMessage); +var + lpBuffer: Array[0..2048] of Char; + BufLen: Integer; + + FromAddr: TSockAddr; + FromLen: Integer; + + SrcAddr: String; + SrcPort: Word; begin - // TODO: TfmMain.WMRecv + ZeroMemory(@lpBuffer, sizeof(lpBuffer)); + + ZeroMemory(@FromAddr, sizeof(FromAddr)); + FromAddr.sin_family:= AF_INET; + FromLen:= SizeOf(FromAddr); + + BufLen:= recvfrom(QuerySocket, lpBuffer, 2048, 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, 2048, 0, FromAddr, FromLen); + SrcAddr:= inet_ntoa(FromAddr.sin_addr); + SrcPort:= htons(FromAddr.sin_port); + end; + end; procedure TfmMain.FormDestroy(Sender: TObject); +var + Reg: TRegistry; begin - // TODO: TfmMain.FormDestroy + 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); end; procedure TfmMain.FormShow(Sender: TObject); +var + ServFull, ServAddr, ServPort, ServPass: String; + NewServer: String; begin - // TODO: TfmMain.FormShow + //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, 7777)); + 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), 7777)); + end else begin + ServAddr:= ServFull; + ServPort:= '7777'; + end; + ServerConnect(ServAddr, ServPort, ServPass); + Application.Terminate; + end; + end; + sub_4E1CEC; end; -procedure TfmMain.BrowseForFolder; +function BrowseCallbackProc(hwnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer; stdcall; begin - // TODO: TfmMain.BrowseForFolder + 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; end; procedure TfmMain.miSampClick(Sender: TObject); begin - // TODO: TfmMain.miSampClick + ShellExecute(Handle, 'open', 'http://www.sa-mp.com/', nil, nil, SW_SHOWNORMAL); end; procedure TfmMain.tmrQueryQueueProcessTimer(Sender: TObject); begin - // TODO: TfmMain.tmrQueryQueueProcessTimer + //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; end; procedure TfmMain.label_urlClick(Sender: TObject); begin - // TODO: TfmMain.label_urlClick + ShellExecute(0, 'open', PAnsiChar('http://' + (Sender as TLabel).Caption), '', '', SW_SHOWNORMAL); end; -procedure TfmMain.CreateFASTDesktoplink1Click; +procedure TfmMain.CreateFASTDesktoplink1Click(Sender: TObject); +var + Idx: Integer; begin - // TODO: TfmMain.CreateFASTDesktoplink1Click + 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); end; procedure TfmMain.FormResize(Sender: TObject); begin - // TODO: TfmMain.FormResize + imLogo.Left:= fmMain.Width - imLogo.Width; + imLogo.Repaint; end; procedure TfmMain.imLogoClick(Sender: TObject); begin - // TODO: TfmMain.imLogoClick + fmAbout.ShowModal; end; end. +