Przejdź do głównej zawartości

Pliki .patch

Pliki .patch w Union pozwalają modyfikować pamięć gry (kod, dane) bez konieczności kompilowania pełnego pluginu C++. Są one interpretowane w czasie rzeczywistym przez Union i przydają się do wprowadzania drobnych poprawek, naprawiania błędów lub zmiany domyślnych wartości silnika.

informacja

Pliki patch muszą mieć rozszerzenie .patch i znajdować się w katalogu System/ lub dowolnym innym katalogu monitorowanym przez Union (np. wewnątrz woluminu .vdf lub .mod).

Wyłączanie patchy​

Możesz zapobiec uruchamianiu określonych patchy lub funkcji używając dyrektywy #disable. Ma ona najwyższy priorytet.

#disable [NazwaRef]     // Wyłącza konkretny patch po nazwie
#disable [Reference] // Wyłącza wszystkie operacje na referencjach
#disable [Cast] // Wyłącza wszystkie operacje rzutowania typów

Bloki silnika​

Użyj bloków #engine, aby ograniczyć wykonywanie kodu do konkretnych wersji gry lub sum kontrolnych pliku wykonywalnego.

#engine [G1, G2A]
// Kod tutaj uruchomi się tylko na Gothic 1 i Gothic 2 NK
#/engine

Obsługiwane tagi: G1, G1A, G2, G2A. Można również podać sumę CRC32: #engine [0x2BCD7E30]. Jeśli blok #engine nie zostanie użyty, kod uruchomi się na wszystkich wersjach.

Bloki patchy​

Blok #patch definiuje zakres konkretnej modyfikacji.

#patch [Nazwa Mojego Patcha]
// Instrukcje patcha
#/patch

Użycie [GLOBAL DATA] jako nazwy sprawia, że zdefiniowane zmienne są widoczne we wszystkich innych patchach.

#patch [GLOBAL DATA]
INT GlobalValue = 100
#/patch

Typy danych​

Union wspiera kilka podstawowych typów danych do definiowania zmiennych i stałych.

  • INT: INT Value = 123 lub INT Hex = 0x123
  • FLOAT: FLOAT Value = 123.45
  • BOOL: BOOL Flag = true (lub 1, false, 0)
  • HEX: Surowe bajty. Może być ciągiem znaków lub bajtami oddzielonymi spacją.
    • HEX Bytes = '90 90 90'
    • HEX String = "Witaj"
  • STRING: STRING Text = "Witaj Świecie"

Referencje (@)​

Operator @ tworzy referencję do adresu pamięci lub ustawienia INI. Przypisanie wartości do referencji modyfikuje wartość pod tym adresem. Automatycznie zdejmuje ochronę pamięci, jeśli jest to konieczne.

Referencje do pamięci​

// Zapisz liczbę całkowitą 100 pod adres 0x123456
INT @0x123456 = 100

// Użycie wyrażenia do obliczenia adresu
INT @(0x123456 + 4) = 200

Referencje do INI​

Możesz powiązać zmienną z ustawieniem w SystemPack.ini.

// Linkuje do SystemPack.ini, sekcja [CORE], klucz ShowDebugWindow
INT @SystemPack:Core:ShowDebugWindow = 1

Rzutowanie typów​

Union wspiera zarówno niejawne, jak i jawne rzutowanie typów.

Niejawne​

INT Value = 5
FLOAT Result = 10.0 + Value * 5.3 // Value jest automatycznie rzutowane na FLOAT

Jawne​

INT Value = 5
FLOAT Result = 10.0 + FLOAT Value * 5.3

Rzutowanie HEX​

Rzutowanie na/z HEX traktuje dane jako surowe bajty.

INT Source = 65535
HEX Bytes = HEX Source // Konwertuje int na surowe bajty
INT Restored = INT Bytes // Konwertuje bajty z powrotem na int

Warunki​

Możesz używać IF, ELSE i END do warunkowego wykonywania kodu. Warunek musi ewaluować do typu BOOL.

IF BOOL @SystemPack:Core:ShowDebugWindow != true
MessageBox("Okno debugowania jest wyłączone")
ELSE
MessageBox("Okno debugowania jest włączone")
END

Strony pamięci​

Możesz alokować własne strony pamięci do przechowywania danych lub kodu. Jest to przydatne dla dużych struktur danych lub własnych wstawek kodu (code caves).

// Alokacja zdefiniowana przez indeks (musi być > 0)
AllocPage(15, 1024)

// Użycie
HEX @15x00000000 = '90 90 90 C3'

Statyczne patche​

Statyczne patche są zoptymalizowane pod kątem wydajności. Przeznaczone są do prostych nadpisań pamięci, które nie wymagają warunków ani złożonej logiki. Są one cache'owane i nakładane szybciej.

#patch static [Szybki Patch]
HEX @0x007524A6 = 'E9 EB C2 F1 FF'
#/patch

Wstawki asemblerowe​

Dla złożonej logiki możesz wstrzykiwać kod asemblera bezpośrednio w przepływ wykonania silnika.

#assembler [Adres]
// Instrukcje asemblera
#/assembler

Przepływ wykonania i Orgcode​

Gdy definiujesz wstawkę asemblerową pod adresem, Union wpisuje tam 5-bajtowy skok JMP do twojego kodu. Nadpisuje to istniejące instrukcje.

  • Aby wykonać nadpisane instrukcje, użyj słowa kluczowego orgcode.
  • orgcode automatycznie przelicza offsety relokacji.
  • Jeśli nie użyjesz orgcode, oryginalne instrukcje zostaną efektywnie usunięte.
#assembler [0x0068CF02]
// Twój własny kod
mov eax, 123

