diff --git a/src/main/java/ganymedes01/etfuturum/configuration/configs/ConfigMixins.java b/src/main/java/ganymedes01/etfuturum/configuration/configs/ConfigMixins.java index 65c86b58..cb60547f 100644 --- a/src/main/java/ganymedes01/etfuturum/configuration/configs/ConfigMixins.java +++ b/src/main/java/ganymedes01/etfuturum/configuration/configs/ConfigMixins.java @@ -44,6 +44,7 @@ public class ConfigMixins extends ConfigBase { public static boolean fireproofItems; public static boolean thinPanes; public static boolean colorGrassBlockItemSides; + public static boolean enablePlayersSleepingPecentageGamerule; static final String catBackport = "backported features"; static final String catOptimization = "optimizations"; @@ -113,5 +114,6 @@ protected void syncConfigOptions() { arrowFallingFix = getBoolean("arrowFallingFix", catFixes, true, "Prevents arrows from falling off of blocks too easily\nModified classes: net.minecraft.entity.EntityArrow"); collidedThrowableFix = getBoolean("collidedThrowableFix", catFixes, true, "Fixes EntityThrowable entities not calling onEntityCollidedWithBlock, causing them to not trigger target blocks or chime amethyst.\nModified classes: net.minecraft.entity.projectile.EntityThrowable"); hideSingleLevelEnchants = getBoolean("hideSingleLevelEnchants", catFixes, true, "Fixes enchantments with only one possible level displaying a level in their name. E.G. \"Silk Touch I\" becomes \"Silk Touch\".\nModified Classes: net.minecraft.enchantment.Enchantment"); + enablePlayersSleepingPecentageGamerule = getBoolean("enablePlayersSleepingPecentageGamerule", catBackport, true, "You nappa, you get slappa"); } } \ No newline at end of file diff --git a/src/main/java/ganymedes01/etfuturum/core/handlers/ServerEventHandler.java b/src/main/java/ganymedes01/etfuturum/core/handlers/ServerEventHandler.java index e6722200..00577cd4 100644 --- a/src/main/java/ganymedes01/etfuturum/core/handlers/ServerEventHandler.java +++ b/src/main/java/ganymedes01/etfuturum/core/handlers/ServerEventHandler.java @@ -32,6 +32,7 @@ import ganymedes01.etfuturum.entities.*; import ganymedes01.etfuturum.entities.ai.EntityAIOpenCustomDoor; import ganymedes01.etfuturum.gamerule.DoWeatherCycle; +import ganymedes01.etfuturum.gamerule.PlayersSleepingPercentage; import ganymedes01.etfuturum.gamerule.RandomTickSpeed; import ganymedes01.etfuturum.items.ItemArrowTipped; import ganymedes01.etfuturum.lib.Reference; @@ -1783,6 +1784,10 @@ public void loadWorldEvent(WorldEvent.Load event) { if (ConfigMixins.enableDoWeatherCycle) { DoWeatherCycle.registerGamerule(event.world); } + + if (ConfigMixins.enablePlayersSleepingPecentageGamerule) { + PlayersSleepingPercentage.registerGamerule(event.world); + } if(ConfigMixins.enableRandomTickSpeed) { RandomTickSpeed.registerGamerule(event.world); diff --git a/src/main/java/ganymedes01/etfuturum/core/utils/Utils.java b/src/main/java/ganymedes01/etfuturum/core/utils/Utils.java index 2c260e19..c9cb6565 100644 --- a/src/main/java/ganymedes01/etfuturum/core/utils/Utils.java +++ b/src/main/java/ganymedes01/etfuturum/core/utils/Utils.java @@ -8,8 +8,10 @@ import ganymedes01.etfuturum.configuration.configs.ConfigModCompat; import ganymedes01.etfuturum.configuration.configs.ConfigSounds; import ganymedes01.etfuturum.lib.Reference; +import ganymedes01.etfuturum.spectator.SpectatorMode; import net.minecraft.block.Block; import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; @@ -28,6 +30,7 @@ import java.util.*; import java.util.function.Predicate; +import java.util.stream.Collectors; public class Utils { @@ -596,4 +599,13 @@ public static boolean listGeneralModdedRawOre(String oreDict) { return !ConfigModCompat.moddedRawOresBlacklist.contains(oreDict.replace("ingot", "ore")) && !OreDictionary.getOres(oreDict).isEmpty() && !OreDictionary.getOres(oreDict.replace("ingot", "ore")).isEmpty(); } + + /** + * Filters spectators out of the provided list. + * @param list + * @return + */ + public static List getListWithoutSpectators(List list) { + return list.stream().filter(entity -> !SpectatorMode.isSpectator(entity)).collect(Collectors.toList()); + } } \ No newline at end of file diff --git a/src/main/java/ganymedes01/etfuturum/gamerule/PlayersSleepingPercentage.java b/src/main/java/ganymedes01/etfuturum/gamerule/PlayersSleepingPercentage.java new file mode 100644 index 00000000..6f5be58a --- /dev/null +++ b/src/main/java/ganymedes01/etfuturum/gamerule/PlayersSleepingPercentage.java @@ -0,0 +1,22 @@ +package ganymedes01.etfuturum.gamerule; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import java.util.ArrayList; +import java.util.List; + +public class PlayersSleepingPercentage { + public static final PlayersSleepingPercentage INSTANCE = new PlayersSleepingPercentage(); + public static final String GAMERULE_NAME = "playersSleepingPercentage"; + public static final String DEFAULT_VALUE = "100"; + + public int percentrillo = 100; + public List sleepyPlayers = new ArrayList<>(); + + public static void registerGamerule(World world) { + if (!world.isRemote && !world.getGameRules().hasRule(GAMERULE_NAME)) { + world.getGameRules().addGameRule(GAMERULE_NAME, DEFAULT_VALUE); + } + } +} diff --git a/src/main/java/ganymedes01/etfuturum/mixinplugin/EtFuturumEarlyMixins.java b/src/main/java/ganymedes01/etfuturum/mixinplugin/EtFuturumEarlyMixins.java index 6f90ecdc..389cc354 100644 --- a/src/main/java/ganymedes01/etfuturum/mixinplugin/EtFuturumEarlyMixins.java +++ b/src/main/java/ganymedes01/etfuturum/mixinplugin/EtFuturumEarlyMixins.java @@ -267,6 +267,10 @@ public List getMixins(Set loadedCoreMods) { } } + if (ConfigMixins.enablePlayersSleepingPecentageGamerule) { + mixins.add("playerssleepingpercentage.MixinWorldServer"); + } + return mixins; } diff --git a/src/main/java/ganymedes01/etfuturum/mixins/early/playerssleepingpercentage/MixinWorldServer.java b/src/main/java/ganymedes01/etfuturum/mixins/early/playerssleepingpercentage/MixinWorldServer.java new file mode 100644 index 00000000..3a601f54 --- /dev/null +++ b/src/main/java/ganymedes01/etfuturum/mixins/early/playerssleepingpercentage/MixinWorldServer.java @@ -0,0 +1,83 @@ +package ganymedes01.etfuturum.mixins.early.playerssleepingpercentage; + +import ganymedes01.etfuturum.core.utils.Utils; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.profiler.Profiler; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.world.World; +import net.minecraft.world.WorldProvider; +import net.minecraft.world.WorldServer; +import net.minecraft.world.WorldSettings; +import net.minecraft.world.storage.ISaveHandler; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +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.Redirect; +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 java.util.Iterator; +import java.util.List; + +import static ganymedes01.etfuturum.gamerule.PlayersSleepingPercentage.GAMERULE_NAME; +import static ganymedes01.etfuturum.gamerule.PlayersSleepingPercentage.INSTANCE; + +@Mixin(WorldServer.class) +public abstract class MixinWorldServer extends World { + @Shadow + private boolean allPlayersSleeping; + + public MixinWorldServer(ISaveHandler p_i45368_1_, String p_i45368_2_, WorldProvider p_i45368_3_, WorldSettings p_i45368_4_, Profiler p_i45368_5_) { + super(p_i45368_1_, p_i45368_2_, p_i45368_3_, p_i45368_4_, p_i45368_5_); + throw new ArithmeticException("2 + 2 = 5 ???"); + } + + @Inject(method = "updateAllPlayersSleepingFlag", at = @At("HEAD"), cancellable = true) + public void hhheheheheeh(CallbackInfo ctx) { + INSTANCE.percentrillo = Integer.parseInt(this.getGameRules().getGameRuleStringValue(GAMERULE_NAME)); + if (INSTANCE.percentrillo > 100) { + this.allPlayersSleeping = false; + ctx.cancel(/* /r/nosleep, vanilla behaviour */); + } else if (INSTANCE.percentrillo < 100) { + INSTANCE.sleepyPlayers.clear(); + List real = Utils.getListWithoutSpectators(this.playerEntities); + int cap = (int) Math.ceil(real.size() * INSTANCE.percentrillo * 0.01f); + for (EntityPlayer player : this.playerEntities) { + if (player.isPlayerSleeping()) { + INSTANCE.sleepyPlayers.add(player); + if (INSTANCE.sleepyPlayers.size() >= cap) { + this.allPlayersSleeping = true; + break; + } + } + } + + if (!INSTANCE.sleepyPlayers.isEmpty() && cap > 0) { + for (EntityPlayer paypiggy : this.playerEntities) { + paypiggy.addChatMessage(new ChatComponentTranslation("sleep.players_sleeping", INSTANCE.sleepyPlayers.size(), cap)); + } + } + ctx.cancel(); + } + } + + @Redirect(method = "areAllPlayersAsleep", at = @At(value = "FIELD", target = "Lnet/minecraft/world/WorldServer;playerEntities:Ljava/util/List;", opcode = Opcodes.GETFIELD)) + public List baited(WorldServer instance) { + return INSTANCE.sleepyPlayers; + } + + @Inject(method = "areAllPlayersAsleep", at = @At(value = "INVOKE", target = "Ljava/util/List;iterator()Ljava/util/Iterator;"), cancellable = true) + public void turbofast(CallbackInfoReturnable ctx) { + if (INSTANCE.percentrillo < 1) ctx.setReturnValue(true); + } + + @Inject(method = "wakeAllPlayers", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/EntityPlayer;wakeUpPlayer(ZZZ)V"), locals = LocalCapture.CAPTURE_FAILHARD) + public void broadcast(CallbackInfo ctx, Iterator iterator, EntityPlayer player) { + if (INSTANCE.percentrillo > 0 && INSTANCE.percentrillo < 101) { + player.addChatMessage(new ChatComponentTranslation("sleep.skipping_night")); + } + } +} diff --git a/src/main/java/ganymedes01/etfuturum/mixins/early/spectator/MixinWorldServer.java b/src/main/java/ganymedes01/etfuturum/mixins/early/spectator/MixinWorldServer.java index f91d359a..31ccce0f 100644 --- a/src/main/java/ganymedes01/etfuturum/mixins/early/spectator/MixinWorldServer.java +++ b/src/main/java/ganymedes01/etfuturum/mixins/early/spectator/MixinWorldServer.java @@ -1,4 +1,5 @@ package ganymedes01.etfuturum.mixins.early.spectator; +import ganymedes01.etfuturum.core.utils.Utils; import com.llamalad7.mixinextras.injector.wrapoperation.Operation; import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; @@ -26,16 +27,6 @@ public MixinWorldServer(ISaveHandler p_i45368_1_, String p_i45368_2_, WorldProvi super(p_i45368_1_, p_i45368_2_, p_i45368_3_, p_i45368_4_, p_i45368_5_); } - /** - * Filters spectators out of the provided list. - * @param list - * @return - */ - @Unique - private static List etfuturum$getListWithoutSpectators(List list) { - return list.stream().filter(entity -> !SpectatorMode.isSpectator(entity)).collect(Collectors.toList()); - } - /** * Filters spectators out of the playerEntities list before it is checked by areAllPlayersAsleep. * Uses original.call to create the iterator to maintain compatibility with any other mixins @@ -45,7 +36,7 @@ public MixinWorldServer(ISaveHandler p_i45368_1_, String p_i45368_2_, WorldProvi */ @WrapOperation(method = "areAllPlayersAsleep", at = @At(value = "INVOKE", target = "Ljava/util/List;iterator()Ljava/util/Iterator;")) private Iterator dontCountSpectatorsForSleepListCheck(List instance, Operation> original) { - return original.call(etfuturum$getListWithoutSpectators(instance)); + return original.call(Utils.getListWithoutSpectators(instance)); } /** @@ -58,7 +49,7 @@ private Iterator dontCountSpectatorsForSleepListCheck(List instance, Operation original, @Share("nonSpectatingPlayers") LocalRef> nonSpectatingPlayers) { - List list = etfuturum$getListWithoutSpectators(instance); + List list = Utils.getListWithoutSpectators(instance); nonSpectatingPlayers.set(list); return original.call(list); } diff --git a/src/main/resources/assets/etfuturum/lang/en_US.lang b/src/main/resources/assets/etfuturum/lang/en_US.lang index f3d6a96d..1ef21eb6 100755 --- a/src/main/resources/assets/etfuturum/lang/en_US.lang +++ b/src/main/resources/assets/etfuturum/lang/en_US.lang @@ -27,6 +27,9 @@ commands.etfuturum.fill.usage=/fill commands.etfuturum.fill.outOfWorld=Cannot place blocks outside of world commands.etfuturum.fill.success=Successfully filled %d block(s) +sleep.players_sleeping=%s/%s players sleeping +sleep.skipping_night=Sleeping through this night + # Containers/GUI container.enchant.lapis.one=1 Lapis Lazuli container.enchant.lapis.many=%d Lapis Lazuli