diff --git a/dependencies.gradle b/dependencies.gradle index 6ae98c64..f180087e 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -12,21 +12,21 @@ configurations { } dependencies { - api("com.github.GTNewHorizons:GTNHLib:0.6.0:dev") + api("com.github.GTNewHorizons:GTNHLib:0.6.1:dev") compileOnly("com.gtnewhorizons.retrofuturabootstrap:RetroFuturaBootstrap:1.0.2") { transitive = false } - transformedMod("com.github.GTNewHorizons:NotEnoughItems:2.7.11-GTNH:dev") // force a more up-to-date NEI version - transformedModCompileOnly("com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-516-GTNH") + transformedMod("com.github.GTNewHorizons:NotEnoughItems:2.7.15-GTNH:dev") // force a more up-to-date NEI version + transformedModCompileOnly("com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta-518-GTNH") transformedModCompileOnly("com.github.GTNewHorizons:Baubles:1.0.4:dev") // Transitive updates to make runClient17 work transformedModCompileOnly("com.github.GTNewHorizons:ForgeMultipart:1.6.0:dev") - transformedModCompileOnly("com.github.GTNewHorizons:GT5-Unofficial:5.09.51.48:dev") + transformedModCompileOnly("com.github.GTNewHorizons:GT5-Unofficial:5.09.51.61:dev") transformedModCompileOnly("com.github.GTNewHorizons:harvestcraft:1.2.3-GTNH:dev") transformedModCompileOnly("com.github.GTNewHorizons:HungerOverhaul:1.1.0-GTNH:dev") - transformedModCompileOnly("com.github.GTNewHorizons:MrTJPCore:1.2.1:dev") // Do not update, fixed afterwards - transformedModCompileOnly("com.github.GTNewHorizons:Railcraft:9.16.1:dev") { exclude group: "thaumcraft", module: "Thaumcraft" } - transformedModCompileOnly("com.github.GTNewHorizons:TinkersConstruct:1.13.2-GTNH:dev") + transformedModCompileOnly("com.github.GTNewHorizons:MrTJPCore:1.3.0:dev") // Do not update, fixed afterwards + transformedModCompileOnly("com.github.GTNewHorizons:Railcraft:9.16.2:dev") { exclude group: "thaumcraft", module: "Thaumcraft" } + transformedModCompileOnly("com.github.GTNewHorizons:TinkersConstruct:1.13.3-GTNH:dev") transformedModCompileOnly(rfg.deobf("curse.maven:bibliocraft-228027:2423369")) transformedModCompileOnly(rfg.deobf("curse.maven:biomes-o-plenty-220318:2499612")) transformedModCompileOnly("curse.maven:cofh-core-69162:2388751") @@ -45,7 +45,7 @@ dependencies { transformedModCompileOnly(rfg.deobf("curse.maven:glibys-voice-chat-225110:2301492")) transformedModCompileOnly(rfg.deobf("curse.maven:automagy-222153:2285272")) - transformedModCompileOnly("com.github.GTNewHorizons:Galacticraft:3.3.0-GTNH:dev") + transformedModCompileOnly("com.github.GTNewHorizons:Galacticraft:3.3.1-GTNH:dev") transformedModCompileOnly("curse.maven:minechem-368422:2905830") transformedModCompileOnly("curse.maven:thermal-dynamics-227443:2388756") transformedModCompileOnly("curse.maven:thermal-expansion-69163:2388759") @@ -61,7 +61,7 @@ dependencies { transformedModCompileOnly(deobf("https://forum.industrial-craft.net/core/attachment/4316-advancedsolarpanel-1-7-10-3-5-1-jar/")) transformedModCompileOnly(rfg.deobf("curse.maven:candycraft-251118:2330488")) - devOnlyNonPublishable(deobf("https://github.com/makamys/CoreTweaks/releases/download/0.3.3.2/CoreTweaks-1.7.10-0.3.3.2+nomixin.jar")) + transformedModCompileOnly(deobf("https://github.com/makamys/CoreTweaks/releases/download/0.3.3.2/CoreTweaks-1.7.10-0.3.3.2+nomixin.jar")) } // Replace when RFG support deobfuscation from notch mappings diff --git a/src/main/java/com/mitchej123/hodgepodge/commands/DebugCommand.java b/src/main/java/com/mitchej123/hodgepodge/commands/DebugCommand.java index c7dc3165..b2e18f10 100644 --- a/src/main/java/com/mitchej123/hodgepodge/commands/DebugCommand.java +++ b/src/main/java/com/mitchej123/hodgepodge/commands/DebugCommand.java @@ -15,6 +15,8 @@ import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.math.NumberUtils; +import com.mitchej123.hodgepodge.config.TweaksConfig; +import com.mitchej123.hodgepodge.mixins.interfaces.IPauseWhenEmpty; import com.mitchej123.hodgepodge.util.AnchorAlarm; public class DebugCommand extends CommandBase { @@ -26,11 +28,11 @@ public String getCommandName() { @Override public String getCommandUsage(ICommandSender sender) { - return "Usage: hp . Valid subcommands are: toggle, anchor, randomNbt."; + return "Usage: hp . Valid subcommands are: toggle, anchor, randomNbt, pauseWhenEmpty."; } private void printHelp(ICommandSender sender) { - sender.addChatMessage(new ChatComponentText("Usage: hp ")); + sender.addChatMessage(new ChatComponentText("Usage: hp ")); sender.addChatMessage(new ChatComponentText("\"toggle anchordebug\" - toggles RC anchor debugging")); sender.addChatMessage( new ChatComponentText( @@ -38,16 +40,19 @@ private void printHelp(ICommandSender sender) { sender.addChatMessage( new ChatComponentText( "\"randomNbt [bytes]\" - adds a random byte array of the given size to the held item")); + sender.addChatMessage( + new ChatComponentText( + "\"pauseWhenEmpty [seconds]\" - sets the time the server will wait before pausing when no players are online; 0 to disable")); } @Override public List addTabCompletionOptions(ICommandSender sender, String[] ss) { List l = new ArrayList<>(); String test = ss.length == 0 ? "" : ss[0].trim(); - if (ss.length == 0 || ss.length == 1 - && (test.isEmpty() || Stream.of("toggle", "anchor", "randomNbt").anyMatch(s -> s.startsWith(test)))) { - Stream.of("toggle", "anchor", "randomNbt").filter(s -> test.isEmpty() || s.startsWith(test)) - .forEach(l::add); + if (ss.length == 0 || ss.length == 1 && (test.isEmpty() + || Stream.of("toggle", "anchor", "randomNbt", "pauseWhenEmpty").anyMatch(s -> s.startsWith(test)))) { + Stream.of("toggle", "anchor", "randomNbt", "pauseWhenEmpty") + .filter(s -> test.isEmpty() || s.startsWith(test)).forEach(l::add); } else if (test.equals("toggle")) { String test1 = ss[1].trim(); if (test1.isEmpty() || "anchordebug".startsWith(test1)) l.add("anchordebug"); @@ -112,6 +117,38 @@ public void processCommand(ICommandSender sender, String[] strings) { stack.stackTagCompound.setByteArray("DebugJunk", randomData); player.inventory.inventoryChanged = true; player.inventoryContainer.detectAndSendChanges(); + break; + case "pauseWhenEmpty": + if (!TweaksConfig.pauseWhenEmpty) { + sender.addChatMessage(new ChatComponentText("'pauseWhenEmpty' config option is disabled")); + return; + } + if (strings.length < 2) { + printHelp(sender); + return; + } + final int pauseTimeout = NumberUtils.toInt(strings[1], -1); + if (pauseTimeout < 0) { + printHelp(sender); + return; + } + + MinecraftServer server = MinecraftServer.getServer(); + if (!server.isDedicatedServer()) { + sender.addChatMessage( + new ChatComponentText("'hp pauseWhenEmpty' only applies to dedicated servers")); + return; + } + + if (server instanceof IPauseWhenEmpty p) { + p.setPauseWhenEmptySeconds(pauseTimeout); + sender.addChatMessage( + new ChatComponentText( + String.format( + "Server property 'pause-when-empty-seconds' set to %d", + pauseTimeout))); + } + break; } } diff --git a/src/main/java/com/mitchej123/hodgepodge/config/TweaksConfig.java b/src/main/java/com/mitchej123/hodgepodge/config/TweaksConfig.java index 34b43b64..cac8464c 100644 --- a/src/main/java/com/mitchej123/hodgepodge/config/TweaksConfig.java +++ b/src/main/java/com/mitchej123/hodgepodge/config/TweaksConfig.java @@ -128,6 +128,10 @@ public class TweaksConfig { @Config.DefaultInt(900) public static int autoSaveInterval; + @Config.Comment({ "Backports 1.20's 'pause-when-empty-seconds' server property", "Default value: 0 (off)" }) + @Config.DefaultBoolean(true) + public static boolean pauseWhenEmpty; + @Config.Comment("Reduces water opacity from 3 to 1, to match modern") @Config.DefaultBoolean(false) public static boolean useLighterWater; @@ -306,5 +310,4 @@ public class TweaksConfig { @Config.Comment("Avoids droping items on container close, and instead places them in the player inventory. (Inspired from EFR)") @Config.DefaultBoolean(true) public static boolean avoidDroppingItemsWhenClosing; - } diff --git a/src/main/java/com/mitchej123/hodgepodge/mixins/Mixins.java b/src/main/java/com/mitchej123/hodgepodge/mixins/Mixins.java index c5ed5753..5f5952ac 100644 --- a/src/main/java/com/mitchej123/hodgepodge/mixins/Mixins.java +++ b/src/main/java/com/mitchej123/hodgepodge/mixins/Mixins.java @@ -421,6 +421,13 @@ public enum Mixins { .addMixinClasses("minecraft.server.MixinMinecraftServer_AutoSaveInterval") .setApplyIf(() -> TweaksConfig.autoSaveInterval != 900)), + PAUSE_WHEN_EMPTY(new Builder("Pauses the server when empty after X seconds; Servers Only").setPhase(Phase.EARLY) + .setSide(Side.SERVER).addTargetedMod(TargetedMod.VANILLA) + .addMixinClasses( + "minecraft.server.MixinMinecraftServer_PauseWhenEmpty", + "minecraft.server.MixinDedicatedServer_PauseWhenEmpty") + .setApplyIf(() -> TweaksConfig.pauseWhenEmpty)), + LIGHTER_WATER(new Builder("Decreases water opacity from 3 to 1, like in modern").setPhase(Phase.EARLY) .setSide(Side.BOTH).addTargetedMod(TargetedMod.VANILLA).addMixinClasses("minecraft.MixinBlock_LighterWater") .setApplyIf(() -> TweaksConfig.useLighterWater)), diff --git a/src/main/java/com/mitchej123/hodgepodge/mixins/early/minecraft/server/MixinDedicatedServer_PauseWhenEmpty.java b/src/main/java/com/mitchej123/hodgepodge/mixins/early/minecraft/server/MixinDedicatedServer_PauseWhenEmpty.java new file mode 100644 index 00000000..6682bf62 --- /dev/null +++ b/src/main/java/com/mitchej123/hodgepodge/mixins/early/minecraft/server/MixinDedicatedServer_PauseWhenEmpty.java @@ -0,0 +1,48 @@ +package com.mitchej123.hodgepodge.mixins.early.minecraft.server; + +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.dedicated.PropertyManager; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.mitchej123.hodgepodge.mixins.interfaces.IPauseWhenEmpty; + +@Mixin(DedicatedServer.class) +public class MixinDedicatedServer_PauseWhenEmpty implements IPauseWhenEmpty { + + @Shadow + private PropertyManager settings; + + @Unique + private int hodgepodge$pauseWhenEmptySeconds = 0; + + @Override + public int getPauseWhenEmptySeconds() { + return hodgepodge$pauseWhenEmptySeconds; + } + + @Override + public void setPauseWhenEmptySeconds(int value) { + value = Math.max(value, 0); + hodgepodge$pauseWhenEmptySeconds = value; + + settings.setProperty("pause-when-empty-seconds", hodgepodge$pauseWhenEmptySeconds); + settings.saveProperties(); + } + + @Inject( + method = "startServer", + at = @At( + value = "INVOKE", + target = "Lcpw/mods/fml/common/FMLCommonHandler;onServerStarted()V", + remap = false, + shift = At.Shift.AFTER)) + public void hodgepodge$setupServer(CallbackInfoReturnable cir) { + hodgepodge$pauseWhenEmptySeconds = settings.getIntProperty("pause-when-empty-seconds", 0); + } +} diff --git a/src/main/java/com/mitchej123/hodgepodge/mixins/early/minecraft/server/MixinMinecraftServer_PauseWhenEmpty.java b/src/main/java/com/mitchej123/hodgepodge/mixins/early/minecraft/server/MixinMinecraftServer_PauseWhenEmpty.java new file mode 100644 index 00000000..1550834b --- /dev/null +++ b/src/main/java/com/mitchej123/hodgepodge/mixins/early/minecraft/server/MixinMinecraftServer_PauseWhenEmpty.java @@ -0,0 +1,74 @@ +package com.mitchej123.hodgepodge.mixins.early.minecraft.server; + +import net.minecraft.network.NetworkSystem; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.server.management.ServerConfigurationManager; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import com.mitchej123.hodgepodge.Common; +import com.mitchej123.hodgepodge.mixins.interfaces.IPauseWhenEmpty; + +@Mixin(MinecraftServer.class) +public abstract class MixinMinecraftServer_PauseWhenEmpty { + + @Shadow + public abstract int getCurrentPlayerCount(); + + @Shadow + private ServerConfigurationManager serverConfigManager; + + @Shadow + protected abstract void saveAllWorlds(boolean dontLog); + + @Shadow + public abstract NetworkSystem func_147137_ag(); + + @Unique + private int hodgepodge$emptyTicks = 0; + @Unique + private boolean hodgepodge$wasPaused = false; + + @Inject(method = "tick", at = @At("HEAD"), cancellable = true, order = 9000) + public void hodgepodge$tick(CallbackInfo ci) { + if ((Object) this instanceof DedicatedServer ds && ds instanceof IPauseWhenEmpty p) { + int pauseTicks = p.getPauseWhenEmptySeconds() * 20; + if (pauseTicks > 0) { + if (this.getCurrentPlayerCount() == 0) { + this.hodgepodge$emptyTicks++; + } else { + this.hodgepodge$emptyTicks = 0; + } + + if (hodgepodge$emptyTicks >= pauseTicks) { + if (!hodgepodge$wasPaused) { + Common.log + .info("Server empty for {} seconds, saving and pausing", p.getPauseWhenEmptySeconds()); + this.serverConfigManager.saveAllPlayerData(); + this.saveAllWorlds(true); + hodgepodge$wasPaused = true; + } + // to finish saving chunks + net.minecraftforge.common.chunkio.ChunkIOExecutor.tick(); + // to process new connections + this.func_147137_ag().networkTick(); + // to process console commands + ds.executePendingCommands(); + ci.cancel(); + } else if (hodgepodge$wasPaused) { + Common.log.info("Resuming server"); + hodgepodge$wasPaused = false; + } + } else if (hodgepodge$wasPaused) { + Common.log.info("Resuming server"); + hodgepodge$wasPaused = false; + } + } + } +} diff --git a/src/main/java/com/mitchej123/hodgepodge/mixins/interfaces/IPauseWhenEmpty.java b/src/main/java/com/mitchej123/hodgepodge/mixins/interfaces/IPauseWhenEmpty.java new file mode 100644 index 00000000..42e2fb96 --- /dev/null +++ b/src/main/java/com/mitchej123/hodgepodge/mixins/interfaces/IPauseWhenEmpty.java @@ -0,0 +1,8 @@ +package com.mitchej123.hodgepodge.mixins.interfaces; + +public interface IPauseWhenEmpty { + + int getPauseWhenEmptySeconds(); + + void setPauseWhenEmptySeconds(int value); +}