Do not initialize a new world for wrapped worlds (#125)

This commit is contained in:
IzzelAliz 2021-01-16 19:13:42 +08:00
parent 3b0e2bd9bf
commit 793fddc227
2 changed files with 67 additions and 0 deletions

View File

@ -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<Field> 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());
}

View File

@ -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<Class<?>> RESULT = new HashSet<>();
private static final HashMap<Class<?>, Field> FIELD = new HashMap<>();
public static Optional<Field> 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<Field> delegate = getDelegate(cl);
if (delegate.isPresent()) {
return delegate.get();
} else {
ArclightMod.LOGGER.debug("{} delegates to nothing", cl);
return null;
}
});
}
}
private static Optional<Field> getOrCreate(Class<?> cl, Function<Class<?>, 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);
}
}
}