Ich werde kurz erklären, wie man einen Core-Mod in der Minecraft Forge 1.15.2-Umgebung schreibt. Was ist ASM? Was ist ein Bytecode? Ich werde es hier nicht erklären. Entschuldigung. Ich werde Javascript auch nicht erklären. Entschuldigung.
Wenn Sie jedoch ein Modder sind, der Core-Mods verwendet, können Sie mit einem Gefühl schreiben.
Forge 1.13 oder höher wird wahrscheinlich auf die gleiche Weise funktionieren, aber ich habe es nicht überprüft.
Ich habe sehr viel auf diese Seite und den Beispielcode verwiesen. Ich bin meinen Vorgängern zutiefst dankbar. 99.99 - Coremod
Immer noch einfach. "coremod" ist einer der von Forge bereitgestellten Mechanismen, mit denen Sie den Java-Code von Minecraft selbst neu schreiben können (es gibt einige Missverständnisse). Die dafür verwendete Bibliothek ist ASM. Außerdem ist der Code selbst nicht der menschliche Code, den Sie normalerweise schreiben, sondern der kompilierte Bytecode. Wenn Sie ASM schreiben, können Sie auf jeden Fall alles tun. Der Wettbewerb mit anderen Mods kann jedoch zunehmen.
Dieses PDF wird dringend empfohlen (aber lang), um ASM zu studieren. ASM 4.0 A Java bytecode engineering library
Minecraft: 1.15.2 Minecraft Forge: 1.15.2-31.2.0
Früher wurde coremod in Java-Code geschrieben, ab 1.13 wird es jedoch in ** Javascript ** geschrieben. Es ist in Ordnung zu glauben, dass der ASM selbst (wahrscheinlich) genauso geschrieben ist wie zuvor.
Es sind mindestens zwei Dateien erforderlich.
coremods.json Platziere es direkt unter ** main / java / resources / META-INF / folder **. Der Dateiname sollte wahrscheinlich "coremods.json" sein.
Der Inhalt ist wie folgt.
coremods.js
{
"TestMod Transformer": "testmod-transformer.js"
}
Der Schlüssel im Array ("Test Mod Transformer") ist wahrscheinlich alles. Ich denke, es ist egal, was der Fall ist. Schreiben Sie für den Wert den Speicherort der js-Datei, die Sie schreiben möchten.
Wenn Sie nur den Dateinamen wie oben schreiben, geben Sie die Datei in ** main / java / resources / direkt unter ** an. Ich habe nicht versucht, ob der absolute Pfad oder der relative Pfad funktioniert, aber ich habe das Gefühl, dass der relative Pfad zu funktionieren scheint.
coremods.js
{
"TestMod Transformer": "testmod-transformer.js",
"TestMod Transformer2": "testmod-transformer2.js"
}
Sie können auch mehrere Javascript-Dateien gleichzeitig angeben.
Der Klarheit halber setzen wir es direkt unter main / java / resources /. Wenn Sie den Speicherort ändern, ändern Sie bitte den Wert des Inhalts von coremods.json oben. Das js, das tatsächlich ASM schreibt, sieht wie folgt aus.
testmod-transformer.js
function initializeCoreMod() {
return {
'coremodmethod': {
'target': {
'type': 'METHOD',
'class': 'your.target.class',
'methodName': 'targetMethodName',
'methodDesc': 'targetMethodDescriptor'
},
'transformer': function(method) {
//Schreiben Sie hier die ASM-Verarbeitung.
return method;
}
}
}
}
In die js-Datei müssen Sie eine Funktion mit dem Namen "initializeCoreMod ()" schreiben, die json zurückgibt. Es ist in Ordnung, wenn Sie oben kopieren und einfügen. Wenn Sie im obigen Abschnitt "ASM-Verarbeitung hier schreiben" verschiedene Dinge schreiben, ist dies abgeschlossen.
Danke für deine harte Arbeit. Dann kommst du normalerweise hierher? Es scheint gesagt zu werden, also werde ich ein bisschen mehr schreiben. Wenn Sie das oben Genannte verstehen, können Sie den Rest erledigen.
Sie können drei Arten von Zielen angeben: "FELD", "METHODE" und "KLASSE". Es stört Felder, Methoden bzw. Klassen. Mit anderen Worten, Sie können die folgenden drei Möglichkeiten schreiben.
testmod-transformer.js
function initializeCoreMod() {
return {
'coremodmethod': {
'target': {
'type': 'FIELD',
'class': 'your.target.class',
'fieldName': 'targetFieldName'
},
'transformer': function(field) {
//Schreiben Sie hier die ASM-Verarbeitung.
return field;
}
}
}
}
testmod-transformer.js
function initializeCoreMod() {
return {
'coremodmethod': {
'target': {
'type': 'METHOD',
'class': 'your.target.class',
'methodName': 'targetMethodName',
'methodDesc': 'targetMethodDescriptor'
},
'transformer': function(method) {
//Schreiben Sie hier die ASM-Verarbeitung.
return method;
}
}
}
}
testmod-transformer.js
function initializeCoreMod() {
return {
'coremodmethod': {
'target': {
'type': 'CLASS',
'class': 'your.target.class'
},
'transformer': function(class) {
//Schreiben Sie hier die ASM-Verarbeitung.
return class;
}
}
}
}
Die erforderlichen Werte in "Ziel" sind wie oben. Aus dem persönlichen Grund, dass das Feld von Java aus den Reflection Helper stören kann und es oft genug ausreicht, um die Methode zu stören, auch wenn es die Klasse selbst nicht stört, werde ich FIELD und CLASS unten ändern. Wird nicht berühren. Jemand bitte.
function initializeCoreMod() {
var ASMAPI = Java.type("net.minecraftforge.coremod.api.ASMAPI");
var Opcodes = Java.type('org.objectweb.asm.Opcodes');
var InsnList = Java.type("org.objectweb.asm.tree.InsnList");
var InsnNode = Java.type("org.objectweb.asm.tree.InsnNode");
var mappedMethodName = ASMAPI.mapMethod("target_srg_func_name");
return {
'coremodmethod': {
'target': {
'type': 'METHOD',
'class': 'your.target.class',
'methodName': mappedMethodName,
'methodDesc':'targetMethodDescriptor'
},
'transformer': function(method) {
print("Enter transformer.");
var arrayLength = method.instructions.size();
var target_instruction = null;
//search the target instruction from the entire instructions.
for(var i = 0; i < arrayLength; ++i) {
var instruction = method.instructions.get(i);
if(instruction.name === "targetMethodName") {
target_instruction = instruction;
break;
}
}
if(target_instruction == null) {
print("Failed to detect target.");
return method;
}
var toInject = new InsnList();
// toInject.add(new InsnNode(Opcodes.POP));
toInject.add(new InsnNode(Opcodes.RETURN));
// Inject new instructions just after the target.
method.instructions.insert(target_instruction, toInject);
return method;
}
}
}
}
Ich denke, die Aussichten haben sich erheblich verbessert. Ich werde in der Reihenfolge erklären.
var ASMAPI = Java.type("net.minecraftforge.coremod.api.ASMAPI");
var Opcodes = Java.type('org.objectweb.asm.Opcodes');
var InsnList = Java.type("org.objectweb.asm.tree.InsnList");
var InsnNode = Java.type("org.objectweb.asm.tree.InsnNode");
Ich weiß nicht, was für eine Art von Magie es ist, aber wenn Sie den üblichen Namen der Importzielklasse in das Argument "Java.type ()" einfügen, können Sie es so verwenden, als wäre es Java (Erklärung Verschiedenes). Wenn Opcodes kommen, habe ich das Gefühl, dass es bereits 100 Leute gibt. Aber ich habe Probleme mit der Code-Vervollständigung, die nicht funktioniert. Wenn jemand weiß, wie man es ergänzt, lass es mich wissen. Ich bin sicher, dass ASMAPI und Opcodes alle Änderungen verwenden werden, aber ich denke, Sie bevorzugen es, andere Klassen aufzurufen. Das aktuelle Coremod verwendet die sogenannte Tree-API. Überprüfen Sie daher dort separat, welche Klassen verfügbar sind.
var mappedMethodName = ASMAPI.mapMethod("target_srg_func_name");
return {
'coremodmethod': {
'target': {
'type': 'METHOD',
'class': 'your.target.class',
'methodName': mappedMethodName,
'methodDesc':'targetMethodDescriptor'
},
'transformer': function(method) {
return method;
}
}
}
Ich habe es "coremodmethod" genannt, aber es scheint, dass dies eine beliebige Zeichenfolge sein kann. Andere "Ziel" und "Transformator" müssen dies sein.
Eine Methode namens mapMethod () ist in ASMAPI definiert und gibt den Namen der zugeordneten Methode aus dem Namen der verschleierten Methode zurück. Die "saveScreenshotRaw" -Methode der Klasse "net.minecraft.util.ScreenShotHelper" lautet beispielsweise "func_228051_b_" oder so ähnlich. Wenn Sie den Methodennamen mit dieser mapMethod () nicht erhalten, funktioniert er in der Entwicklungsumgebung, jedoch nicht in der realen Umgebung (oder umgekehrt).
Fügen Sie beim eigentlichen Schreiben den Namen der verschleierten Methode in das Argument "ASMAPI.mapMethod (" func_228051_b_ ")" ein.
Wählen Sie für den verschleierten Methodennamen die Zuordnung aus, die zu Ihrer Entwicklungsumgebung passt, aus dem üblichen MCP-Bot.
Übrigens gibt es einige Leute, die es nicht finden können, selbst wenn sie es durch MCP-Mapping suchen. Sie müssen den Methodennamen nicht mit mapMethod () abrufen, da sie bereits unter dem Namen ausgeführt werden, der sowohl in der Entwicklungsumgebung als auch in der realen Umgebung leicht zu verstehen ist.
"methodDesc" ist der übliche Deskriptor.
void hogehoge(int i, float f)
Wenn es sich um eine solche Methode handelt, lautet der Deskriptor "(IF) V".
Sowohl IDEA als auch Eclipse verfügen über ein Plug-In, das Java-Code im Byte-Code anzeigt. Ich denke, dass die Verwendung des Plug-Ins das Kopieren verbessert.
'transformer': function(method) {
print("Enter transformer.");
var arrayLength = method.instructions.size();
var target_instruction = null;
//search the target instruction from the entire instructions.
for(var i = 0; i < arrayLength; ++i) {
var instruction = method.instructions.get(i);
if(instruction.name === "targetMethodName") {
target_instruction = instruction;
break;
}
}
if(target_instruction == null) {
print("Failed to detect target.");
return method;
}
var toInject = new InsnList();
// toInject.add(new InsnNode(Opcodes.POP));
toInject.add(new InsnNode(Opcodes.RETURN));
// Inject new instructions just after the target.
method.instructions.insert(target_instruction, toInject);
return method;
}
Ich persönlich denke, dass die Teile, die tatsächlich modifiziert werden, einfacher zu schreiben sind als zuvor.
Die Methode, die das Argument kreuzt, verfügt über ein Feld namens "Anweisungen", in das der Bytecode zeilenweise in ein Array eingegeben wird. Der Bytecode der Methode selbst lautet. Danach können Sie an jeder Stelle im Bytecode eine Rückgabe löschen, ändern oder einfügen.
Oben haben wir eine Änderung vorgenommen, die "sofort zurückkehrt, wenn eine bestimmte Methode aufgerufen wird". Drehen Sie Anweisungen primär nacheinander mit for, um die Zeile (dh Anweisungen) zu finden, in der die Zielmethode aufgerufen wird.
Wenn Sie die gesuchte Anweisung gefunden haben, fügen Sie eine neue Anweisung ein.
InsnList () ist eine Klasse zum Erstellen einer Reihe von Befehlspaaren, und jeder Befehl wird dieser Klasse hinzugefügt (). Hier wird als "neuer InsnNode (Opcodes.RETURN)" nur die Anweisung zur InsnList hinzugefügt, die "return" bedeutet.
Schließlich haben Anweisungen eine Methode namens insert (Argument 1, Argument 2), die die Anweisungen in die in Argument 2 angegebene insnList unmittelbar nach ** unmittelbar nach der in Argument 1 angegebenen Anweisung hinzufügt. Ich werde.
Hier wird "return" unmittelbar nach einer bestimmten Methode hinzugefügt.
Es ist wichtig zu beachten, dass wenn Sie coremod berührt haben, Sie wissen, dass die Frames inkonsistent werden und wahrscheinlich auch in der aktuellen Version abstürzen, wenn Sie so viel zurückgeben, wie Sie möchten. Ich denke, dass Werte, die in den Frame geladen werden, aber nicht mehr verwendet werden, die richtige Anzahl von Pops angezeigt werden müssen.
Ich dachte, ich würde ein Beispiel schreiben, aber es hat mir geholfen. Ich werde es wieder schreiben, wenn ich freie Kapazität habe.
Ich habe das Gefühl, dass es verschiedene Fehler und Missverständnisse gibt. Bitte lassen Sie mich wissen, wenn Sie es bemerken.
Vielen Dank für Ihre Beziehung.
Recommended Posts