diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/WorldMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/WorldMixin.java index fcef32b3..743784f3 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/WorldMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/WorldMixin.java @@ -4,6 +4,7 @@ import io.izzel.arclight.common.bridge.world.WorldBridge; import io.izzel.arclight.common.bridge.world.border.WorldBorderBridge; import io.izzel.arclight.common.mod.ArclightMod; import io.izzel.arclight.common.mod.server.ArclightServer; +import io.izzel.arclight.common.mod.server.world.WrappedWorlds; import io.izzel.arclight.common.mod.util.ArclightCaptures; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -43,6 +44,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import javax.annotation.Nullable; +import java.lang.reflect.Field; +import java.util.Optional; import java.util.function.Supplier; @Mixin(World.class) @@ -193,6 +196,14 @@ public abstract class WorldMixin implements WorldBridge { public CraftWorld getWorld() { if (this.world == null) { + Optional delegate = WrappedWorlds.getDelegate(this.getClass()); + if (delegate.isPresent()) { + try { + return ((WorldBridge) delegate.get().get(this)).bridge$getWorld(); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } if (generator == null) { generator = getServer().getGenerator(((IServerWorldInfo) this.getWorldInfo()).getWorldName()); } diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/server/world/WrappedWorlds.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/server/world/WrappedWorlds.java new file mode 100644 index 00000000..aad6b864 --- /dev/null +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/server/world/WrappedWorlds.java @@ -0,0 +1,56 @@ +package io.izzel.arclight.common.mod.server.world; + +import io.izzel.arclight.common.mod.ArclightMod; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Optional; +import java.util.function.Function; + +public class WrappedWorlds { + + private static final HashSet> RESULT = new HashSet<>(); + private static final HashMap, Field> FIELD = new HashMap<>(); + + public static Optional getDelegate(Class cl) { + if (cl.equals(ServerWorld.class)) { + return Optional.empty(); + } else { + return getOrCreate(cl, key -> { + for (Field f : cl.getDeclaredFields()) { + if (World.class.isAssignableFrom(f.getType())) { + ArclightMod.LOGGER.debug("{} delegates to field {}", cl, f.getName()); + f.setAccessible(true); + return f; + } + } + Optional delegate = getDelegate(cl); + if (delegate.isPresent()) { + return delegate.get(); + } else { + ArclightMod.LOGGER.debug("{} delegates to nothing", cl); + return null; + } + }); + } + } + + private static Optional getOrCreate(Class cl, Function, Field> function) { + Field field = FIELD.get(cl); + if (field != null) { + return Optional.of(field); + } else if (RESULT.contains(cl)) { + return Optional.empty(); + } else { + Field delegate = function.apply(cl); + RESULT.add(cl); + if (delegate != null) { + FIELD.put(cl, delegate); + } + return Optional.ofNullable(delegate); + } + } +}