z0z0z

SpongeVanilla

Jul 18th, 2019
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 16.21 KB | None | 0 0
  1. /*
  2.  * This file is part of Sponge, licensed under the MIT License (MIT).
  3.  *
  4.  * Copyright (c) SpongePowered <https://www.spongepowered.org>
  5.  * Copyright (c) contributors
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  8.  * of this software and associated documentation files (the "Software"), to deal
  9.  * in the Software without restriction, including without limitation the rights
  10.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11.  * copies of the Software, and to permit persons to whom the Software is
  12.  * furnished to do so, subject to the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice shall be included in
  15.  * all copies or substantial portions of the Software.
  16.  *
  17.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23.  * THE SOFTWARE.
  24.  */
  25. package org.spongepowered.server.mixin.core.server;
  26.  
  27. import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
  28. import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
  29. import it.unimi.dsi.fastutil.objects.ObjectIterator;
  30. import net.minecraft.crash.CrashReport;
  31. import net.minecraft.network.NetworkSystem;
  32. import net.minecraft.network.ServerStatusResponse;
  33. import net.minecraft.network.play.server.SPacketTimeUpdate;
  34. import net.minecraft.profiler.Profiler;
  35. import net.minecraft.profiler.Snooper;
  36. import net.minecraft.server.MinecraftServer;
  37. import net.minecraft.server.management.PlayerList;
  38. import net.minecraft.server.management.PlayerProfileCache;
  39. import net.minecraft.util.ITickable;
  40. import net.minecraft.util.ReportedException;
  41. import net.minecraft.util.Util;
  42. import net.minecraft.util.text.ITextComponent;
  43. import net.minecraft.util.text.TextComponentString;
  44. import net.minecraft.world.WorldServer;
  45. import org.apache.logging.log4j.Logger;
  46. import org.spongepowered.asm.mixin.Final;
  47. import org.spongepowered.asm.mixin.Mixin;
  48. import org.spongepowered.asm.mixin.Overwrite;
  49. import org.spongepowered.asm.mixin.Shadow;
  50. import org.spongepowered.asm.mixin.injection.At;
  51. import org.spongepowered.asm.mixin.injection.Inject;
  52. import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
  53. import org.spongepowered.common.SpongeImpl;
  54. import org.spongepowered.common.bridge.server.MinecraftServerBridge;
  55. import org.spongepowered.common.bridge.world.ServerWorldBridge;
  56. import org.spongepowered.common.bridge.world.ServerWorldBridge_AsyncLighting;
  57. import org.spongepowered.common.text.SpongeTexts;
  58. import org.spongepowered.common.world.WorldManager;
  59. import org.spongepowered.server.SpongeVanilla;
  60. import org.spongepowered.server.bridge.ChunkLoaderTickBridge;
  61.  
  62. import java.io.File;
  63. import java.text.SimpleDateFormat;
  64. import java.util.Date;
  65. import java.util.List;
  66. import java.util.Queue;
  67. import java.util.concurrent.ExecutorService;
  68. import java.util.concurrent.FutureTask;
  69. import java.util.concurrent.TimeUnit;
  70.  
  71. // SpongeCommon injects into updateTimeLightAndEntities, so we need to apply
  72. // our @Overwrite *before* SpongeCommon's mixin is applied, otherwise it will fail
  73. @Mixin(value = MinecraftServer.class, priority = 999)
  74. public abstract class MinecraftServerMixin_Vanilla implements MinecraftServerBridge, ChunkLoaderTickBridge {
  75.  
  76.     @Shadow @Final private static Logger LOGGER;
  77.     @Shadow @Final private Snooper usageSnooper;
  78.     @Shadow @Final private List<ITickable> tickables;
  79.     @Shadow @Final public Profiler profiler;
  80.     @Shadow private PlayerList playerList;
  81.     @Shadow private int tickCounter;
  82.     @Shadow @Final protected Queue<FutureTask<?>> futureTaskQueue;
  83.     @Shadow public WorldServer[] worlds;
  84.  
  85.     @Shadow public abstract boolean getAllowNether();
  86.     @Shadow public abstract NetworkSystem getNetworkSystem();
  87.     @Shadow public abstract void saveAllWorlds(boolean isSilent);
  88.     @Shadow public abstract PlayerProfileCache getPlayerProfileCache();
  89.  
  90.     @SuppressWarnings("NullableProblems") @com.google.inject.Inject private static SpongeVanilla vanilla$spongeVanilla;
  91.     private boolean vanilla$skipServerStop = false;
  92.  
  93.     private final Int2ObjectMap<long[]> vanilla$worldTickTimes = new Int2ObjectOpenHashMap<>(3);
  94.  
  95.     /**
  96.      * @author Minecrell
  97.      * @reason Sets the server brand name to 'sponge'
  98.      */
  99.     @Overwrite
  100.     public String getServerModName() {
  101.         return vanilla$spongeVanilla.getName();
  102.     }
  103.  
  104.     /**
  105.      * @author Minecrell
  106.      * @reason Logs chat messages with legacy color codes to show colored
  107.      *     messages in the console
  108.      */
  109.     @Overwrite
  110.     public void sendMessage(ITextComponent component) {
  111.         LOGGER.info(SpongeTexts.toLegacy(component));
  112.     }
  113.  
  114.     @Inject(method = "applyServerIconToResponse", at = @At("HEAD"), cancellable = true)
  115.     private void vanilla$onAddFaviconToStatusResponse(ServerStatusResponse response, CallbackInfo ci) {
  116.         // Don't load favicon twice
  117.         if (response.getFavicon() != null) {
  118.             ci.cancel();
  119.         }
  120.     }
  121.  
  122.     /**
  123.      * @author Zidane - Chris Sanders
  124.      * @reason need to save player stuff for sponge
  125.      */
  126.     @Overwrite
  127.     public void stopServer() {
  128.  
  129.         // stopServer is called from both the shutdown hook AND the finally statement in the main game loop, no reason to do this twice..
  130.         if (vanilla$skipServerStop) {
  131.             return;
  132.         }
  133.  
  134.         vanilla$skipServerStop = true;
  135.  
  136.         LOGGER.info("Stopping server");
  137.  
  138.         vanilla$spongeVanilla.onServerStopping();
  139.  
  140.         // Sponge Start - Force player profile cache save
  141.         this.getPlayerProfileCache().save();
  142.  
  143.         if (this.getNetworkSystem() != null) {
  144.             this.getNetworkSystem().terminateEndpoints();
  145.         }
  146.  
  147.         if (this.playerList != null) {
  148.             LOGGER.info("Saving players");
  149.             this.playerList.saveAllPlayerData();
  150.             this.playerList.removeAllPlayers();
  151.         }
  152.  
  153.         if (this.worlds != null) {
  154.             LOGGER.info("Saving worlds");
  155.  
  156.             for (WorldServer worldserver : this.worlds) {
  157.                 if (worldserver != null) {
  158.                     worldserver.disableLevelSaving = false;
  159.                 }
  160.             }
  161.  
  162.             this.saveAllWorlds(false);
  163.  
  164.             for (WorldServer worldserver1 : this.worlds) {
  165.                 if (worldserver1 != null) {
  166.                     // Turn off Async Lighting
  167.                     if (SpongeImpl.getGlobalConfigAdapter().getConfig().getModules().useOptimizations() &&
  168.                         SpongeImpl.getGlobalConfigAdapter().getConfig().getOptimizations().useAsyncLighting()) {
  169.                         final ExecutorService lightingExecutor =
  170.                             ((ServerWorldBridge_AsyncLighting) worldserver1).asyncLightingBridge$getLightingExecutor();
  171.                         lightingExecutor.shutdown();
  172.  
  173.                         try {
  174.                             lightingExecutor.awaitTermination(1, TimeUnit.SECONDS);
  175.                         } catch (InterruptedException e) {
  176.                             e.printStackTrace();
  177.                         } finally {
  178.                             lightingExecutor.shutdownNow();
  179.                         }
  180.                     }
  181.  
  182.                     WorldManager.unloadWorld(worldserver1, false, true);
  183.                 }
  184.             }
  185.  
  186.             if (this.usageSnooper.isSnooperRunning()) {
  187.                 this.usageSnooper.stopSnooper();
  188.             }
  189.         }
  190.     }
  191.  
  192.     @Override
  193.     public long[] bridge$getWorldTickTimes(int dimensionId) {
  194.         return this.vanilla$worldTickTimes.get(dimensionId);
  195.     }
  196.  
  197.     @Override
  198.     public void bridge$putWorldTickTimes(int dimensionId, long[] tickTimes) {
  199.         this.vanilla$worldTickTimes.put(dimensionId, tickTimes);
  200.     }
  201.  
  202.     @Override
  203.     public void bridge$removeWorldTickTimes(int dimensionId) {
  204.         this.vanilla$worldTickTimes.remove(dimensionId);
  205.     }
  206.  
  207.     /**
  208.      * @author Zidane
  209.      * @reason Handles ticking the additional worlds loaded by Sponge.
  210.      */
  211.     @Overwrite
  212.     public void updateTimeLightAndEntities() {
  213.         this.profiler.startSection("jobs");
  214.  
  215.         synchronized (this.futureTaskQueue) {
  216.             while (!this.futureTaskQueue.isEmpty()) {
  217.                 Util.runTask(this.futureTaskQueue.poll(), LOGGER);
  218.             }
  219.         }
  220.  
  221.         this.profiler.endStartSection("levels");
  222.         chunkIO$tickChunkLoader(); // Sponge: Tick chunk loader
  223.  
  224.         // Sponge start - Iterate over all our dimensions
  225.         for (final ObjectIterator<Int2ObjectMap.Entry<WorldServer>> it = WorldManager.worldsIterator(); it.hasNext();) {
  226.             Int2ObjectMap.Entry<WorldServer> entry = it.next();
  227.             final WorldServer worldServer = entry.getValue();
  228.             // Sponge end
  229.             long i = System.nanoTime();
  230.  
  231.             if (entry.getIntKey() == 0 || this.getAllowNether()) {
  232.  
  233.                 // Sponge start - copy from SpongeCommon MinecraftServerMixin_Vanilla
  234.                 ServerWorldBridge spongeWorld = (ServerWorldBridge) worldServer;
  235.                 if (spongeWorld.bridge$getChunkGCTickInterval() > 0) {
  236.                     spongeWorld.bridge$doChunkGC();
  237.                 }
  238.                 // Sponge end
  239.  
  240.                 this.profiler.startSection(worldServer.getWorldInfo().getWorldName());
  241.  
  242.                 if (this.tickCounter % 20 == 0) {
  243.                     this.profiler.startSection("timeSync");
  244.                     this.playerList.sendPacketToAllPlayersInDimension (
  245.                             new SPacketTimeUpdate(worldServer.getTotalWorldTime(), worldServer.getWorldTime(),
  246.                                     worldServer.getGameRules().getBoolean("doDaylightCycle")), ((ServerWorldBridge) worldServer).bridge$getDimensionId());
  247.                     this.profiler.endSection();
  248.                 }
  249.  
  250.                 this.profiler.startSection("tick");
  251.  
  252.                 try {
  253.                     worldServer.tick();
  254.                 } catch (Throwable throwable1) {
  255.                     CrashReport crashreport = CrashReport.makeCrashReport(throwable1, "Exception ticking world");
  256.                     worldServer.addWorldInfoToCrashReport(crashreport);
  257.                     throw new ReportedException(crashreport);
  258.                 }
  259.  
  260.                 try {
  261.                     worldServer.updateEntities();
  262.                 } catch (Throwable throwable) {
  263.                     CrashReport crashreport1 = CrashReport.makeCrashReport(throwable, "Exception ticking world entities");
  264.                     worldServer.addWorldInfoToCrashReport(crashreport1);
  265.                     throw new ReportedException(crashreport1);
  266.                 }
  267.  
  268.                 this.profiler.endSection();
  269.                 this.profiler.startSection("tracker");
  270.  
  271.                 // Sponge start - copy from SpongeCommon MinecraftServerMixin_Vanilla
  272.                 if (spongeWorld.bridge$getChunkGCTickInterval() > 0) {
  273.                     worldServer.getChunkProvider().tick();
  274.                 }
  275.                 // Sponge end
  276.  
  277.                 worldServer.getEntityTracker().tick();
  278.                 this.profiler.endSection();
  279.                 this.profiler.endSection();
  280.             }
  281.  
  282.             // Sponge start - Write tick times to our custom map
  283.             this.vanilla$worldTickTimes.get(entry.getIntKey())[this.tickCounter % 100] = System.nanoTime() - i;
  284.             // Sponge end
  285.         }
  286.  
  287.         // Sponge start - Unload requested worlds
  288.         this.profiler.endStartSection("dim_unloading");
  289.         WorldManager.unloadQueuedWorlds();
  290.         // Sponge end
  291.  
  292.         this.profiler.endStartSection("connection");
  293.         this.getNetworkSystem().networkTick();
  294.         this.profiler.endStartSection("players");
  295.         this.playerList.onTick();
  296.         this.profiler.endStartSection("tickables");
  297.  
  298.         for (int k = 0; k < this.tickables.size(); ++k) {
  299.             this.tickables.get(k).update();
  300.         }
  301.  
  302.         this.profiler.endSection();
  303.     }
  304.  
  305.     // This is used by asynchronous chunk loading to finish loading the chunks
  306.     public void chunkIO$tickChunkLoader() {
  307.     }
  308.     @Shadow public abstract boolean init();
  309.     @Shadow private long currentTime = getCurrentTimeMillis();
  310.     @Shadow public static long getCurrentTimeMillis();
  311.     @Shadow private final ServerStatusResponse statusResponse = new ServerStatusResponse();
  312.     @Shadow public abstract void applyServerIconToResponse(ServerStatusResponse statusResponse2);
  313.     @Shadow private String motd;
  314.     @Shadow public abstract boolean isServerRunning();
  315.     @Shadow private boolean serverRunning = true;
  316.     @Shadow private long timeOfLastWarning;
  317.     @Shadow protected abstract void tick();
  318.     @Shadow protected abstract void finalTick(CrashReport crashReport);
  319.     @Shadow public abstract CrashReport addServerInfoToCrashReport(CrashReport crashReport);
  320.     @Shadow public abstract File getDataDirectory();
  321.     @Shadow private boolean serverStopped;
  322.     @Shadow public abstract void systemExitNow();
  323.    
  324.     @Overwrite
  325.     public void run()
  326.     {
  327.         try
  328.         {
  329.             if (this.init())
  330.             {
  331.                 this.currentTime = getCurrentTimeMillis();
  332.                 long i = 0L;
  333.                 this.statusResponse.setServerDescription(new TextComponentString(this.motd));
  334.                 this.statusResponse.setVersion(new ServerStatusResponse.Version("1.12.2", 340));
  335.                 this.applyServerIconToResponse(this.statusResponse);
  336.  
  337.                 while (this.serverRunning)
  338.                 {
  339.                     long k = getCurrentTimeMillis();
  340.                     long j = k - this.currentTime;
  341.  
  342.                     if (j > 2000L && this.currentTime - this.timeOfLastWarning >= 15000L)
  343.                     {
  344.                         LOGGER.warn("Can't keep up! Did the system time change, or is the server overloaded? Running {}ms behind, skipping {} tick(s)", Long.valueOf(j), Long.valueOf(j / 50L));
  345.                         j = 2000L;
  346.                         this.timeOfLastWarning = this.currentTime;
  347.                     }
  348.  
  349.                     if (j < 0L)
  350.                     {
  351.                         LOGGER.warn("Time ran backwards! Did the system time change?");
  352.                         j = 0L;
  353.                     }
  354.  
  355.                     i += j;
  356.                     this.currentTime = k;
  357.  
  358.                     this.tick();
  359.                 }
  360.             }
  361.             else
  362.             {
  363.                 this.finalTick((CrashReport)null);
  364.             }
  365.         }
  366.         catch (Throwable throwable1)
  367.         {
  368.             LOGGER.error("Encountered an unexpected exception", throwable1);
  369.             CrashReport crashreport = null;
  370.  
  371.             if (throwable1 instanceof ReportedException)
  372.             {
  373.                 crashreport = this.addServerInfoToCrashReport(((ReportedException)throwable1).getCrashReport());
  374.             }
  375.             else
  376.             {
  377.                 crashreport = this.addServerInfoToCrashReport(new CrashReport("Exception in server tick loop", throwable1));
  378.             }
  379.  
  380.             File file1 = new File(new File(this.getDataDirectory(), "crash-reports"), "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-server.txt");
  381.  
  382.             if (crashreport.saveToFile(file1))
  383.             {
  384.                 LOGGER.error("This crash report has been saved to: {}", (Object)file1.getAbsolutePath());
  385.             }
  386.             else
  387.             {
  388.                 LOGGER.error("We were unable to save this crash report to disk.");
  389.             }
  390.  
  391.             this.finalTick(crashreport);
  392.         }
  393.         finally
  394.         {
  395.             try
  396.             {
  397.                 this.serverStopped = true;
  398.                 this.stopServer();
  399.             }
  400.             catch (Throwable throwable)
  401.             {
  402.                 LOGGER.error("Exception stopping the server", throwable);
  403.             }
  404.             finally
  405.             {
  406.                 this.systemExitNow();
  407.             }
  408.         }
  409.     }
  410.  
  411. }
Advertisement
Add Comment
Please, Sign In to add comment