Make the spectral clock more accurate

This commit is contained in:
Sollace 2024-02-03 12:42:26 +00:00
parent 38892ffde4
commit 4230518d08
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
7 changed files with 102 additions and 69 deletions

View file

@ -45,6 +45,7 @@ import net.minecraft.block.entity.BlockEntity;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.color.world.BiomeColors; import net.minecraft.client.color.world.BiomeColors;
import net.minecraft.client.color.world.FoliageColors; import net.minecraft.client.color.world.FoliageColors;
import net.minecraft.client.item.ClampedModelPredicateProvider;
import net.minecraft.client.item.ModelPredicateProviderRegistry; import net.minecraft.client.item.ModelPredicateProviderRegistry;
import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.SpriteProvider; import net.minecraft.client.particle.SpriteProvider;
@ -55,6 +56,8 @@ import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.json.ModelTransformationMode; import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld; import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.fluid.Fluids; import net.minecraft.fluid.Fluids;
import net.minecraft.item.*; import net.minecraft.item.*;
import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleEffect;
@ -116,7 +119,32 @@ public interface URenderers {
PolearmRenderer.register(UItems.WOODEN_POLEARM, UItems.STONE_POLEARM, UItems.IRON_POLEARM, UItems.GOLDEN_POLEARM, UItems.DIAMOND_POLEARM, UItems.NETHERITE_POLEARM); PolearmRenderer.register(UItems.WOODEN_POLEARM, UItems.STONE_POLEARM, UItems.IRON_POLEARM, UItems.GOLDEN_POLEARM, UItems.DIAMOND_POLEARM, UItems.NETHERITE_POLEARM);
ModelPredicateProviderRegistry.register(UItems.GEMSTONE, new Identifier("affinity"), (stack, world, entity, seed) -> EnchantableItem.isEnchanted(stack) ? EnchantableItem.getSpellKey(stack).getAffinity().getAlignment() : 0); ModelPredicateProviderRegistry.register(UItems.GEMSTONE, new Identifier("affinity"), (stack, world, entity, seed) -> EnchantableItem.isEnchanted(stack) ? EnchantableItem.getSpellKey(stack).getAffinity().getAlignment() : 0);
ModelPredicateProviderRegistry.register(UItems.ROCK_CANDY, new Identifier("count"), (stack, world, entity, seed) -> stack.getCount() / (float)stack.getMaxCount()); ModelPredicateProviderRegistry.register(UItems.ROCK_CANDY, new Identifier("count"), (stack, world, entity, seed) -> stack.getCount() / (float)stack.getMaxCount());
ModelPredicateProviderRegistry.register(Unicopia.id("zap_cycle"), (stack, world, entity, seed) -> UnicopiaClient.getInstance().getZapStageDelta()); ModelPredicateProviderRegistry.register(Unicopia.id("zap_cycle"), new ClampedModelPredicateProvider() {
private double targetAngle;
private double lastAngle;
private long lastTick;
@Override
public float unclampedCall(ItemStack stack, ClientWorld world, LivingEntity e, int var4) {
Entity entity = e != null ? e : stack.getHolder();
if (entity == null) {
return 0;
}
if (world == null && entity.getWorld() instanceof ClientWorld) {
world = (ClientWorld)entity.getWorld();
}
if (world == null) {
return 0;
}
if (world.getTime() != lastTick) {
targetAngle = world.getDimension().natural() ? UnicopiaClient.getInstance().getZapAppleStage().getCycleProgress(world) : Math.random();
lastAngle = lastAngle + (targetAngle - lastAngle) * 0.1;
}
return (float)lastAngle;
}
});
ColorProviderRegistry.BLOCK.register(URenderers::getTintedBlockColor, TintedBlock.REGISTRY.stream().toArray(Block[]::new)); ColorProviderRegistry.BLOCK.register(URenderers::getTintedBlockColor, TintedBlock.REGISTRY.stream().toArray(Block[]::new));
ColorProviderRegistry.ITEM.register((stack, i) -> getTintedBlockColor(Block.getBlockFromItem(stack.getItem()).getDefaultState(), null, null, i), TintedBlock.REGISTRY.stream().map(Block::asItem).filter(i -> i != Items.AIR).toArray(Item[]::new)); ColorProviderRegistry.ITEM.register((stack, i) -> getTintedBlockColor(Block.getBlockFromItem(stack.getItem()).getDefaultState(), null, null, i), TintedBlock.REGISTRY.stream().map(Block::asItem).filter(i -> i != Items.AIR).toArray(Item[]::new));

View file

@ -55,7 +55,6 @@ public class UnicopiaClient implements ClientModInitializer {
public final Lerp skyAngle = new Lerp(0, true); public final Lerp skyAngle = new Lerp(0, true);
private ZapAppleStageStore.Stage zapAppleStage = ZapAppleStageStore.Stage.HIBERNATING; private ZapAppleStageStore.Stage zapAppleStage = ZapAppleStageStore.Stage.HIBERNATING;
private long zapStageTime;
public static Optional<PlayerCamera> getCamera() { public static Optional<PlayerCamera> getCamera() {
PlayerEntity player = MinecraftClient.getInstance().player; PlayerEntity player = MinecraftClient.getInstance().player;
@ -88,13 +87,12 @@ public class UnicopiaClient implements ClientModInitializer {
instance = this; instance = this;
} }
public void setZapAppleStage(ZapAppleStageStore.Stage stage, long delta) { public void setZapAppleStage(ZapAppleStageStore.Stage stage) {
zapAppleStage = stage; zapAppleStage = stage;
zapStageTime = delta;
} }
public float getZapStageDelta() { public ZapAppleStageStore.Stage getZapAppleStage() {
return zapAppleStage.getCycleProgress(zapStageTime); return zapAppleStage;
} }
public float getSkyAngleDelta(float tickDelta) { public float getSkyAngleDelta(float tickDelta) {
@ -148,8 +146,6 @@ public class UnicopiaClient implements ClientModInitializer {
world.setRainGradient(gradient); world.setRainGradient(gradient);
world.setThunderGradient(gradient); world.setThunderGradient(gradient);
} }
zapStageTime++;
} }
private Float getTargetRainGradient(ClientWorld world, BlockPos pos, float tickDelta) { private Float getTargetRainGradient(ClientWorld world, BlockPos pos, float tickDelta) {

View file

@ -55,7 +55,7 @@ public interface Channel {
sender.sendPacket(SERVER_RESOURCES.id(), new MsgServerResources().toBuffer()); sender.sendPacket(SERVER_RESOURCES.id(), new MsgServerResources().toBuffer());
sender.sendPacket(SERVER_SKY_ANGLE.id(), new MsgSkyAngle(UnicopiaWorldProperties.forWorld(handler.getPlayer().getServerWorld()).getTangentalSkyAngle()).toBuffer()); sender.sendPacket(SERVER_SKY_ANGLE.id(), new MsgSkyAngle(UnicopiaWorldProperties.forWorld(handler.getPlayer().getServerWorld()).getTangentalSkyAngle()).toBuffer());
ZapAppleStageStore store = ZapAppleStageStore.get(handler.player.getServerWorld()); ZapAppleStageStore store = ZapAppleStageStore.get(handler.player.getServerWorld());
sender.sendPacket(SERVER_ZAP_STAGE.id(), new MsgZapAppleStage(store.getStage(), store.getStageDelta()).toBuffer()); sender.sendPacket(SERVER_ZAP_STAGE.id(), new MsgZapAppleStage(store.getStage()).toBuffer());
}); });
} }
} }

