mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-30 16:28:00 +01:00
Bat ponies can now sleep during the day to skip to the night
This commit is contained in:
parent
c665137a5c
commit
4783b80f38
9 changed files with 133 additions and 24 deletions
|
@ -29,7 +29,7 @@ public record Race (boolean canCast, FlightType flightType, boolean canUseEarth,
|
||||||
private static final DynamicCommandExceptionType UNKNOWN_RACE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("race.unknown", id));
|
private static final DynamicCommandExceptionType UNKNOWN_RACE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("race.unknown", id));
|
||||||
|
|
||||||
public static Race register(String name, boolean magic, FlightType flight, boolean earth, boolean nocturnal) {
|
public static Race register(String name, boolean magic, FlightType flight, boolean earth, boolean nocturnal) {
|
||||||
return register(Unicopia.id(name), magic, flight, earth, false);
|
return register(Unicopia.id(name), magic, flight, earth, nocturnal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Race register(Identifier id, boolean magic, FlightType flight, boolean earth, boolean nocturnal) {
|
public static Race register(Identifier id, boolean magic, FlightType flight, boolean earth, boolean nocturnal) {
|
||||||
|
|
|
@ -18,7 +18,6 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.TraitLoader;
|
||||||
import com.minelittlepony.unicopia.advancement.UCriteria;
|
import com.minelittlepony.unicopia.advancement.UCriteria;
|
||||||
import com.minelittlepony.unicopia.block.UBlocks;
|
import com.minelittlepony.unicopia.block.UBlocks;
|
||||||
import com.minelittlepony.unicopia.block.UTreeGen;
|
import com.minelittlepony.unicopia.block.UTreeGen;
|
||||||
import com.minelittlepony.unicopia.block.data.*;
|
|
||||||
import com.minelittlepony.unicopia.block.state.StateMapLoader;
|
import com.minelittlepony.unicopia.block.state.StateMapLoader;
|
||||||
import com.minelittlepony.unicopia.command.Commands;
|
import com.minelittlepony.unicopia.command.Commands;
|
||||||
import com.minelittlepony.unicopia.container.SpellbookChapterLoader;
|
import com.minelittlepony.unicopia.container.SpellbookChapterLoader;
|
||||||
|
@ -31,6 +30,7 @@ import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||||
import com.minelittlepony.unicopia.network.Channel;
|
import com.minelittlepony.unicopia.network.Channel;
|
||||||
import com.minelittlepony.unicopia.particle.UParticles;
|
import com.minelittlepony.unicopia.particle.UParticles;
|
||||||
import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
|
import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
|
||||||
|
import com.minelittlepony.unicopia.server.world.NocturnalSleepManager;
|
||||||
import com.minelittlepony.unicopia.server.world.UGameRules;
|
import com.minelittlepony.unicopia.server.world.UGameRules;
|
||||||
import com.minelittlepony.unicopia.server.world.WeatherConditions;
|
import com.minelittlepony.unicopia.server.world.WeatherConditions;
|
||||||
import com.minelittlepony.unicopia.server.world.ZapAppleStageStore;
|
import com.minelittlepony.unicopia.server.world.ZapAppleStageStore;
|
||||||
|
@ -71,6 +71,8 @@ public class Unicopia implements ModInitializer {
|
||||||
SpellbookChapterLoader.INSTANCE.sendUpdate(w.getServer());
|
SpellbookChapterLoader.INSTANCE.sendUpdate(w.getServer());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
NocturnalSleepManager.bootstrap();
|
||||||
|
|
||||||
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(TreeTypeLoader.INSTANCE);
|
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(TreeTypeLoader.INSTANCE);
|
||||||
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(UEnchantments.POISONED_JOKE);
|
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(UEnchantments.POISONED_JOKE);
|
||||||
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(new TraitLoader());
|
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(new TraitLoader());
|
||||||
|
|
|
@ -47,6 +47,7 @@ import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.server.world.ServerWorld;
|
import net.minecraft.server.world.ServerWorld;
|
||||||
import net.minecraft.sound.SoundEvents;
|
import net.minecraft.sound.SoundEvents;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.math.*;
|
import net.minecraft.util.math.*;
|
||||||
import net.minecraft.world.GameMode;
|
import net.minecraft.world.GameMode;
|
||||||
|
@ -571,8 +572,12 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
||||||
.map(p -> Text.translatable("block.unicopia.bed.not_safe"));
|
.map(p -> Text.translatable("block.unicopia.bed.not_safe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDaytime() {
|
public ActionResult canSleepNow() {
|
||||||
return asWorld().getGameRules().getBoolean(UGameRules.DO_NOCTURNAL_BAT_PONIES) && getActualSpecies().isNocturnal() ? !asWorld().isDay() : asWorld().isDay();
|
if (asWorld().getGameRules().getBoolean(UGameRules.DO_NOCTURNAL_BAT_PONIES) && getActualSpecies().isNocturnal()) {
|
||||||
|
return asWorld().isDay() ? ActionResult.SUCCESS : ActionResult.FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ActionResult.PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,7 +5,6 @@ import org.spongepowered.asm.mixin.gen.Invoker;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.entity.duck.PlayerEntityDuck;
|
import com.minelittlepony.unicopia.entity.duck.PlayerEntityDuck;
|
||||||
|
@ -22,10 +21,10 @@ import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
||||||
import net.minecraft.entity.damage.DamageSource;
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.stat.Stats;
|
import net.minecraft.stat.Stats;
|
||||||
import net.minecraft.util.Unit;
|
import net.minecraft.util.Unit;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
|
||||||
|
|
||||||
@Mixin(PlayerEntity.class)
|
@Mixin(PlayerEntity.class)
|
||||||
abstract class MixinPlayerEntity extends LivingEntity implements Equine.Container<Pony>, PlayerEntityDuck {
|
abstract class MixinPlayerEntity extends LivingEntity implements Equine.Container<Pony>, PlayerEntityDuck {
|
||||||
|
@ -70,7 +69,7 @@ abstract class MixinPlayerEntity extends LivingEntity implements Equine.Containe
|
||||||
get().trySleep(pos).ifPresent(reason -> {
|
get().trySleep(pos).ifPresent(reason -> {
|
||||||
((PlayerEntity)(Object)this).sendMessage(reason, true);
|
((PlayerEntity)(Object)this).sendMessage(reason, true);
|
||||||
|
|
||||||
info.setReturnValue(Either.right(Unit.INSTANCE));
|
info.setReturnValue(Either.left(ServerPlayerEntity.SleepFailureReason.OTHER_PROBLEM));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,12 +100,4 @@ abstract class MixinPlayerEntity extends LivingEntity implements Equine.Containe
|
||||||
private void onGetBlockBreakingSpeed(BlockState state, CallbackInfoReturnable<Float> info) {
|
private void onGetBlockBreakingSpeed(BlockState state, CallbackInfoReturnable<Float> info) {
|
||||||
info.setReturnValue(info.getReturnValue() * get().getBlockBreakingSpeed());
|
info.setReturnValue(info.getReturnValue() * get().getBlockBreakingSpeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Redirect(method = "tick", at = @At(
|
|
||||||
value = "INVOKE",
|
|
||||||
target = "net/minecraft/world/World.isDay()Z"
|
|
||||||
))
|
|
||||||
private boolean redirectIsDay(World world) {
|
|
||||||
return get().isDaytime();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,21 @@ import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
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.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.entity.Equine;
|
import com.minelittlepony.unicopia.entity.Equine;
|
||||||
import com.minelittlepony.unicopia.entity.duck.ServerPlayerEntityDuck;
|
import com.minelittlepony.unicopia.entity.duck.ServerPlayerEntityDuck;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
import com.minelittlepony.unicopia.server.world.UGameRules;
|
||||||
|
import com.mojang.datafixers.util.Either;
|
||||||
|
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.screen.ScreenHandlerListener;
|
import net.minecraft.screen.ScreenHandlerListener;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Unit;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
@Mixin(ServerPlayerEntity.class)
|
@Mixin(ServerPlayerEntity.class)
|
||||||
abstract class MixinServerPlayerEntity extends PlayerEntity implements ScreenHandlerListener, Equine.Container<Pony>, ServerPlayerEntityDuck {
|
abstract class MixinServerPlayerEntity extends PlayerEntity implements ScreenHandlerListener, Equine.Container<Pony>, ServerPlayerEntityDuck {
|
||||||
|
@ -29,11 +34,14 @@ abstract class MixinServerPlayerEntity extends PlayerEntity implements ScreenHan
|
||||||
get().copyFrom(((Equine.Container<Pony>)oldPlayer).get(), alive);
|
get().copyFrom(((Equine.Container<Pony>)oldPlayer).get(), alive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Redirect(method = "trySleep", at = @At(
|
@Inject(method = "trySleep(Lnet/minecraft/util/math/BlockPos;)Lcom/mojang/datafixers/util/Either;",
|
||||||
value = "INVOKE",
|
at = @At(value = "FIELD", target = "net/minecraft/entity/player/PlayerEntity$SleepFailureReason.NOT_POSSIBLE_NOW"),
|
||||||
target = "net/minecraft/world/World.isDay()Z"
|
cancellable = true)
|
||||||
))
|
private void onTrySleep(BlockPos pos, CallbackInfoReturnable<Either<PlayerEntity.SleepFailureReason, Unit>> info) {
|
||||||
private boolean redirectIsDay(World world) {
|
if (get().getActualSpecies().isNocturnal() && get().asWorld().getGameRules().getBoolean(UGameRules.DO_NOCTURNAL_BAT_PONIES)) {
|
||||||
return get().isDaytime();
|
((PlayerEntity)this).sendMessage(Text.translatable("block.minecraft.bed.no_sleep.nocturnal"), true);
|
||||||
|
|
||||||
|
info.setReturnValue(Either.left(PlayerEntity.SleepFailureReason.OTHER_PROBLEM));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,67 @@
|
||||||
package com.minelittlepony.unicopia.mixin;
|
package com.minelittlepony.unicopia.mixin;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Constant;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.ModifyConstant;
|
||||||
|
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
|
import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
|
||||||
|
import com.minelittlepony.unicopia.server.world.NocturnalSleepManager;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.server.world.ServerWorld;
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.server.world.SleepManager;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.StructureWorldAccess;
|
import net.minecraft.world.StructureWorldAccess;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
@Mixin(ServerWorld.class)
|
@Mixin(ServerWorld.class)
|
||||||
abstract class MixinServerWorld extends World implements StructureWorldAccess {
|
abstract class MixinServerWorld extends World implements StructureWorldAccess, NocturnalSleepManager.Source {
|
||||||
|
|
||||||
|
private NocturnalSleepManager nocturnalSleepManager;
|
||||||
|
|
||||||
MixinServerWorld() { super(null, null, null, null, false, false, 0, 0); }
|
MixinServerWorld() { super(null, null, null, null, false, false, 0, 0); }
|
||||||
|
|
||||||
@Inject(method = "onBlockChanged", at = @At("HEAD"))
|
@Inject(method = "onBlockChanged", at = @At("HEAD"))
|
||||||
private void onOnBlockChanged(BlockPos pos, BlockState oldState, BlockState newState, CallbackInfo info) {
|
private void onOnBlockChanged(BlockPos pos, BlockState oldState, BlockState newState, CallbackInfo info) {
|
||||||
((BlockDestructionManager.Source)this).getDestructionManager().onBlockChanged(pos, oldState, newState);
|
((BlockDestructionManager.Source)this).getDestructionManager().onBlockChanged(pos, oldState, newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ModifyConstant(method = "sendSleepingStatus()V", constant = @Constant(
|
||||||
|
stringValue = "sleep.skipping_night"
|
||||||
|
))
|
||||||
|
private String modifySleepingMessage(String initial) {
|
||||||
|
return getNocturnalSleepManager().getTimeSkippingMessage(initial);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NocturnalSleepManager getNocturnalSleepManager() {
|
||||||
|
if (nocturnalSleepManager == null) {
|
||||||
|
nocturnalSleepManager = new NocturnalSleepManager((ServerWorld)(Object)this);
|
||||||
|
}
|
||||||
|
return nocturnalSleepManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "tick(Ljava/util/function/BooleanSupplier;)V", at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "net/minecraft/server/world/ServerWorld.wakeSleepingPlayers()V"
|
||||||
|
))
|
||||||
|
public void beforeWakeup(BooleanSupplier shouldKeepTicking, CallbackInfo info) {
|
||||||
|
getNocturnalSleepManager().skipTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mixin(SleepManager.class)
|
||||||
|
abstract class MixinSleepManager {
|
||||||
|
@ModifyVariable(method = "update(Ljava/util/List;)Z", at = @At("HEAD"))
|
||||||
|
public List<ServerPlayerEntity> modifyPlayers(List<ServerPlayerEntity> players) {
|
||||||
|
return players.size() <= 0 ? players : ((NocturnalSleepManager.Source)players.get(0).getWorld()).getNocturnalSleepManager().filterPlayers(players);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.minelittlepony.unicopia.server.world;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.entity.event.v1.EntitySleepEvents;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.server.world.SleepManager;
|
||||||
|
import net.minecraft.world.GameRules;
|
||||||
|
|
||||||
|
public class NocturnalSleepManager extends SleepManager {
|
||||||
|
public static final long DAY_LENGTH = 24000L;
|
||||||
|
|
||||||
|
private final ServerWorld world;
|
||||||
|
|
||||||
|
public NocturnalSleepManager(ServerWorld world) {
|
||||||
|
this.world = world;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTimeSkippingMessage(String nightSkippingMessage) {
|
||||||
|
if (world.getGameRules().getBoolean(UGameRules.DO_NOCTURNAL_BAT_PONIES) && world.isDay()) {
|
||||||
|
return "sleep.skipping_day";
|
||||||
|
}
|
||||||
|
|
||||||
|
return nightSkippingMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skipTime() {
|
||||||
|
if (world.getGameRules().getBoolean(GameRules.DO_DAYLIGHT_CYCLE)) {
|
||||||
|
world.setTimeOfDay(world.getLevelProperties().getTimeOfDay() - DAY_LENGTH + 13500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ServerPlayerEntity> getApplicablePlayer() {
|
||||||
|
return filterPlayers(world.getPlayers());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ServerPlayerEntity> filterPlayers(List<ServerPlayerEntity> players) {
|
||||||
|
if (!world.getGameRules().getBoolean(UGameRules.DO_NOCTURNAL_BAT_PONIES)) {
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
return players.stream().filter(player -> {
|
||||||
|
Pony pony = Pony.of(player);
|
||||||
|
return (pony.getActualSpecies().isNocturnal() == world.isDay());
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bootstrap() {
|
||||||
|
EntitySleepEvents.ALLOW_SLEEP_TIME.register((player, pos, isDay) -> Pony.of(player).canSleepNow());
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Source {
|
||||||
|
NocturnalSleepManager getNocturnalSleepManager();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
"block.unicopia.bed.not_safe": "You may not rest here, there are enemies nearby",
|
"block.unicopia.bed.not_safe": "You may not rest here, there are enemies nearby",
|
||||||
"block.unicopia.bed.not_tired": "You do not feel tired right now",
|
"block.unicopia.bed.not_tired": "You do not feel tired right now",
|
||||||
|
"block.minecraft.bed.no_sleep.nocturnal": "You can only sleep in the day or during thunderstorms",
|
||||||
|
|
||||||
"ability.unicopia.empty_hooves": "I need to find a jar",
|
"ability.unicopia.empty_hooves": "I need to find a jar",
|
||||||
"ability.unicopia.indoors": "I can't see the sky from here",
|
"ability.unicopia.indoors": "I can't see the sky from here",
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"MixinServerPlayerEntity",
|
"MixinServerPlayerEntity",
|
||||||
"MixinServerPlayNetworkHandler",
|
"MixinServerPlayNetworkHandler",
|
||||||
"MixinServerWorld",
|
"MixinServerWorld",
|
||||||
|
"MixinSleepManager",
|
||||||
"MixinSheepEntity",
|
"MixinSheepEntity",
|
||||||
"MixinShulkerEntity",
|
"MixinShulkerEntity",
|
||||||
"MixinStateManager",
|
"MixinStateManager",
|
||||||
|
|
Loading…
Reference in a new issue