Forge 1.12.2 на Java 17

Версия Minecraft
1.12.2
API
Forge
437
41
112
Доброго времени суток, в общем мне взбрела в голову идея портировать forge на новые версии java. Сейчас смог добиться совместимости с java 11, но дальше пошли проблемы.

Суть проблемы: Спецефикации новой jav-ы ,,блокируют,, ,,окольные,, пути модификации доступа к полям

Например в java 11 в public static final net.minecraft.block.Block net.minecraft.init.Blocks.field_150350_a без проблем присваивается какое-то значение на этапе запуска майна, но на 16+ вылетает ошибка.

MinecraftForge/src/main/java/net/minecraftforge/registries/ObjectHolderRegistry.java at 1.12.x · MinecraftForge/MinecraftForge

MinecraftForge/src/main/java/net/minecraftforge/registries/ObjectHolderRef.java at 1.12.x · MinecraftForge/MinecraftForge (180 строка)

https://www.reddit.com/r/feedthebeast/comments/que3wq

Подскажите любой способ снять final с поля, который будет работать на java 17

(Оригинальная ошибка на всякий случай, их просто куча)
Java:
java.lang.IllegalAccessException: Can not set static final net.minecraft.block.Block field net.minecraft.init.Blocks.field_150481_bH to net.minecraft.block.BlockStairs
    at jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76) ~[?:?]
    at jdk.internal.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:80) ~[?:?]
    at jdk.internal.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77) ~[?:?]
    at java.lang.reflect.Field.set(Field.java:793) ~[?:?]
    at net.minecraftforge.registries.ObjectHolderRef$FinalFieldHelper.setField(ObjectHolderRef.java:143) ~[ObjectHolderRef$FinalFieldHelper.class:?]
    at net.minecraftforge.registries.ObjectHolderRef.apply(ObjectHolderRef.java:111) [ObjectHolderRef.class:?]
    at net.minecraftforge.registries.ObjectHolderRegistry.applyObjectHolders(ObjectHolderRegistry.java:134) [ObjectHolderRegistry.class:?]
    at net.minecraftforge.registries.GameData.fireRegistryEvents(GameData.java:846) [GameData.class:?]
    at net.minecraftforge.fml.common.Loader.preinitializeMods(Loader.java:630) [Loader.class:?]
    at net.minecraftforge.fml.client.FMLClientHandler.beginMinecraftLoading(FMLClientHandler.java:252) [FMLClientHandler.class:?]
    at net.minecraft.client.Minecraft.func_71384_a(Minecraft.java:467) [bib.class:?]
    at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:378) [bib.class:?]
    at net.minecraft.client.main.Main.main(SourceFile:123) [Main.class:?]
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) ~[?:?]
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:567) ~[?:?]
    at net.minecraft.launchwrapper.Launch.launch(Launch.java:107) [te4_forgepatch.jar:?]
    at net.minecraft.launchwrapper.Launch.main(Launch.java:26) [te4_forgepatch.jar:?]

(Как ни странно, если обернуть это в try-catch и тупо игнорировать исключения, майн запустится на java17 и даже поиграть можно, но в консоли будет лютый спам этими ошибками)
 
1,074
72
372
346
25
94
Подскажите любой способ снять final с поля, который будет работать на java 17
По сути таких нет. Используй Unsafe, на новых версиях у Forge даже специально для этого есть класс UnsafeHacks.
 
437
41
112
По сути таких нет. Используй Unsafe, на новых версиях у Forge даже специально для этого есть класс UnsafeHacks.
Не нашел в исходниках, можно точное имя класса (с пакетом) или ссылку?
 
346
25
94
Java:
/*
 * Minecraft Forge
 * Copyright (c) 2016-2019.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation version 2.1
 * of the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

package net.minecraftforge.fml.unsafe;

import java.lang.reflect.Field;
import java.util.Optional;

import sun.misc.Unsafe;

@SuppressWarnings("restriction")
public class UnsafeHacks
{
    private static final Unsafe UNSAFE;
    static
    {
        try
        {
            final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            UNSAFE = (Unsafe)theUnsafe.get(null);
        }
        catch (IllegalAccessException | NoSuchFieldException e)
        {
            throw new RuntimeException("BARF!", e);
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T newInstance(Class<T> clazz)
    {
        try
        {
            return (T) UNSAFE.allocateInstance(clazz);
        }
        catch (InstantiationException e)
        {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T getField(Field field, Object object)
    {
        final long l = UNSAFE.objectFieldOffset(field);
        return (T) UNSAFE.getObject(object, l);
    }

    public static void setField(Field data, Object object, Object value)
    {
        long offset = UNSAFE.objectFieldOffset(data);
        UNSAFE.putObject(object, offset, value);
    }

    public static int getIntField(Field f, Object obj)
    {
        long offset = UNSAFE.objectFieldOffset(f);
        return UNSAFE.getInt(obj, offset);
    }

    public static void setIntField(Field data, Object object, int value)
    {
        long offset = UNSAFE.objectFieldOffset(data);
        UNSAFE.putInt(object, offset, value);
    }
    
    // Make sure we don't crash if any future versions change field names
    private static Optional<Field> findField(Class<?> clazz, String name)
    {
        for (Field f : clazz.getDeclaredFields())
        {
            if (f.getName().equals(name))
            {
                return Optional.of(f);
            }
        }
        return Optional.empty();
    }

    public static void cleanEnumCache(Class<? extends Enum<?>> enumClass) throws Exception
    {
        findField(Class.class, "enumConstantDirectory").ifPresent(f -> setField(f, enumClass, null));
        findField(Class.class, "enumConstants").ifPresent(f -> setField(f, enumClass, null));
    }
}
 
437
41
112
Обычная модификация байт-кода, считай исходника, о чём JVM ничего не узнает.
Оба варианта - рабочие решения, (не знал что трансформеры работают на этом принципе) но все же думаю правильнее это реализовать через модификацию байт-кода, тк Unsafe использовать unsafe, дополнительные аргументы для jvm, и не понятно как будет работать на более высоких версиях java (20, 21 .. и 23 когда там выйдет)

Осталось только решить последнюю проблему - полную перезапись некоторых ванльных классов, которые жизненно не совместимы с java 17. До сих пор я использовал для этого NLaunch, но для ,,публичного и свободного использования всеми,, такое не подходит.

И вот что я заметил - некоторые классы (например) DimensionType (который необходимо перезаписать) перезаписываются без особых проблем, а например WorldGenerator или NetworkManager - ни в какую.

SSPatchLoader игнорирует входные данные и сразу возвращает ,,правильный,, байткод,, но по какой-то причине с (2 по 16 позиции) обратно перезаписывается неправильным (Proxy - это твикеры Mixin-ов). Может у кого есть идеи ,,где это происходит,, ?

1702931228505.png

UPD тут уже я рукожоп, тупо забыл указать все имена классов, которые необходимо загрузить из другого места
 
Последнее редактирование:
Сверху