// Wykonaj oryginalne instrukcje, które zostały nadpisane przez hook
orgcode
#/assembler

Częściowe nadpisania (orgcode +)​

Jeśli 5-bajtowy skok hooka częściowo nadpisuje wiele instrukcji, możesz użyć orgcode +N, aby pominąć pierwsze N instrukcji.

// Przykład: Pomiń pierwszą nadpisaną instrukcję, wykonaj resztę
orgcode +1

Przekazywanie zmiennych​

  • Przekazywanie przez wartość: Standardowe typy (INT, FLOAT) są przekazywane przez wartość.
  • Przekazywanie przez adres: Zmienne HEX oraz zmienne zdefiniowane w [GLOBAL DATA] są przekazywane przez adres.
#patch [Przykład]
HEX Data = '00 00 00 00'

#assembler [0x123456]
// Załaduj adres Data do EAX
lea eax, [$Data]
orgcode
#/assembler
#/patch

Ograniczenia​

  • Adres wstrzyknięcia musi pozwalać na wpisanie 5-bajtowego skoku bez przecinania instrukcji w połowie.
  • Nadpisywane bajty nie mogą zawierać celu skoku (etykiety) z innej części kodu, w przeciwnym razie gra ulegnie awarii.
  • Jeśli nie podano instrukcji retn, wykonanie powraca do pierwszej ważnej instrukcji po wstawce.

Wbudowane funkcje​

Union udostępnia standardową bibliotekę funkcji do użycia w patchach.

Matematyka​

  • Sqrt(value): Zwraca pierwiastek kwadratowy liczby.
  • Min(a, b): Zwraca mniejszą z dwóch wartości.
  • Max(a, b): Zwraca większą z dwóch wartości.
  • Lim(min, value, max): Ogranicza wartość do przedziału min i max.

Pamięć i HEX​

  • GetHexSize(value): Zwraca rozmiar zmiennej HEX w bajtach.
  • SetHexSize(value, size): Ręcznie ustawia rozmiar zmiennej HEX.
  • SetHexAutoSize(value): Automatycznie ustala rozmiar zmiennej HEX (zakłada logikę ciągu zakończonego zerem).
  • HexViewBox(ptr, size = auto): Wyświetla okno wiadomości ze zrzutem pamięci pod adresem ptr.

Wyszukiwanie i operacje na pamięci​

  • FindAndReplace(from, to, start, len): Wyszukuje wzorzec bajtowy from i zamienia go na to w zakresie od start do start+len.
  • MemSet(start, byte, len): Wypełnia len bajtów pamięci zaczynając od start wartością byte.
  • MemCopy(start, dest, len): Kopiuje len bajtów z start do dest.
  • GetRefAddress(ref): Zwraca adres pamięci zmiennej referencyjnej.
  • JMP(from, to): Wpisuje 5-bajtową instrukcję JMP pod adresem from skaczącą do to.
  • CALL(from, to): Wpisuje 5-bajtową instrukcję CALL pod adresem from wywołującą to.

Operacje na plikach​

  • RenameFile(oldName, newName): Zmienia nazwę pliku.
  • CopyFile(oldName, newName, replace = true): Kopiuje plik.
  • MoveFile(oldName, newName): Przenosi plik.
  • DeleteFile(fileName): Usuwa plik.
  • FileExists(fileName): Zwraca true jeśli plik istnieje, w przeciwnym razie false.

System i silnik​

  • MessageBox(text): Wyświetla standardowe okno wiadomości Windows.
  • PrintScreen(text): Wypisuje tekst do wewnętrznej konsoli gry (zSpy).
  • GetUnionVersion(): Zwraca zainstalowany numer wersji Union.
  • GetLanguage(): Zwraca ID języka Union (1=Rus, 2=Eng, 3=Deu, 4=Pol, ...).
  • Restart(): Wymusza restart gry.
  • AllocPage(id, size): Alokuje stronę pamięci o indeksie id (musi być > 0).
  • FreePage(id): Zwalnia stronę pamięci o indeksie id.
  • FindSteamDirectory(): Zwraca ścieżkę do katalogu instalacyjnego Steam.
  • GetScreenSizeX(): Zwraca szerokość ekranu.
  • GetScreenSizeY(): Zwraca wysokość ekranu.

Okna i procesy​

  • ShowCmd(): Pokazuje okno konsoli.
  • HideCmd(): Ukrywa okno konsoli.
  • FindWindowHandle(windowName): Zwraca uchwyt HWND okna po jego nazwie.
  • GetProcessID(processName): Zwraca PID procesu.
  • StartProcess(path, args, hide): Uruchamia zewnętrzny proces.

Pluginy i pomocnicze​

  • LoadPlugins(fileMask): Ładuje pluginy pasujące do maski (np. Shw32.dll lub Data\*.dll).
  • ModuleBase(moduleName): Zwraca adres bazowy załadowanego modułu (DLL).
  • ModuleSize(moduleName): Zwraca rozmiar załadowanego modułu.
  • OptionDef(section, name, value): Definiuje domyślną wartość dla ustawienia INI, jeśli nie istnieje.
  • ShowFunctionList(moduleName): Loguje wszystkie wyeksportowane funkcje modułu do zSpy.
  • Concat(str1, str2): Łączy dwa ciągi znaków.

Interfejs zewnętrzny​

  • LoadLibrary(libName): Ładuje zewnętrzną bibliotekę DLL do procesu.
  • ImportSymbol(moduleName, symbolName): Zwraca adres wyeksportowanej funkcji z biblioteki DLL.
  • ExecAsm(hexCode): Wykonuje surowy bajtkod asemblera i zwraca wynik rejestru EAX.