Fix 1.14 NoSuchMethodError. Dramatically improved multi world plugin compatibility. (#14)
This commit is contained in:
parent
aff33be4ce
commit
6507484079
|
@ -9,9 +9,11 @@ import com.mojang.datafixers.DataFixer;
|
|||
import io.izzel.arclight.common.bridge.command.ICommandSourceBridge;
|
||||
import io.izzel.arclight.common.bridge.server.MinecraftServerBridge;
|
||||
import io.izzel.arclight.common.bridge.world.WorldBridge;
|
||||
import io.izzel.arclight.common.bridge.world.dimension.DimensionTypeBridge;
|
||||
import io.izzel.arclight.common.mod.ArclightConstants;
|
||||
import io.izzel.arclight.common.mod.server.BukkitRegistry;
|
||||
import io.izzel.arclight.common.mod.util.BukkitOptionParser;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import net.minecraft.command.CommandSource;
|
||||
|
@ -23,15 +25,24 @@ import net.minecraft.profiler.DebugProfiler;
|
|||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.management.PlayerProfileCache;
|
||||
import net.minecraft.util.SharedConstants;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.util.concurrent.RecursiveEventLoop;
|
||||
import net.minecraft.util.concurrent.TickDelayedTask;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
import net.minecraft.util.text.TranslationTextComponent;
|
||||
import net.minecraft.world.ForcedChunksSaveData;
|
||||
import net.minecraft.world.WorldSettings;
|
||||
import net.minecraft.world.WorldType;
|
||||
import net.minecraft.world.chunk.listener.IChunkStatusListener;
|
||||
import net.minecraft.world.chunk.listener.IChunkStatusListenerFactory;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import net.minecraft.world.server.ServerChunkProvider;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraft.world.server.TicketType;
|
||||
import net.minecraft.world.storage.SaveHandler;
|
||||
import net.minecraft.world.storage.WorldInfo;
|
||||
import net.minecraftforge.fml.StartupQuery;
|
||||
|
@ -53,6 +64,7 @@ import org.spongepowered.asm.mixin.Shadow;
|
|||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -94,12 +106,16 @@ public abstract class MinecraftServerMixin extends RecursiveEventLoop<TickDelaye
|
|||
@Shadow protected abstract void stopServer();
|
||||
@Shadow protected abstract void systemExitNow();
|
||||
@Shadow public abstract Commands getCommandManager();
|
||||
@Shadow protected abstract void applyDebugWorldInfo(WorldInfo worldInfoIn);
|
||||
@Shadow protected abstract void setUserMessage(ITextComponent userMessageIn);
|
||||
@Shadow public abstract ServerWorld getWorld(DimensionType dimension);
|
||||
// @formatter:on
|
||||
|
||||
public MinecraftServerMixin(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
private boolean forceTicks;
|
||||
public CraftServer server;
|
||||
public OptionSet options;
|
||||
public ConsoleCommandSender console;
|
||||
|
@ -199,7 +215,7 @@ public abstract class MinecraftServerMixin extends RecursiveEventLoop<TickDelaye
|
|||
ServerLifecycleHooks.expectServerStopped(); // has to come before finalTick to avoid race conditions
|
||||
} else {
|
||||
ServerLifecycleHooks.expectServerStopped(); // has to come before finalTick to avoid race conditions
|
||||
this.finalTick((CrashReport) null);
|
||||
this.finalTick(null);
|
||||
}
|
||||
} catch (StartupQuery.AbortedException e) {
|
||||
// ignore silently
|
||||
|
@ -215,7 +231,7 @@ public abstract class MinecraftServerMixin extends RecursiveEventLoop<TickDelaye
|
|||
|
||||
File file1 = new File(new File(this.getDataDirectory(), "crash-reports"), "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-server.txt");
|
||||
if (crashreport.saveToFile(file1)) {
|
||||
LOGGER.error("This crash report has been saved to: {}", (Object) file1.getAbsolutePath());
|
||||
LOGGER.error("This crash report has been saved to: {}", file1.getAbsolutePath());
|
||||
} else {
|
||||
LOGGER.error("We were unable to save this crash report to disk.");
|
||||
}
|
||||
|
@ -265,17 +281,90 @@ public abstract class MinecraftServerMixin extends RecursiveEventLoop<TickDelaye
|
|||
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
|
||||
}
|
||||
|
||||
@Inject(method = "loadWorlds", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/server/MinecraftServer;func_213204_a(Lnet/minecraft/world/storage/DimensionSavedDataManager;)V"))
|
||||
private void arclight$worldInit(SaveHandler p_213194_1_, WorldInfo info, WorldSettings p_213194_3_, IChunkStatusListener p_213194_4_, CallbackInfo ci, ServerWorld serverWorld) {
|
||||
if (((CraftServer) Bukkit.getServer()).scoreboardManager == null) {
|
||||
((CraftServer) Bukkit.getServer()).scoreboardManager = new CraftScoreboardManager((MinecraftServer) (Object) this, serverWorld.getScoreboard());
|
||||
}
|
||||
Bukkit.getPluginManager().callEvent(new WorldInitEvent(((WorldBridge) serverWorld).bridge$getWorld()));
|
||||
public void initWorld(ServerWorld serverWorld, WorldInfo worldInfo, WorldSettings worldSettings) {
|
||||
serverWorld.getWorldBorder().copyFrom(worldInfo);
|
||||
if (((WorldBridge) serverWorld).bridge$getGenerator() != null) {
|
||||
((WorldBridge) serverWorld).bridge$getWorld().getPopulators().addAll(
|
||||
((WorldBridge) serverWorld).bridge$getGenerator().getDefaultPopulators(
|
||||
((WorldBridge) serverWorld).bridge$getWorld()));
|
||||
}
|
||||
if (!worldInfo.isInitialized()) {
|
||||
try {
|
||||
serverWorld.createSpawnPosition(worldSettings);
|
||||
if (worldInfo.getGenerator() == WorldType.DEBUG_ALL_BLOCK_STATES) {
|
||||
this.applyDebugWorldInfo(worldInfo);
|
||||
}
|
||||
worldInfo.setInitialized(true);
|
||||
} catch (Throwable throwable) {
|
||||
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Exception initializing level");
|
||||
try {
|
||||
serverWorld.fillCrashReport(crashreport);
|
||||
} catch (Throwable ignored) {}
|
||||
throw new ReportedException(crashreport);
|
||||
}
|
||||
worldInfo.setInitialized(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadSpawn(IChunkStatusListener listener, ServerWorld serverWorld) {
|
||||
if (!((WorldBridge) serverWorld).bridge$getWorld().getKeepSpawnInMemory()) {
|
||||
return;
|
||||
}
|
||||
this.setUserMessage(new TranslationTextComponent("menu.generatingTerrain"));
|
||||
this.forceTicks = true;
|
||||
LOGGER.info("Preparing start region for dimension '{}'/{}", serverWorld.getWorldInfo().getWorldName(), DimensionType.getKey(((DimensionTypeBridge) serverWorld.dimension.getType()).bridge$getType()));
|
||||
BlockPos pos = serverWorld.getSpawnPoint();
|
||||
listener.start(new ChunkPos(pos));
|
||||
ServerChunkProvider chunkProvider = serverWorld.getChunkProvider();
|
||||
chunkProvider.getLightManager().func_215598_a(500);
|
||||
this.serverTime = Util.milliTime();
|
||||
chunkProvider.registerTicket(TicketType.START, new ChunkPos(pos), 11, Unit.INSTANCE);
|
||||
while (chunkProvider.getLoadedChunksCount() != 441) {
|
||||
this.executeModerately();
|
||||
}
|
||||
this.executeModerately();
|
||||
DimensionType type = serverWorld.dimension.getType();
|
||||
ForcedChunksSaveData chunks = serverWorld.getSavedData().get(ForcedChunksSaveData::new, "chunks");
|
||||
if (chunks != null) {
|
||||
ServerWorld world = this.getWorld(type);
|
||||
LongIterator iterator = chunks.getChunks().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
long i = iterator.nextLong();
|
||||
ChunkPos chunkPos = new ChunkPos(i);
|
||||
world.getChunkProvider().forceChunk(chunkPos, true);
|
||||
}
|
||||
}
|
||||
this.executeModerately();
|
||||
listener.stop();
|
||||
chunkProvider.getLightManager().func_215598_a(5);
|
||||
this.forceTicks = false;
|
||||
}
|
||||
|
||||
private void executeModerately() {
|
||||
this.drainTasks();
|
||||
java.util.concurrent.locks.LockSupport.parkNanos("executing tasks", 1000L);
|
||||
}
|
||||
|
||||
@Inject(method = "isAheadOfTime", cancellable = true, at = @At("HEAD"))
|
||||
private void arclight$forceAheadOfTime(CallbackInfoReturnable<Boolean> cir) {
|
||||
if (this.forceTicks) cir.setReturnValue(true);
|
||||
}
|
||||
|
||||
@Inject(method = "loadWorlds", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", shift = At.Shift.AFTER, target = "Lnet/minecraft/server/MinecraftServer;func_213204_a(Lnet/minecraft/world/storage/DimensionSavedDataManager;)V"))
|
||||
private void arclight$worldInit(SaveHandler p_213194_1_, WorldInfo info, WorldSettings p_213194_3_, IChunkStatusListener p_213194_4_, CallbackInfo ci, ServerWorld serverWorld) {
|
||||
if (((CraftServer) Bukkit.getServer()).scoreboardManager == null) {
|
||||
((CraftServer) Bukkit.getServer()).scoreboardManager = new CraftScoreboardManager((MinecraftServer) (Object) this, serverWorld.getScoreboard());
|
||||
}
|
||||
if (((WorldBridge) serverWorld).bridge$getGenerator() != null) {
|
||||
((WorldBridge) serverWorld).bridge$getWorld().getPopulators().addAll(
|
||||
((WorldBridge) serverWorld).bridge$getGenerator().getDefaultPopulators(
|
||||
((WorldBridge) serverWorld).bridge$getWorld()));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "loadWorlds", locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", target = "Lnet/minecraft/server/management/PlayerList;func_212504_a(Lnet/minecraft/world/server/ServerWorld;)V"))
|
||||
private void arclight$initEvent(SaveHandler saveHandlerIn, WorldInfo info, WorldSettings worldSettingsIn, IChunkStatusListener chunkStatusListenerIn, CallbackInfo ci, ServerWorld serverWorld) {
|
||||
Bukkit.getPluginManager().callEvent(new WorldInitEvent(((WorldBridge) serverWorld).bridge$getWorld()));
|
||||
}
|
||||
|
||||
@Inject(method = "updateTimeLightAndEntities", at = @At("HEAD"))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.izzel.arclight.common.mixin.core.world;
|
||||
|
||||
import io.izzel.arclight.api.ArclightVersion;
|
||||
import io.izzel.arclight.common.bridge.world.WorldBridge;
|
||||
import io.izzel.arclight.common.bridge.world.border.WorldBorderBridge;
|
||||
import io.izzel.arclight.common.mod.util.ArclightCaptures;
|
||||
|
@ -76,8 +77,13 @@ public abstract class WorldMixin implements WorldBridge {
|
|||
((WorldBorderBridge) this.worldBorder).bridge$setWorld((ServerWorld) (Object) this);
|
||||
this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns();
|
||||
this.ticksPerMonsterSpawns = this.getServer().getTicksPerMonsterSpawns();
|
||||
this.ticksPerWaterSpawns = this.getServer().getTicksPerWaterSpawns();
|
||||
this.ticksPerAmbientSpawns = this.getServer().getTicksPerAmbientSpawns();
|
||||
if (ArclightVersion.atLeast(ArclightVersion.v1_15)) {
|
||||
this.ticksPerWaterSpawns = this.getServer().getTicksPerWaterSpawns();
|
||||
this.ticksPerAmbientSpawns = this.getServer().getTicksPerAmbientSpawns();
|
||||
} else {
|
||||
this.ticksPerWaterSpawns = 1;
|
||||
this.ticksPerAmbientSpawns = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -200,7 +206,7 @@ public abstract class WorldMixin implements WorldBridge {
|
|||
|
||||
@Override
|
||||
public CraftWorld bridge$getWorld() {
|
||||
return this.world;
|
||||
return this.getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -92,7 +92,7 @@ public abstract class ServerWorldMixin extends WorldMixin implements ServerWorld
|
|||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
public void arclight$constructor(MinecraftServer serverIn, Executor executor, SaveHandler saveHandler, WorldInfo worldInfo, DimensionType dimType, IProfiler profiler, IChunkStatusListener listener, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env) {
|
||||
public void arclight$constructor(MinecraftServer serverIn, Executor executor, SaveHandler saveHandler, WorldInfo worldInfo, DimensionType dimType, IProfiler profiler, IChunkStatusListener listener, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen) {
|
||||
arclight$constructor(serverIn, executor, saveHandler, worldInfo, dimType, profiler, listener);
|
||||
this.generator = gen;
|
||||
this.environment = env;
|
||||
|
|
|
@ -6,6 +6,9 @@ import net.minecraft.world.biome.IBiomeMagnifier;
|
|||
import net.minecraft.world.dimension.Dimension;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
|
@ -36,4 +39,11 @@ public class DimensionTypeMixin_1_15 implements DimensionTypeBridge {
|
|||
public DimensionType bridge$getType() {
|
||||
return getType();
|
||||
}
|
||||
|
||||
@Inject(method = "isVanilla", remap = false, cancellable = true, at = @At("HEAD"))
|
||||
private void arclight$vanillaCheck(CallbackInfoReturnable<Boolean> cir) {
|
||||
if (this.type != null) {
|
||||
cir.setReturnValue(this.type.isVanilla());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ public class BukkitRegistry {
|
|||
private static void loadEntities() {
|
||||
int origin = EntityType.values().length;
|
||||
int i = origin;
|
||||
List<EntityType> newTypes = new ArrayList<>(ForgeRegistries.ENTITIES.getEntries().size() - origin);
|
||||
List<EntityType> newTypes = new ArrayList<>(ForgeRegistries.ENTITIES.getEntries().size() - origin + 1); // UNKNOWN
|
||||
for (Map.Entry<ResourceLocation, net.minecraft.entity.EntityType<?>> entry : ForgeRegistries.ENTITIES.getEntries()) {
|
||||
ResourceLocation location = entry.getKey();
|
||||
net.minecraft.entity.EntityType<?> type = entry.getValue();
|
||||
|
|
|
@ -5,6 +5,9 @@ import net.minecraft.world.World;
|
|||
import net.minecraft.world.dimension.Dimension;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
|
@ -35,4 +38,11 @@ public class DimensionTypeMixin_1_14 implements DimensionTypeBridge {
|
|||
public DimensionType bridge$getType() {
|
||||
return getType();
|
||||
}
|
||||
|
||||
@Inject(method = "isVanilla", remap = false, cancellable = true, at = @At("HEAD"))
|
||||
private void arclight$vanillaCheck(CallbackInfoReturnable<Boolean> cir) {
|
||||
if (this.type != null) {
|
||||
cir.setReturnValue(this.type.isVanilla());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user