View file

@ -7,17 +7,15 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
public record MsgZapAppleStage ( public record MsgZapAppleStage (
ZapAppleStageStore.Stage stage, ZapAppleStageStore.Stage stage
long delta
) implements Packet<PlayerEntity> { ) implements Packet<PlayerEntity> {
public MsgZapAppleStage(PacketByteBuf buffer) { public MsgZapAppleStage(PacketByteBuf buffer) {
this(buffer.readEnumConstant(ZapAppleStageStore.Stage.class), buffer.readLong()); this(buffer.readEnumConstant(ZapAppleStageStore.Stage.class));
} }
@Override @Override
public void toBuffer(PacketByteBuf buffer) { public void toBuffer(PacketByteBuf buffer) {
buffer.writeEnumConstant(stage); buffer.writeEnumConstant(stage);
buffer.writeLong(delta);
} }
} }

View file

@ -95,7 +95,7 @@ public class ClientNetworkHandlerImpl {
} }
private void handleZapStage(PlayerEntity sender, MsgZapAppleStage packet) { private void handleZapStage(PlayerEntity sender, MsgZapAppleStage packet) {
UnicopiaClient.getInstance().setZapAppleStage(packet.stage(), packet.delta()); UnicopiaClient.getInstance().setZapAppleStage(packet.stage());
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View file

@ -3,12 +3,15 @@ package com.minelittlepony.unicopia.server.world;
import java.util.Locale; import java.util.Locale;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.network.Channel; import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgZapAppleStage; import com.minelittlepony.unicopia.network.MsgZapAppleStage;
import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect; import com.minelittlepony.unicopia.particle.LightningBoltParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.util.MeteorlogicalUtil;
import com.minelittlepony.unicopia.util.Tickable; import com.minelittlepony.unicopia.util.Tickable;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
@ -37,17 +40,15 @@ public class ZapAppleStageStore extends PersistentState implements Tickable {
private final World world; private final World world;
private Stage lastStage = Stage.HIBERNATING; private Stage lastStage = Stage.HIBERNATING;
private long stageDelta;
private long lastTime;
private boolean stageChanged; private boolean stageChanged;
private boolean playedMoonEffect; private boolean playedMoonEffect;
private int nextLightningEvent = 1200; private int nextLightningEvent = 1200;
private float prevSkyAngle;
ZapAppleStageStore(World world, NbtCompound compound) { ZapAppleStageStore(World world, NbtCompound compound) {
this(world); this(world);
lastStage = Stage.VALUES[Math.max(0, compound.getInt("stage")) % Stage.VALUES.length]; lastStage = Stage.VALUES[Math.max(0, compound.getInt("stage")) % Stage.VALUES.length];
stageDelta = compound.getLong("stageDelta");
stageChanged = compound.getBoolean("stageChanged"); stageChanged = compound.getBoolean("stageChanged");
playedMoonEffect = compound.getBoolean("playedMoonEffect"); playedMoonEffect = compound.getBoolean("playedMoonEffect");
nextLightningEvent = compound.getInt("nextLightningEvent"); nextLightningEvent = compound.getInt("nextLightningEvent");
@ -59,41 +60,36 @@ public class ZapAppleStageStore extends PersistentState implements Tickable {
@Override @Override
public void tick() { public void tick() {
if (!world.isDay()) { float skyAngle = MeteorlogicalUtil.getSkyAngle(world);
if (skyAngle > MeteorlogicalUtil.SUNSET) {
if (nextLightningEvent > 0) { if (nextLightningEvent > 0) {
nextLightningEvent--; nextLightningEvent--;
markDirty();
} }
if (!stageChanged && (lastStage != Stage.HIBERNATING || (world.getMoonPhase() == 0))) { if (!stageChanged && MathHelper.approximatelyEquals(skyAngle, MeteorlogicalUtil.MIDNIGHT) || (
MeteorlogicalUtil.isBetween(skyAngle, MeteorlogicalUtil.MIDNIGHT, MeteorlogicalUtil.MOONSET)
&& MeteorlogicalUtil.isBetween(prevSkyAngle, MeteorlogicalUtil.SUNSET, MeteorlogicalUtil.MIDNIGHT)
)) {
stageChanged = true; stageChanged = true;
lastStage = lastStage.getNext(); if (lastStage != Stage.HIBERNATING || world.getMoonPhase() == 0) {
stageDelta = 0; lastStage = lastStage.getNext();
playedMoonEffect = false; playedMoonEffect = false;
sendUpdate(); markDirty();
sendUpdate();
}
} }
} else if (stageChanged) { } else if (stageChanged) {
stageChanged = false; stageChanged = false;
markDirty();
} }
long timeOfDay = world.getTimeOfDay(); prevSkyAngle = skyAngle;
if (stageDelta != 0 && (timeOfDay < lastTime || timeOfDay > lastTime + 10)) {
long timeDifference = timeOfDay - lastTime;
Unicopia.LOGGER.info("Times a changing {}!", timeDifference);
while (timeDifference < 0) {
timeDifference += DAY_LENGTH;
}
stageDelta += timeDifference;
sendUpdate();
}
lastTime = timeOfDay;
stageDelta++;
markDirty();
} }
protected void sendUpdate() { protected void sendUpdate() {
Channel.SERVER_ZAP_STAGE.sendToAllPlayers(new MsgZapAppleStage(getStage(), stageDelta), world); Channel.SERVER_ZAP_STAGE.sendToAllPlayers(new MsgZapAppleStage(getStage()), world);
} }
public void playMoonEffect(BlockPos pos) { public void playMoonEffect(BlockPos pos) {
@ -137,22 +133,9 @@ public class ZapAppleStageStore extends PersistentState implements Tickable {
return lastStage; return lastStage;
} }
public long getStageDelta() {
return stageDelta;
}
public float getStageProgress() {
return getStage().getStageProgress(getStageDelta());
}
public float getCycleProgress() {
return getStage().getCycleProgress(getStageDelta());
}
@Override @Override
public NbtCompound writeNbt(NbtCompound compound) { public NbtCompound writeNbt(NbtCompound compound) {
compound.putInt("stage", lastStage.ordinal()); compound.putInt("stage", lastStage.ordinal());
compound.putLong("stageDelta", stageDelta);
compound.putBoolean("stageChanged", stageChanged); compound.putBoolean("stageChanged", stageChanged);
compound.putBoolean("playedMoonEffect", playedMoonEffect); compound.putBoolean("playedMoonEffect", playedMoonEffect);
compound.putInt("nextLightningEvent", nextLightningEvent); compound.putInt("nextLightningEvent", nextLightningEvent);
@ -160,19 +143,16 @@ public class ZapAppleStageStore extends PersistentState implements Tickable {
} }
public enum Stage implements StringIdentifiable { public enum Stage implements StringIdentifiable {
HIBERNATING(MOON_PHASES * DAY_LENGTH), HIBERNATING,
GREENING(DAY_LENGTH), GREENING,
FLOWERING(DAY_LENGTH), FLOWERING,
FRUITING(DAY_LENGTH), FRUITING,
RIPE(DAY_LENGTH); RIPE;
static final Stage[] VALUES = values(); static final Stage[] VALUES = values();
static final float MAX = VALUES.length;
private final long duration; private final float ordinal = ordinal();
Stage(long duration) {
this.duration = duration;
}
public Stage getNext() { public Stage getNext() {
return byId((ordinal() + 1) % VALUES.length); return byId((ordinal() + 1) % VALUES.length);
@ -182,13 +162,21 @@ public class ZapAppleStageStore extends PersistentState implements Tickable {
return byId(((ordinal() - 1) + VALUES.length) % VALUES.length); return byId(((ordinal() - 1) + VALUES.length) % VALUES.length);
} }
public float getStageProgress(long time) { public float getStageProgress(@Nullable World world) {
return (time % duration) / (float)duration; if (world == null) {
return 0;
}
float skyAngle = MeteorlogicalUtil.getSkyAngle(world);
float dayProgress = ((skyAngle + 1.5F) % 3F) / 3F;
if (this == HIBERNATING) {
return (world.getMoonPhase() + dayProgress) / MOON_PHASES;
}
return dayProgress;
} }
public float getCycleProgress(long time) { public float getCycleProgress(@Nullable World world) {
float ordinal = ordinal(); return MathHelper.lerp(getStageProgress(world), ordinal, ordinal + 1) / MAX;
return MathHelper.lerp(getStageProgress(time), ordinal, ordinal + 1) / 5F;
} }
public static Stage byId(int id) { public static Stage byId(int id) {

View file

@ -12,6 +12,15 @@ import net.minecraft.world.LightType;
import net.minecraft.world.World; import net.minecraft.world.World;
public interface MeteorlogicalUtil { public interface MeteorlogicalUtil {
float SUNRISE = 0;
float NOON = 0.5F;
float SUNSET = 1;
float MIDNIGHT = 1.5F;
float MOONSET = 2;
static boolean isBetween(float skyAngle, float start, float end) {
return skyAngle >= start && skyAngle <= end;
}
static boolean isLookingIntoSun(World world, Entity entity) { static boolean isLookingIntoSun(World world, Entity entity) {
@ -52,7 +61,7 @@ public interface MeteorlogicalUtil {
static float getSunIntensity(World world) { static float getSunIntensity(World world) {
float skyAngle = getSkyAngle(world); float skyAngle = getSkyAngle(world);
if (skyAngle > 1) { if (skyAngle > SUNSET) {
return 0; return 0;
} }
@ -69,7 +78,21 @@ public interface MeteorlogicalUtil {
return intensity; return intensity;
} }
// we translate sun angle to a scale of 0-1 (0=sunrise, 1=sunset, >1 nighttime) /**
* Gets the sun angle on a scale of 0-2 where 0=sunrise, 1=sunset, and >1 is night
*
* 0 = sunrisde
* 0-0.5 = morning
* 0.5 = noon
* 0.5-1 = evening
* 1 = sunset
* 1-1.5 = night
* 1.5 = midnight
* 1.5-0 = night
*
* @param world
* @return The sun angle
*/
static float getSkyAngle(World world) { static float getSkyAngle(World world) {
return ((world.getSkyAngle(1) + 0.25F) % 1F) * 2; return ((world.getSkyAngle(1) + 0.25F) % 1F) * 2;
} }