Apply Age celestial angles
Build / build (push) Canceled after 0s

This commit is contained in:
dnorberg committed 2026-09-22 22:33:11 -04:00
1 parent 88af167f62
commit 08caa98c0b
10 files changed
+163 -4

No files matched your search

@@ -9,6 +9,7 @@ import net.dnorberg.rivencraft.registry.ModBlocks;
import net.dnorberg.rivencraft.registry.ModBlockEntities;
import net.dnorberg.rivencraft.registry.ModBiomeSources;
import net.dnorberg.rivencraft.event.BookStandConversionHandler;
import net.dnorberg.rivencraft.event.AgeCelestialAngleSync;
import net.dnorberg.rivencraft.network.ModNetworking;
import net.dnorberg.rivencraft.config.RivencraftConfig;
import net.dnorberg.rivencraft.config.RivencraftClientConfig;
@@ -40,6 +41,8 @@ public final class Rivencraft {
ModCreativeTabs.register(modEventBus);
NeoForge.EVENT_BUS.addListener(BookStandConversionHandler::onRightClickBlock);
NeoForge.EVENT_BUS.addListener(AgeWeatherService::onLevelTickPost);
NeoForge.EVENT_BUS.addListener(AgeCelestialAngleSync::onPlayerLoggedIn);
NeoForge.EVENT_BUS.addListener(AgeCelestialAngleSync::onPlayerChangedDimension);
LOGGER.info("Initializing Rivencraft");
}
}
@@ -0,0 +1,24 @@
package net.dnorberg.rivencraft.client;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.dnorberg.rivencraft.network.AgeCelestialAnglePayload;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
import net.neoforged.neoforge.network.handling.IPayloadContext;
/** Client cache used by both the active world and remote preview renderers. */
public final class ClientAgeCelestialAngles {
private static final Map<ResourceKey<Level>, Float> ANGLES = new ConcurrentHashMap<>();
private ClientAgeCelestialAngles() {
}
public static void handle(AgeCelestialAnglePayload payload, IPayloadContext context) {
ANGLES.put(payload.dimension(), payload.angle());
}
public static float get(ResourceKey<Level> dimension) {
return ANGLES.getOrDefault(dimension, 0.0F);
}
}
@@ -0,0 +1,43 @@
package net.dnorberg.rivencraft.event;
import net.dnorberg.rivencraft.book.AgeDefinition;
import net.dnorberg.rivencraft.book.AgeDimensionService;
import net.dnorberg.rivencraft.book.AgeRegistrySavedData;
import net.dnorberg.rivencraft.network.AgeCelestialAnglePayload;
import net.minecraft.server.level.ServerPlayer;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.network.PacketDistributor;
import net.neoforged.neoforge.network.registration.NetworkRegistry;
/** Sends saved celestial angles when a client joins or enters an Age. */
public final class AgeCelestialAngleSync {
private AgeCelestialAngleSync() {
}
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
if (!(event.getEntity() instanceof ServerPlayer player)) {
return;
}
for (AgeDefinition age : AgeRegistrySavedData.get(player.serverLevel()).definitions()) {
send(player, age);
}
}
public static void onPlayerChangedDimension(PlayerEvent.PlayerChangedDimensionEvent event) {
if (!(event.getEntity() instanceof ServerPlayer player)) {
return;
}
AgeRegistrySavedData.get(player.serverLevel()).definitions().stream()
.filter(age -> AgeDimensionService.dimensionKey(age).equals(event.getTo()))
.findFirst()
.ifPresent(age -> send(player, age));
}
public static void send(ServerPlayer player, AgeDefinition age) {
if (!NetworkRegistry.hasChannel(player.connection, AgeCelestialAnglePayload.TYPE.id())) {
return;
}
PacketDistributor.sendToPlayer(player, new AgeCelestialAnglePayload(
AgeDimensionService.dimensionKey(age), age.traits().celestialAngle()));
}
}
@@ -0,0 +1,31 @@
package net.dnorberg.rivencraft.mixin.client;
import com.mojang.math.Axis;
import net.dnorberg.rivencraft.client.ClientAgeCelestialAngles;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer;
import org.joml.Quaternionf;
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.Redirect;
/** Tilts the vanilla sun, moon, and star plane by each Age's saved angle. */
@Mixin(LevelRenderer.class)
public abstract class LevelRendererMixin {
@Shadow
private ClientLevel level;
@Redirect(
method = "renderSky",
at = @At(
value = "INVOKE",
target = "Lcom/mojang/math/Axis;rotationDegrees(F)Lorg/joml/Quaternionf;",
ordinal = 3
)
)
private Quaternionf rivencraft$rotateCelestialPlane(Axis axis, float degrees) {
float angle = ClientAgeCelestialAngles.get(level.dimension());
return new Quaternionf(Axis.ZP.rotationDegrees(angle)).mul(axis.rotationDegrees(degrees));
}
}
@@ -0,0 +1,32 @@
package net.dnorberg.rivencraft.network;
import net.dnorberg.rivencraft.Rivencraft;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
/** Synchronizes an Age's saved celestial-plane rotation to clients. */
public record AgeCelestialAnglePayload(ResourceKey<Level> dimension, float angle)
implements CustomPacketPayload {
public static final Type<AgeCelestialAnglePayload> TYPE = new Type<>(
ResourceLocation.fromNamespaceAndPath(Rivencraft.MOD_ID, "age_celestial_angle")
);
public static final StreamCodec<RegistryFriendlyByteBuf, AgeCelestialAnglePayload> STREAM_CODEC =
StreamCodec.of(
(buffer, payload) -> {
buffer.writeResourceKey(payload.dimension());
buffer.writeFloat(payload.angle());
},
buffer -> new AgeCelestialAnglePayload(
buffer.readResourceKey(Registries.DIMENSION), buffer.readFloat())
);
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
}
@@ -8,6 +8,8 @@ import net.dnorberg.rivencraft.book.AgeDimensionService;
import net.dnorberg.rivencraft.block.entity.BookStandBlockEntity;
import net.dnorberg.rivencraft.client.ClientLinkPreviewHandler;
import net.dnorberg.rivencraft.client.ClientBookInteractionHandler;
import net.dnorberg.rivencraft.client.ClientAgeCelestialAngles;
import net.dnorberg.rivencraft.event.AgeCelestialAngleSync;
import net.dnorberg.rivencraft.item.DescriptiveBookItem;
import net.dnorberg.rivencraft.item.LinkingBookItem;
import net.dnorberg.rivencraft.registry.ModDataComponents;
@@ -46,7 +48,7 @@ public final class ModNetworking {
}
public static void register(RegisterPayloadHandlersEvent event) {
PayloadRegistrar registrar = event.registrar("8");
PayloadRegistrar registrar = event.registrar("9");
registrar.playToServer(RequestDescriptiveBookScreenPayload.TYPE, RequestDescriptiveBookScreenPayload.STREAM_CODEC,
ModNetworking::requestDescriptiveBookScreen);
registrar.playToClient(OpenDescriptiveBookScreenPayload.TYPE, OpenDescriptiveBookScreenPayload.STREAM_CODEC,
@@ -64,6 +66,8 @@ public final class ModNetworking {
(payload, context) -> releaseLinkPreview(context));
registrar.playToClient(LinkPreviewPayload.TYPE, LinkPreviewPayload.STREAM_CODEC,
ClientLinkPreviewHandler::handle);
registrar.playToClient(AgeCelestialAnglePayload.TYPE, AgeCelestialAnglePayload.STREAM_CODEC,
ClientAgeCelestialAngles::handle);
}
private static void requestDescriptiveBookScreen(RequestDescriptiveBookScreenPayload payload, IPayloadContext context) {
@@ -222,6 +226,11 @@ public final class ModNetworking {
return;
}
AgeRegistrySavedData.get(player.serverLevel()).definitions().stream()
.filter(age -> AgeDimensionService.dimensionKey(age).equals(target.location().dimension()))
.findFirst()
.ifPresent(age -> AgeCelestialAngleSync.send(player, age));
ServerLevel level = player.getServer().getLevel(target.location().dimension());
if (level == null) {
return;
+12
View File
@@ -0,0 +1,12 @@
{
"required": true,
"minVersion": "0.8",
"package": "net.dnorberg.rivencraft.mixin",
"compatibilityLevel": "JAVA_21",
"client": [
"client.LevelRendererMixin"
],
"injectors": {
"defaultRequire": 1
}
}
@@ -50,8 +50,8 @@ A spiritual successor and modern port of Mystcraft for Minecraft 1.21.1 on NeoFo
'''
# The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded.
#[[mixins]]
#config="${mod_id}.mixins.json"
[[mixins]]
config="${mod_id}.mixins.json"
# The [[accessTransformers]] block allows you to declare where your AT file is.
# If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg