gamerforEA / Minecraft-ClientFixer

Minecraft ASM Patcher
GNU General Public License v3.0
23 stars 6 forks source link

Added patching font shadow size (with configuration) #3

Closed miuirussia closed 7 years ago

gamerforEA commented 7 years ago

Неплохо, но заменять всё, что FCONST_1 - не очень хорошая идея (достаточно добавить новые float константы в этот метод, чтобы всё сломать). Вместо этого стоит отслеживать вызов метода FontRenderer.renderString(String, float, float, int, boolean) и заменять 1.0F только в передаваемых аргументах.

miuirussia commented 7 years ago

Хм, а как найти, какие аргументы передаются? Там же к аргументам прибавляется 1.0F, а не в сам аргумент отправляется

gamerforEA commented 7 years ago
insn.add(new VarInsnNode(ALOAD, 0));
insn.add(new FieldInsnNode(GETFIELD, "net/minecraft/client/resources/Locale", unicode, "Z"));
insn.add(new MethodInsnNode(INVOKESTATIC, "com/gamerforea/clientfixer/asm/FatRussianFont", "isUnicode", "(Z)Z", false));
insn.add(new InsnNode(IRETURN));

Перед вызовом метода все аргументы помещаются в стек. Пример выше. (ALOAD, 0) - кладём в стек указатель this. (GETFIELD, "net/minecraft/client/resources/Locale", unicode, "Z") - обращаемся к последнему указателю в стеке (в данном случае это this), вызываем булево поле unicode и кладём его в стек. (INVOKESTATIC, "com/gamerforea/clientfixer/asm/FatRussianFont", "isUnicode", "(Z)Z", false) - вызываем метод FatRussianFont.isUnicode(boolean), при этом его аргументы заполняются последними значениями в стеке. Стоит обратить внимание, что если данные в стеке не помечаются как переменные, то при первом обращении к ним они удаляются из стека (именно поэтому первый указатель this исчезает при обращении к полю, значение которого потом тоже исчезает при вызове метода). P.S. Правда я всем этим давно интересовался, так что могу немного ошибаться, но в главном, думаю, не ошибаюсь.

miuirussia commented 7 years ago

Всё равно в данном случае получиться случае слишком сложная конструкция - нужно будет создавать стек и смотреть, что делается со значениями, потому что метод вызывается так: this.renderString(p_drawString1, p_drawString2 + 1.0F, p_drawString3 + 1.0F, p_drawString4, true); и можно заменить либо весь метод другим, либо извращаться с вычетанием в методе renderString

gamerforEA commented 7 years ago

Создавать стэк не надо. Надо просто смотреть на инструкции, которые его заполняют. Не спорю, это всё намного сложнее, чем просто заменить все FCONST_1, но при этом безопаснее. Уже были случаи, когда небольшие патчи ломали совместимость с некоторыми модами.

miuirussia commented 7 years ago

по хорошему, надо искать в методе такое: FLOAD 2 и FLOAD 3 FCONST_1 FADD и вот в таком виде заменять FCONST_1

gamerforEA commented 7 years ago

Да. Это уже намного лучше, хотя если кто-то добавит новую константу, то это работать не будет. Например: Было:

this.renderString(text, x + 1.0F, y + 1.0F, color, true);

Стало:

myMethod(text + 3.0F);
this.renderString(text, x + 1.0F, y + 1.0F, color, true);

В данном случае FCONST_1 - это 3.0F, а 1.0F - это FCONST_2.

miuirussia commented 7 years ago

Нет, стоп FCONST_1 это всегда 1.0F (т.е. = LDC 1.0) по спецификации: https://cs.au.dk/~mis/dOvs/jvmspec/ref--15.html и ошибка будет только, если кто-нибудь добавит такое, что скорее всего всё равно будет правильно:

myMethod(x + 1.0F, y + 1.0F); this.renderString(text, x + 1.0F, y + 1.0F, color, true);

gamerforEA commented 7 years ago

Посыпаю голову пеплом. Значит, ваше предпоследнее сообщение вполне подходит. Хотя я вижу ещё один вариант.

this.оченьВажныйМетод(x * y + 1.0F);
this.renderString(text, x + 1.0F, y + 1.0F, color, true);

То, что выше, рискует превратиться в то, что ниже, если толщину указать как 1.5 (а ведь нам нужно менять только вызов renderString):

this.оченьВажныйМетод(x * y + 1.5F);
this.renderString(text, x + 1.5F, y + 1.5F, color, true);

Этого очень важного метода нет в оригинальном коде, но если его кто-то добавит (допустим, OptiFine), то может получиться не очень хорошо.

miuirussia commented 7 years ago

Пока оставлю это тут, чтобы потом не искать, позже еще подумаю, как оптимально такое сделать:

ALOAD 0
ALOAD 1
FLOAD 2
FCONST_1
FADD
FLOAD 3
FCONST_1
FADD
ILOAD 4
ICONST_1
INVOKESPECIAL net/minecraft/client/gui/FontRenderer.renderString (Ljava/lang/String;FFIZ)I
miuirussia commented 7 years ago

Вот такое пока придумалось, если будут баги, можно будет еще что-нибудь придумать, но думаю никто не будет лезть в этот метод