Ist an sich schon richtig, aber RequestSpawn macht erstmal nix du musst dann 0x3AD0 ebenfalls noch aufrufen.
Edit: true, false ist aber falsch, der Stack muss nicht gecleant werden denn es ist ein Thiscall. Also false, true
Beiträge von Madd92
-
-
-
stLocalPlayer ist eine Struktur in der SAMP.dll. Dazu gibt es in der UDF auch schon Funktionen, die diese Pointer nutzen. In den globalen Variablen wirst du auch die Offsets dazu finden, oder eben im s0beit Source:
C
Alles anzeigenstruct stPlayerPool { uint32_t ulMaxPlayerID; uint16_t sLocalPlayerID; void *pVTBL_txtHandler; std::string strLocalPlayerName; struct stLocalPlayer *pLocalPlayer; int iLocalPlayerPing; int iLocalPlayerScore; struct stRemotePlayer *pRemotePlayer[SAMP_MAX_PLAYERS]; int iIsListed[SAMP_MAX_PLAYERS]; DWORD dwPlayerIP[SAMP_MAX_PLAYERS]; // always 0 };
In der UDF wird es etwas umständlich so gemacht, funktioniert aber problemlos:
PHP
Alles anzeigendwAddress := readDWORD(hGTA, dwSAMP + SAMP_INFO_OFFSET) if (ErrorLevel || !dwAddress) { ErrorLevel := ERROR_READ_MEMORY return -1 } dwAddress := readDWORD(hGTA, dwAddress + SAMP_PPOOLS_OFFSET) if (ErrorLevel || !dwAddress) { ErrorLevel := ERROR_READ_MEMORY return -1 } dwPlayers := readDWORD(hGTA, dwAddress + SAMP_PPOOL_PLAYER_OFFSET) if (ErrorLevel || !dwPlayers) { ErrorLevel := ERROR_READ_MEMORY return -1 } dwLocalPlayer := readDWORD(hGTA, dwPlayers + SAMP_LOCALPLAYER_OFFSET) if(ErrorLevel) { ErrorLevel := ERROR_READ_MEMORY return -1 }
-
Na aus dem Source Code von s0beit:
#define SAMP_FUNC_REQUEST_SPAWN 0x3EC0
#define SAMP_FUNC_SPAWN 0x3AD0 -
callWithParams(hGTA, dwSAMP + 0x3AD0, [["i", localPlayerPointer]], false, true)
Wäre ein korrekter Aufruf, localPlayerPointer musst du eben noch auslesen vorher. -
Wenn du dich wirklich mit dem Thema beschäftigen willst, solltest du Kenntnis haben von:
1. C/C++
2. Calling Conventions
3. den Memory und callWithParams Funktion der UDF, oder deinen eigenen Memory Funktionen
4. grundlegendes AssemblerverständnisAlso die Funktion als Beispiel, einfach nur aus dem s0beit Source in AHK und die UDF Funktion zu integrieren wäre einfach:
Cvoid playerSpawn(void) { if (g_SAMP == NULL) return; ((void(__thiscall *) (void *_this)) (g_dwSAMP_Addr + SAMP_FUNC_REQUEST_SPAWN)) (g_Players->pLocalPlayer); ((void(__thiscall *) (void *_this)) (g_dwSAMP_Addr + SAMP_FUNC_SPAWN)) (g_Players->pLocalPlayer); }
Es gibt zwei Funktionsaufrufe, die komplett identisch sind, bis auf die aufgerufene Funktion natürlich. Du hast also nur einen Parameter, in diesem Fall den Local-Player-Pointer.
Wenn du dir die callWithParams Funktion anschaust, solltest du schnell erkennen, welche Parameter wie zu übergeben sind.
Für so eine einfache Funktion ist es wie gesagt, mit den in der UDF enthalten Memory Funktionen ziemlich einfach. Aber je mehr du ausprobieren willst, desto wichtiger ist es, dass du dich informierst über die Zusammenhänge. -
Dann probier mal bitte dieses Script, am besten auf einem Testserver auf dem du nicht gekickt wirst:
PHP
Alles anzeigen#NoEnv #SingleInstance, Force #Include SAMP.ahk global commandCounter := 0 return SendChat(wText) { if (!checkHandles()) return false if (SubStr(wText, 1, 1) == "/") { if (commandCounter >= 6) return false if (commandCounter == 0) SetTimer, CommandReset, 1000, 1 dwFunc := dwSAMP + FUNC_SAMP_SENDCMD commandCounter++ } else dwFunc := dwSAMP + FUNC_SAMP_SENDSAY return callWithParams(hGTA, dwFunc, [["s", wText]], false) } CommandReset: commandCounter := 0 return #If WinActive("GTA:SA:MP") && !isInChat() !1:: Loop, 10 SendChat("/Test") return
Die SendChat-Funktion in der SAMP.ahk logischerweise ausklammern.
-
Du könntest entweder in den mod_sa Code gucken, wo und wie die Funktionadresse verwendet wird, oder du schaust dir in nem Debugger oder Disassembler die SAMP-Funktion selber an und baust sie nach.
-
Keine Ahnung, ob man das hier verlinken darf, wenn nicht dann tut es mir leid:
Source - mod_s0beit_sa
Man kann statt Overlays auch die TextDraws von SAMP nutzen. Im UDF Forum hab ich da mal Funktionen zu gepostet, die allerdings nicht großartig ausgearbeitet sind. Sie funktionieren aber bei mir ohne Probleme. -
Ich glaube er will einen Integer als String ausgeben und die Tausendertrennzeichen einfügen
Hier gibt es ein paar Beispiele für SA-MP. -
Steht global commandCounter := 0 oben im Script unter den Deklarationen vor dem ersten Return?
-
Wird der Timer denn ausgeführt?
-
Also bei mir funktioniert's. Pack mal in den Timer ein AddChatMessage rein, um zu sehen, ob er funktioniert (bzw. je nach Editor eine Nachricht in die Debug Konsole). Gleiches für commandCounter in der SendChat Funktion.
-
Ich hab keine Ahnung von GTA:N, aber du scriptest in C#? Wenn ja dann einfach ToString("N") nutzen.
-
Zum Beispiel so:
PHP
Alles anzeigenglobal commandCounter := 0 SetTimer, CommandReset, 1000 CommandReset: commandCounter := 0 return SendChat(wText) { if (!checkHandles()) return false if (SubStr(wText, 1, 1) == "/") { if (commandCounter >= 6) return false dwFunc := dwSAMP + FUNC_SAMP_SENDCMD commandCounter++ } else dwFunc := dwSAMP + FUNC_SAMP_SENDSAY return callWithParams(hGTA, dwFunc, [["s", wText]], false) }
Allerdings bleibt die Frage, wie genau das Anti-Spam System vom Server eingestellt ist. Denn mit dem Code oben könnte es passieren, dass du 6 Commands schickst, dann praktisch sofort danach der Timer ausgeführt wird und die Variable zurücksetzt und dann wieder 6 Commands verschickt werden. Daher dann eher so:PHP
Alles anzeigenglobal commandCounter := 0 CommandReset: commandCounter := 0 return SendChat(wText) { if (!checkHandles()) return false if (SubStr(wText, 1, 1) == "/") { if (commandCounter >= 6) return false if (commandCounter == 0) { SetTimer, CommandReset, 1000, 1 } dwFunc := dwSAMP + FUNC_SAMP_SENDCMD commandCounter++ } else dwFunc := dwSAMP + FUNC_SAMP_SENDSAY return callWithParams(hGTA, dwFunc, [["s", wText]], false) }
Edit: Wenn counter gleich 0 nicht 1.
-
Ich gehe mal davon aus, dass du die UDF nutzt. Wenn du das nur für den Keybinder selber haben möchtest, kannst du entweder vor jedes SendChat eine Abfrage schreiben, über eine Counter-Variable oder direkt die SendChat Funktion ändern und dort die Abfrage einbauen. Die Variable wird mit jedem Mal hochgezählt, wenn ein Command ausgeführt wird und ein 1000ms Timer sorgt dafür, dass die Variable resettet wird. Wenn du alle Commands mitzählen willst, auch die die du händisch eingibst, musst du ein System schreiben, welches die Commands erst abfängt, bevor sie abgeschickt werden.
Edit: Wenn ich so darüber nachdenke, glaube ich nicht, dass es möglich ist, per Hand 6 Commands die Sekunde zu schicken
-
Zum zweiten: "Wenn einer der Elemente zu Beginn vorab ausgewählt sein soll, müssen zwei senkrechte Striche nach diesem Element erfolgen (z. B. Rot|Grün||Blau)." Bzw. "GuiControl, Choose, SteuerelementID, N".
Dein Overlayproblem kann ich selber nicht nachvollziehen, bei mir funktioniert das Script ohne Probleme. Allerdings könnte es an den Mods liegen, die du installiert hast.
-
Das ist auch in der UDF drin. Aber wie gesagt, geht nur innerhalb der Streaming-Reichweite.
-
Ich meine, den Skin kann man nur auslesen, wenn der Spieler in Streaming-Reichweite ist. Werden auf dem Server die PDler in der Spielerliste farblich hervorgehoben? Dann wird vermutlich die getPlayerColor Funktion genutzt.
-
Ich würde es so machen:
PHP
Alles anzeigen#UseHook #Include SAMP.ahk #Persistent global timerWait := false SetTimer, ReadChat, 50 SetTimer, ThrowBack, 2000 return ReadChat: if (!WinActive("GTA:SA:MP")) return GetChatLine(0, line) if (InStr(line, "Du kannst erst in ") && InStr(line, " Minuten wieder angeln")) { SetTimer, Timer2, 10000, 1 ; // 10000 = 10 Sekunden, 15 Minuten = 900000 timerWait := true } return ThrowBack: if (!WinActive("GTA:SA:MP")) return SendChat("/throwbackall") if (timerWait) { timerWait := false SetTimer, Timer2, 2000 } return #If WinActive("GTA:SA:MP") && !isInChat() && !isInMenu() ; // ##### Eventuelle Hotkeys hier drunter #####
Ich rate dir, dich in AHK und Funktionen, die du benutzen willst, einfach mal einzulesen, dann kannst du einfache Fehler vermeiden
http://ahkde.github.io/docs/AutoHotkey.htm