Learn · concepts

Czym jest ASM (kod bajtowy Java)? Wyjaśnienie biblioteki

ASM to biblioteka Java do odczytu i zapisu kodu bajtowego JVM w czasie działania programu. Oto co robi, jak działa i dlaczego mody Minecraft na niej polegają.

TRtrolPublished 4 min read

Czym jest ASM w modowaniu Minecrafta?

ASM to biblioteka Java do odczytu, modyfikacji i zapisu kodu bajtowego JVM. Działa na skompilowanych plikach .class zamiast kodu źródłowego, dzięki czemu może sprawdzić lub przepisać klasę bez rekompilacji. Mody Minecraft opierają się na niej, ponieważ pozwala im na poprawianie gry w czasie ładowania, po tym jak gra została już skompilowana.

Dlaczego istnieje poprawianie kodu bajtowego

Gra Minecraft jest dostarczana jako skompilowany kod bajtowy, a nie jako kod źródłowy. Oznacza to, że autor modyfikacji nie może zmienić kodu źródłowego i ponownie skompilować całej gry: kod źródłowy nie istnieje. Jedynym sposobem na poprawianie kodu, którego nie posiadasz, jest sięgnięcie do poziomu kodu bajtowego, czyli zestawu instrukcji, które faktycznie wykonuje Java Virtual Machine. ASM jest praktycznym narzędziem do tego zadania.

Jak działa ASM

ASM przekształca skompilowaną klasę w coś, co program może edytować. Plik .class to po prostu kod bajtowy, czyli instrukcje, które wykonuje Java Virtual Machine. ASM analizuje ten kod bajtowy, udostępnia Ci metody i pola, i pozwala na dodawanie, usuwanie lub zmienianie instrukcji. Następnie zapisuje nową, poprawną klasę.

Czysta Java nie jest w stanie tego zrobić samodzielnie. Kompilator zamienia Twój kod źródłowy na kod bajtowy raz, a po tym kod bajtowy jest ustalony. ASM sięga do poziomu kodu bajtowego, czyli warstwy poniżej kodu źródłowego, który normalnie piszesz.

Wzór obserwatora i API drzew

ASM odczytuje klasę za pomocą ClassReader i zapisuje ją za pomocą ClassWriter. Pomiędzy tymi dwoma, Twój kod przegląda elementy klasy i decyduje, co zmienić. Istnieją dwa podejścia:

Podejście oparte na visitorze przetwarza klasę element po elemencie. Jest szybkie i zużywa mało pamięci, ponieważ nigdy nie przechowuje całej klasy w całości. Podejście oparte na drzewie ładuje klasę do obiektów, po których można swobodnie poruszać się i je edytować, co jest łatwiejsze do zrozumienia przy większych zmianach, ale zużywa więcej pamięci.

PodejścieJak działaNajlepsze dla
API VisitoraPrzetwarza zdarzenia klasy w trakcie odczytuMałe, szybkie edycje przy niskim zużyciu pamięci
API DrzewaBuduje edytowalny model obiektu klasyWiększe lub bardziej złożone refaktoryzacje

Dlaczego mody Minecraft używają ASM

Mody muszą zmieniać kod gry, którego nie napisali i nie mogą go ponownie skompilować. Gra jest dostarczana jako skompilowane klasy, więc jedyną drogą jest poziom kodu bajtowego, a ASM to właśnie zapewnia. Mod może wstrzyknąć haczyk do metody gry, przekierować wywołanie lub dodać pole, wszystko podczas uruchamiania.

Większość twórców modów nie wywołuje ASM bezpośrednio. Używają Mixin, frameworku wyższego poziomu, który opiera się na ASM i przekształca proste adnotacje w edycje kodu bajtowego. Piszesz małą klasę Java opisującą zmianę, a framework wykonuje niskopoziomową pracę z ASM za Ciebie. Szczególnie mody Fabric polegają na tym łańcuchu.

Kiedy musisz bezpośrednio pracować z ASM

Rzadko piszesz surowy kod ASM jako autor modyfikacji. Pojawia się to, gdy narzędzie potrzebuje większej kontroli niż ta, którą umożliwiają adnotacje, na przykład w przypadku loadera, obfuscatora lub patchera, który całkowicie przepisuje klasy. Dla codziennych modyfikacji wystarczy warstwa adnotacji, a ona jest znacznie mniej podatna na błędy.

FAQ