From 886c110eb6257be79db3e212fa9853ef5cbed2fd Mon Sep 17 00:00:00 2001 From: Ian1337 Date: Thu, 16 Jul 2026 11:43:01 +0200 Subject: [PATCH] test Skyblock --- .../ovh/glitchlabs/ornamentum/Ornamentum.java | 11 ++ .../ornamentum/blocks/ModBlocks.java | 13 +- .../ornamentum/blocks/SkyboxBlock.java | 49 ++++++ .../blocks/entity/ModBlockEntities.java | 23 +++ .../blocks/entity/SkyboxBlockEntity.java | 160 ++++++++++++++++++ .../client/ClientSkyboxTracker.java | 70 ++++++++ .../ornamentum/client/ModSkyboxRenderer.java | 115 +++++++++++++ .../client/SkyboxSphereBuilder.java | 69 ++++++++ .../ornamentum/client/gui/SkyboxScreen.java | 69 ++++++++ .../datagen/ModBlockLootTableProvider.java | 3 + .../datagen/ModBlockStateProvider.java | 3 + .../ornamentum/menu/ModMenuTypes.java | 22 +++ .../ornamentum/menu/SkyboxMenu.java | 53 ++++++ .../ornamentum/network/ModNetworking.java | 36 ++++ .../network/SkyboxSettingsPayload.java | 30 ++++ 15 files changed, 722 insertions(+), 4 deletions(-) create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/blocks/SkyboxBlock.java create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/blocks/entity/ModBlockEntities.java create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/blocks/entity/SkyboxBlockEntity.java create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/client/ClientSkyboxTracker.java create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/client/ModSkyboxRenderer.java create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/client/SkyboxSphereBuilder.java create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/client/gui/SkyboxScreen.java create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/menu/ModMenuTypes.java create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/menu/SkyboxMenu.java create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/network/ModNetworking.java create mode 100644 src/main/java/ovh/glitchlabs/ornamentum/network/SkyboxSettingsPayload.java diff --git a/src/main/java/ovh/glitchlabs/ornamentum/Ornamentum.java b/src/main/java/ovh/glitchlabs/ornamentum/Ornamentum.java index cc10301..19c1942 100644 --- a/src/main/java/ovh/glitchlabs/ornamentum/Ornamentum.java +++ b/src/main/java/ovh/glitchlabs/ornamentum/Ornamentum.java @@ -33,8 +33,10 @@ import net.neoforged.neoforge.registries.DeferredItem; import net.neoforged.neoforge.registries.DeferredRegister; import org.slf4j.Logger; import ovh.glitchlabs.ornamentum.blocks.ModBlocks; +import ovh.glitchlabs.ornamentum.blocks.entity.ModBlockEntities; import ovh.glitchlabs.ornamentum.items.ModCreativeModeTabs; import ovh.glitchlabs.ornamentum.items.ModItems; +import ovh.glitchlabs.ornamentum.menu.ModMenuTypes; // The value here should match an entry in the META-INF/neoforge.mods.toml file @Mod(Ornamentum.MODID) @@ -53,6 +55,9 @@ public class Ornamentum { ModItems.register(modEventBus); ModCreativeModeTabs.register(modEventBus); + ModBlockEntities.register(modEventBus); + ModMenuTypes.register(modEventBus); + // Register the commonSetup method for modloading modEventBus.addListener(this::commonSetup); @@ -97,6 +102,12 @@ public class Ornamentum { // Register render types for glow glass blocks registerGlassRenderTypes(); registerGrateRenderTypes(); + + } + + @SubscribeEvent + public static void onRegisterScreens(net.neoforged.neoforge.client.event.RegisterMenuScreensEvent event) { + event.register(ModMenuTypes.SKYBOX_MENU.get(), ovh.glitchlabs.ornamentum.client.gui.SkyboxScreen::new); } private static void registerGlassRenderTypes() { diff --git a/src/main/java/ovh/glitchlabs/ornamentum/blocks/ModBlocks.java b/src/main/java/ovh/glitchlabs/ornamentum/blocks/ModBlocks.java index 434e034..b7b7334 100644 --- a/src/main/java/ovh/glitchlabs/ornamentum/blocks/ModBlocks.java +++ b/src/main/java/ovh/glitchlabs/ornamentum/blocks/ModBlocks.java @@ -2,16 +2,15 @@ package ovh.glitchlabs.ornamentum.blocks; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.StairBlock; +import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockBehaviour; import net.neoforged.bus.api.IEventBus; import net.neoforged.neoforge.registries.DeferredBlock; import net.neoforged.neoforge.registries.DeferredRegister; import ovh.glitchlabs.ornamentum.Ornamentum; import ovh.glitchlabs.ornamentum.items.ModItems; +import ovh.glitchlabs.ornamentum.blocks.SkyboxBlock; + import java.util.function.Supplier; @@ -19,6 +18,12 @@ public class ModBlocks { public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(Ornamentum.MODID); + public static final DeferredBlock SKYBOX_BLOCK = registerBlock("skybox_block", + () -> new SkyboxBlock(BlockBehaviour.Properties.of() + .strength(3.0f) + .sound(SoundType.AMETHYST) + .lightLevel(state -> 7))); + //more bricks diff --git a/src/main/java/ovh/glitchlabs/ornamentum/blocks/SkyboxBlock.java b/src/main/java/ovh/glitchlabs/ornamentum/blocks/SkyboxBlock.java new file mode 100644 index 0000000..d1339f4 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/blocks/SkyboxBlock.java @@ -0,0 +1,49 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/block/SkyboxBlock.java +package ovh.glitchlabs.ornamentum.blocks; + +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.Nullable; +import ovh.glitchlabs.ornamentum.blocks.entity.SkyboxBlockEntity; + +public class SkyboxBlock extends BaseEntityBlock { + + public static final MapCodec CODEC = simpleCodec(SkyboxBlock::new); + + public SkyboxBlock(BlockBehaviour.Properties properties) { + super(properties); + } + + @Override + protected MapCodec codec() { + return CODEC; + } + + @Override + public RenderShape getRenderShape(BlockState state) { + return RenderShape.MODEL; + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + return new SkyboxBlockEntity(pos, state); + } + + @Override + protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) { + if (!level.isClientSide() && level.getBlockEntity(pos) instanceof SkyboxBlockEntity be) { + player.openMenu(be, buf -> buf.writeBlockPos(pos)); + } + return InteractionResult.SUCCESS; + } +} \ No newline at end of file diff --git a/src/main/java/ovh/glitchlabs/ornamentum/blocks/entity/ModBlockEntities.java b/src/main/java/ovh/glitchlabs/ornamentum/blocks/entity/ModBlockEntities.java new file mode 100644 index 0000000..012d357 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/blocks/entity/ModBlockEntities.java @@ -0,0 +1,23 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/block/entity/ModBlockEntities.java +package ovh.glitchlabs.ornamentum.blocks.entity; + +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; +import ovh.glitchlabs.ornamentum.Ornamentum; +import ovh.glitchlabs.ornamentum.blocks.ModBlocks; + +public class ModBlockEntities { + public static final DeferredRegister> BLOCK_ENTITY_TYPES = + DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, Ornamentum.MODID); + + public static final DeferredHolder, BlockEntityType> SKYBOX_BLOCK_ENTITY = + BLOCK_ENTITY_TYPES.register("skybox_block_entity", + () -> BlockEntityType.Builder.of(SkyboxBlockEntity::new, ModBlocks.SKYBOX_BLOCK.get()).build(null)); + + public static void register(IEventBus bus) { + BLOCK_ENTITY_TYPES.register(bus); + } +} diff --git a/src/main/java/ovh/glitchlabs/ornamentum/blocks/entity/SkyboxBlockEntity.java b/src/main/java/ovh/glitchlabs/ornamentum/blocks/entity/SkyboxBlockEntity.java new file mode 100644 index 0000000..ee9fcf8 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/blocks/entity/SkyboxBlockEntity.java @@ -0,0 +1,160 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/block/entity/SkyboxBlockEntity.java +package ovh.glitchlabs.ornamentum.blocks.entity; + +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.util.Mth; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ContainerData; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.core.BlockPos; +import ovh.glitchlabs.ornamentum.client.ClientSkyboxTracker; +import ovh.glitchlabs.ornamentum.menu.SkyboxMenu; + +public class SkyboxBlockEntity extends BlockEntity implements MenuProvider { + + private int range = 48; + private int colorIndex = 0; + private boolean starsEnabled = true; + private int texturePreset = 0; + + private final ContainerData data = new ContainerData() { + @Override + public int get(int index) { + return switch (index) { + case 0 -> range; + case 1 -> colorIndex; + case 2 -> starsEnabled ? 1 : 0; + case 3 -> texturePreset; + default -> 0; + }; + } + + @Override + public void set(int index, int value) { + switch (index) { + case 0 -> range = value; + case 1 -> colorIndex = value; + case 2 -> starsEnabled = value != 0; + case 3 -> texturePreset = value; + } + } + + @Override + public int getCount() { + return 4; + } + }; + + public SkyboxBlockEntity(BlockPos pos, BlockState state) { + super(ModBlockEntities.SKYBOX_BLOCK_ENTITY.get(), pos, state); + } + + public int getRange() { + return range; + } + + public int getColorIndex() { + return colorIndex; + } + + public boolean isStarsEnabled() { + return starsEnabled; + } + + public int getTexturePreset() { + return texturePreset; + } + + public void setRange(int value) { + this.range = Mth.clamp(value, 8, 128); + syncToClient(); + } + + public void setColorIndex(int value) { + this.colorIndex = value; + syncToClient(); + } + + public void setStarsEnabled(boolean value) { + this.starsEnabled = value; + syncToClient(); + } + + public void setTexturePreset(int value) { + this.texturePreset = value; + syncToClient(); + } + + private void syncToClient() { + setChanged(); + if (level != null && !level.isClientSide()) { + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); + } + } + + @Override + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.saveAdditional(tag, registries); + tag.putInt("Range", range); + tag.putInt("ColorIndex", colorIndex); + tag.putBoolean("StarsEnabled", starsEnabled); + tag.putInt("TexturePreset", texturePreset); + } + + @Override + protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { + super.loadAdditional(tag, registries); + range = tag.getInt("Range"); + colorIndex = tag.getInt("ColorIndex"); + starsEnabled = tag.getBoolean("StarsEnabled"); + texturePreset = tag.getInt("TexturePreset"); + } + + @Override + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + CompoundTag tag = new CompoundTag(); + saveAdditional(tag, registries); + return tag; + } + + @Override + public ClientboundBlockEntityDataPacket getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this); + } + + @Override + public Component getDisplayName() { + return Component.translatable("block.ornamentum.skybox_block"); + } + + @Override + public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) { + return new SkyboxMenu(containerId, playerInventory, this, this.data); + } + + @Override + public void onLoad() { + super.onLoad(); + // Nur der physische Client betritt diesen Zweig, da level.isClientSide() auf dem + // dedizierten Server immer false ist -> ClientSkyboxTracker wird dort nie geladen. + if (level != null && level.isClientSide()) { + ClientSkyboxTracker.register(getBlockPos()); + } + } + + @Override + public void setRemoved() { + super.setRemoved(); + if (level != null && level.isClientSide()) { + ClientSkyboxTracker.unregister(getBlockPos()); + } + } +} diff --git a/src/main/java/ovh/glitchlabs/ornamentum/client/ClientSkyboxTracker.java b/src/main/java/ovh/glitchlabs/ornamentum/client/ClientSkyboxTracker.java new file mode 100644 index 0000000..3d06455 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/client/ClientSkyboxTracker.java @@ -0,0 +1,70 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/client/ClientSkyboxTracker.java +package ovh.glitchlabs.ornamentum.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import ovh.glitchlabs.ornamentum.blocks.entity.SkyboxBlockEntity; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class ClientSkyboxTracker { + + private static final Set POSITIONS = ConcurrentHashMap.newKeySet(); + private static final int FADE_DISTANCE = 12; + + public static void register(BlockPos pos) { + POSITIONS.add(pos); + } + + public static void unregister(BlockPos pos) { + POSITIONS.remove(pos); + } + + /** + * Bündelt alle für das Rendering relevanten Werte des aktuell "gewinnenden" + * (nächstgelegenen, aktivsten) Skybox-Blocks. + */ + public record ActiveSkybox(float blend, int colorIndex, boolean starsEnabled, int texturePreset) { + } + + /** + * @return null, wenn kein Skybox-Block in Reichweite ist, sonst die Werte + * des Blocks mit dem stärksten Überblend-Faktor. + */ + public static ActiveSkybox getActive() { + LocalPlayer player = Minecraft.getInstance().player; + ClientLevel level = Minecraft.getInstance().level; + if (player == null || level == null || POSITIONS.isEmpty()) { + return null; + } + + ActiveSkybox best = null; + float bestBlend = 0f; + + for (BlockPos pos : POSITIONS) { + if (!(level.getBlockEntity(pos) instanceof SkyboxBlockEntity be)) { + continue; + } + + double dist = Math.sqrt(player.blockPosition().distSqr(pos)); + int range = be.getRange(); + if (dist >= range) { + continue; + } + + float blend = dist <= range - FADE_DISTANCE + ? 1f + : (float) ((range - dist) / FADE_DISTANCE); + + if (blend > bestBlend) { + bestBlend = blend; + best = new ActiveSkybox(blend, be.getColorIndex(), be.isStarsEnabled(), be.getTexturePreset()); + } + } + + return best; + } +} diff --git a/src/main/java/ovh/glitchlabs/ornamentum/client/ModSkyboxRenderer.java b/src/main/java/ovh/glitchlabs/ornamentum/client/ModSkyboxRenderer.java new file mode 100644 index 0000000..619ceba --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/client/ModSkyboxRenderer.java @@ -0,0 +1,115 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/client/ModSkyboxRenderer.java +package ovh.glitchlabs.ornamentum.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexBuffer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RenderLevelStageEvent; +import org.joml.Matrix4f; +import ovh.glitchlabs.ornamentum.Ornamentum; + +@EventBusSubscriber(modid = Ornamentum.MODID, value = Dist.CLIENT) +public class ModSkyboxRenderer { + + // Ein Preset pro Index aus dem GUI ("Textur wechseln"). Lege die passenden + // PNGs unter assets/ornamentum/textures/sky/ ab (equirektangulare Panoramen). + private static final ResourceLocation[] SKY_TEXTURES = { + ResourceLocation.fromNamespaceAndPath(Ornamentum.MODID, "textures/sky/custom_sky_0.png"), + ResourceLocation.fromNamespaceAndPath(Ornamentum.MODID, "textures/sky/custom_sky_1.png"), + ResourceLocation.fromNamespaceAndPath(Ornamentum.MODID, "textures/sky/custom_sky_2.png"), + ResourceLocation.fromNamespaceAndPath(Ornamentum.MODID, "textures/sky/custom_sky_3.png") + }; + + private static final ResourceLocation STARS_TEXTURE = + ResourceLocation.fromNamespaceAndPath(Ornamentum.MODID, "textures/sky/custom_stars.png"); + + // r, g, b pro Farb-Preset (Index = colorIndex aus dem GUI, "Farbe wechseln") + private static final float[][] COLOR_PRESETS = { + {0.55f, 0.75f, 1.00f}, // Blau + {0.65f, 0.45f, 0.85f}, // Lila + {1.00f, 0.60f, 0.30f}, // Orange + {0.40f, 0.85f, 0.45f}, // Grün + {0.90f, 0.30f, 0.30f}, // Rot + {0.30f, 0.80f, 0.80f} // Türkis + }; + + private static VertexBuffer skySphere; + private static VertexBuffer starSphere; + + @SubscribeEvent + public static void onRenderSky(RenderLevelStageEvent event) { + if (event.getStage() != RenderLevelStageEvent.Stage.AFTER_SKY) { + return; + } + + ClientSkyboxTracker.ActiveSkybox active = ClientSkyboxTracker.getActive(); + if (active == null || active.blend() <= 0f) { + return; + } + + if (skySphere == null) { + skySphere = SkyboxSphereBuilder.buildSphere(16, 16, 100f); + } + if (starSphere == null) { + starSphere = SkyboxSphereBuilder.buildSphere(16, 16, 90f); + } + + ClientLevel level = Minecraft.getInstance().level; + if (level == null) { + return; + } + + long dayTime = level.getDayTime() % 24000; + boolean isNight = dayTime > 13000 && dayTime < 23000; + float partialTick = event.getPartialTick().getGameTimeDeltaPartialTick(true); + float starVisibility = level.getStarBrightness(partialTick); + + float[] color = COLOR_PRESETS[active.colorIndex() % COLOR_PRESETS.length]; + float darken = isNight ? 0.25f : 1.0f; + + PoseStack poseStack = event.getPoseStack(); + if (poseStack == null) { + return; + } + poseStack.pushPose(); + + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.depthMask(false); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + + Matrix4f mvMatrix = new Matrix4f(poseStack.last().pose()); + Matrix4f projMatrix = event.getProjectionMatrix(); + + // 1) Basis-Himmelskugel mit gewählter Textur + Farbton + RenderSystem.setShaderColor(color[0] * darken, color[1] * darken, color[2] * darken, active.blend()); + RenderSystem.setShaderTexture(0, SKY_TEXTURES[active.texturePreset() % SKY_TEXTURES.length]); + skySphere.bind(); + skySphere.drawWithShader(mvMatrix, projMatrix, RenderSystem.getShader()); + + // 2) Sterne-Overlay, nur wenn im GUI aktiviert + es dunkel genug ist + if (active.starsEnabled()) { + float starAlpha = starVisibility * active.blend(); + if (starAlpha > 0.01f) { + RenderSystem.setShaderColor(1f, 1f, 1f, starAlpha); + RenderSystem.setShaderTexture(0, STARS_TEXTURE); + starSphere.bind(); + starSphere.drawWithShader(mvMatrix, projMatrix, RenderSystem.getShader()); + } + } + + VertexBuffer.unbind(); + RenderSystem.setShaderColor(1f, 1f, 1f, 1f); + RenderSystem.depthMask(true); + RenderSystem.disableBlend(); + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/ovh/glitchlabs/ornamentum/client/SkyboxSphereBuilder.java b/src/main/java/ovh/glitchlabs/ornamentum/client/SkyboxSphereBuilder.java new file mode 100644 index 0000000..717301a --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/client/SkyboxSphereBuilder.java @@ -0,0 +1,69 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/client/SkyboxSphereBuilder.java +package ovh.glitchlabs.ornamentum.client; + +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.MeshData; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexBuffer; +import com.mojang.blaze3d.vertex.VertexFormat; +import org.joml.Vector3f; + +/** + * Baut eine einfache UV-gemappte Kugel als VertexBuffer, die per RenderSystem + * mit einer equirektangularen Panorama-Textur bezogen werden kann. + * + * Hinweis: Die genaue BufferBuilder/Tesselator-API kann sich zwischen NeoForge- + * Patch-Versionen leicht unterscheiden (1.21.x hat die Vertex-Pipeline mehrfach + * überarbeitet). Falls dein Compiler hier meckert, sag Bescheid mit der genauen + * Fehlermeldung - meist reicht eine kleine Anpassung der Methodennamen. + */ +public class SkyboxSphereBuilder { + + public static VertexBuffer buildSphere(int rings, int segments, float radius) { + BufferBuilder builder = Tesselator.getInstance().begin( + VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_TEX); + + for (int r = 0; r < rings; r++) { + float theta1 = (float) (r * Math.PI / rings); + float theta2 = (float) ((r + 1) * Math.PI / rings); + + for (int s = 0; s < segments; s++) { + float phi1 = (float) (s * 2 * Math.PI / segments); + float phi2 = (float) ((s + 1) * 2 * Math.PI / segments); + + Vector3f p1 = sphericalToCartesian(theta1, phi1, radius); + Vector3f p2 = sphericalToCartesian(theta2, phi1, radius); + Vector3f p3 = sphericalToCartesian(theta2, phi2, radius); + Vector3f p4 = sphericalToCartesian(theta1, phi2, radius); + + float u1 = (float) s / segments; + float u2 = (float) (s + 1) / segments; + float v1 = (float) r / rings; + float v2 = (float) (r + 1) / rings; + + builder.addVertex(p1.x, p1.y, p1.z).setUv(u1, v1); + builder.addVertex(p2.x, p2.y, p2.z).setUv(u1, v2); + builder.addVertex(p3.x, p3.y, p3.z).setUv(u2, v2); + + builder.addVertex(p1.x, p1.y, p1.z).setUv(u1, v1); + builder.addVertex(p3.x, p3.y, p3.z).setUv(u2, v2); + builder.addVertex(p4.x, p4.y, p4.z).setUv(u2, v1); + } + } + + MeshData mesh = builder.buildOrThrow(); + VertexBuffer buffer = new VertexBuffer(VertexBuffer.Usage.STATIC); + buffer.bind(); + buffer.upload(mesh); + VertexBuffer.unbind(); + return buffer; + } + + private static Vector3f sphericalToCartesian(float theta, float phi, float radius) { + float x = (float) (radius * Math.sin(theta) * Math.cos(phi)); + float y = (float) (radius * Math.cos(theta)); + float z = (float) (radius * Math.sin(theta) * Math.sin(phi)); + return new Vector3f(x, y, z); + } +} diff --git a/src/main/java/ovh/glitchlabs/ornamentum/client/gui/SkyboxScreen.java b/src/main/java/ovh/glitchlabs/ornamentum/client/gui/SkyboxScreen.java new file mode 100644 index 0000000..cd33ef1 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/client/gui/SkyboxScreen.java @@ -0,0 +1,69 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/client/gui/SkyboxScreen.java +package ovh.glitchlabs.ornamentum.client.gui; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.network.PacketDistributor; +import ovh.glitchlabs.ornamentum.Ornamentum; +import ovh.glitchlabs.ornamentum.menu.SkyboxMenu; +import ovh.glitchlabs.ornamentum.network.SkyboxSettingsPayload; +import net.minecraft.world.entity.player.Inventory; + +public class SkyboxScreen extends AbstractContainerScreen { + + private static final ResourceLocation BG_TEXTURE = + ResourceLocation.fromNamespaceAndPath(Ornamentum.MODID, "textures/gui/skybox_gui.png"); + + private static final String[] COLOR_NAMES = {"Blau", "Lila", "Orange", "Grün", "Rot", "Türkis"}; + private static final String[] TEXTURE_NAMES = {"Standard", "Nebel", "Sterne+", "Aurora"}; + + public SkyboxScreen(SkyboxMenu menu, Inventory inventory, Component title) { + super(menu, inventory, title); + this.imageWidth = 176; + this.imageHeight = 166; + this.inventoryLabelY = 10000; // Standard-Inventar-Label ausblenden (kein Spieler-Inventar im GUI) + } + + @Override + protected void init() { + super.init(); + int x = leftPos; + int y = topPos; + + addRenderableWidget(Button.builder(Component.literal("-8"), b -> sendChange(0, -8)) + .bounds(x + 20, y + 20, 30, 20).build()); + addRenderableWidget(Button.builder(Component.literal("+8"), b -> sendChange(0, 8)) + .bounds(x + 126, y + 20, 30, 20).build()); + + addRenderableWidget(Button.builder(Component.literal("Farbe wechseln"), b -> sendChange(1, 1)) + .bounds(x + 20, y + 50, 136, 20).build()); + + addRenderableWidget(Button.builder(Component.literal("Sterne umschalten"), b -> sendChange(2, 0)) + .bounds(x + 20, y + 80, 136, 20).build()); + + addRenderableWidget(Button.builder(Component.literal("Textur wechseln"), b -> sendChange(3, 1)) + .bounds(x + 20, y + 110, 136, 20).build()); + } + + private void sendChange(int field, int delta) { + PacketDistributor.sendToServer(new SkyboxSettingsPayload( + menu.getBlockEntity().getBlockPos(), field, delta)); + } + + @Override + protected void renderBg(GuiGraphics guiGraphics, float partialTick, int mouseX, int mouseY) { + guiGraphics.blit(BG_TEXTURE, leftPos, topPos, 0, 0, imageWidth, imageHeight); + } + + @Override + protected void renderLabels(GuiGraphics guiGraphics, int mouseX, int mouseY) { + var data = menu.getData(); + guiGraphics.drawString(font, "Reichweite: " + data.get(0), 20, 8, 0x404040, false); + guiGraphics.drawString(font, "Farbe: " + COLOR_NAMES[data.get(1) % COLOR_NAMES.length], 20, 38, 0x404040, false); + guiGraphics.drawString(font, "Sterne: " + (data.get(2) != 0 ? "An" : "Aus"), 20, 68, 0x404040, false); + guiGraphics.drawString(font, "Textur: " + TEXTURE_NAMES[data.get(3) % TEXTURE_NAMES.length], 20, 98, 0x404040, false); + } +} diff --git a/src/main/java/ovh/glitchlabs/ornamentum/datagen/ModBlockLootTableProvider.java b/src/main/java/ovh/glitchlabs/ornamentum/datagen/ModBlockLootTableProvider.java index 9595beb..50197f9 100644 --- a/src/main/java/ovh/glitchlabs/ornamentum/datagen/ModBlockLootTableProvider.java +++ b/src/main/java/ovh/glitchlabs/ornamentum/datagen/ModBlockLootTableProvider.java @@ -16,6 +16,9 @@ public class ModBlockLootTableProvider extends BlockLootSubProvider { @Override protected void generate() { + + dropSelf(ModBlocks.SKYBOX_BLOCK.get()); + dropSelf(ModBlocks.POOL_TILES.get()); dropSelf(ModBlocks.POOL_TILES1.get()); diff --git a/src/main/java/ovh/glitchlabs/ornamentum/datagen/ModBlockStateProvider.java b/src/main/java/ovh/glitchlabs/ornamentum/datagen/ModBlockStateProvider.java index 0c74418..682dd4f 100644 --- a/src/main/java/ovh/glitchlabs/ornamentum/datagen/ModBlockStateProvider.java +++ b/src/main/java/ovh/glitchlabs/ornamentum/datagen/ModBlockStateProvider.java @@ -15,6 +15,9 @@ public class ModBlockStateProvider extends BlockStateProvider { @Override protected void registerStatesAndModels() { + + blockWithItem(ModBlocks.SKYBOX_BLOCK); + blockWithItem(ModBlocks.POOL_TILES); blockWithItem(ModBlocks.POOL_TILES1); diff --git a/src/main/java/ovh/glitchlabs/ornamentum/menu/ModMenuTypes.java b/src/main/java/ovh/glitchlabs/ornamentum/menu/ModMenuTypes.java new file mode 100644 index 0000000..962e708 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/menu/ModMenuTypes.java @@ -0,0 +1,22 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/menu/ModMenuTypes.java +package ovh.glitchlabs.ornamentum.menu; + +import net.minecraft.core.registries.Registries; +import net.minecraft.world.inventory.MenuType; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.common.extensions.IMenuTypeExtension; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; +import ovh.glitchlabs.ornamentum.Ornamentum; + +public class ModMenuTypes { + public static final DeferredRegister> MENU_TYPES = + DeferredRegister.create(Registries.MENU, Ornamentum.MODID); + + public static final DeferredHolder, MenuType> SKYBOX_MENU = + MENU_TYPES.register("skybox_menu", () -> IMenuTypeExtension.create(SkyboxMenu::new)); + + public static void register(IEventBus bus) { + MENU_TYPES.register(bus); + } +} diff --git a/src/main/java/ovh/glitchlabs/ornamentum/menu/SkyboxMenu.java b/src/main/java/ovh/glitchlabs/ornamentum/menu/SkyboxMenu.java new file mode 100644 index 0000000..051a736 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/menu/SkyboxMenu.java @@ -0,0 +1,53 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/menu/SkyboxMenu.java +package ovh.glitchlabs.ornamentum.menu; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ContainerData; +import net.minecraft.world.inventory.SimpleContainerData; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec3; +import ovh.glitchlabs.ornamentum.blocks.entity.SkyboxBlockEntity; + +public class SkyboxMenu extends AbstractContainerMenu { + + private final SkyboxBlockEntity blockEntity; + private final ContainerData data; + + // Wird beim Client-seitigen Öffnen des Menüs aufgerufen (über ModMenuTypes / IMenuTypeExtension) + public SkyboxMenu(int containerId, Inventory inv, RegistryFriendlyByteBuf buf) { + this(containerId, inv, + (SkyboxBlockEntity) inv.player.level().getBlockEntity(buf.readBlockPos()), + new SimpleContainerData(4)); + } + + // Wird server- und clientseitig verwendet (die echte BlockEntity liefert die Daten) + public SkyboxMenu(int containerId, Inventory inv, SkyboxBlockEntity blockEntity, ContainerData data) { + super(ModMenuTypes.SKYBOX_MENU.get(), containerId); + this.blockEntity = blockEntity; + this.data = data; + addDataSlots(data); + } + + public SkyboxBlockEntity getBlockEntity() { + return blockEntity; + } + + public ContainerData getData() { + return data; + } + + @Override + public boolean stillValid(Player player) { + return blockEntity != null && !blockEntity.isRemoved() + && player.distanceToSqr(Vec3.atCenterOf(blockEntity.getBlockPos())) < 64.0; + } + + @Override + public ItemStack quickMoveStack(Player player, int index) { + // Kein Inventar in diesem Menü - keine Item-Slots zu verschieben. + return ItemStack.EMPTY; + } +} diff --git a/src/main/java/ovh/glitchlabs/ornamentum/network/ModNetworking.java b/src/main/java/ovh/glitchlabs/ornamentum/network/ModNetworking.java new file mode 100644 index 0000000..dbc0b09 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/network/ModNetworking.java @@ -0,0 +1,36 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/network/ModNetworking.java +package ovh.glitchlabs.ornamentum.network; + +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; +import ovh.glitchlabs.ornamentum.Ornamentum; +import ovh.glitchlabs.ornamentum.blocks.entity.SkyboxBlockEntity; + +@EventBusSubscriber(modid = Ornamentum.MODID, bus = EventBusSubscriber.Bus.MOD) +public class ModNetworking { + + @SubscribeEvent + public static void register(RegisterPayloadHandlersEvent event) { + PayloadRegistrar registrar = event.registrar("1"); + registrar.playToServer(SkyboxSettingsPayload.TYPE, SkyboxSettingsPayload.STREAM_CODEC, + ModNetworking::handleSkyboxSettings); + } + + private static void handleSkyboxSettings(SkyboxSettingsPayload payload, IPayloadContext context) { + context.enqueueWork(() -> { + if (!(context.player().level().getBlockEntity(payload.pos()) instanceof SkyboxBlockEntity be)) { + return; + } + + switch (payload.field()) { + case 0 -> be.setRange(be.getRange() + payload.delta()); + case 1 -> be.setColorIndex((be.getColorIndex() + 1) % 6); + case 2 -> be.setStarsEnabled(!be.isStarsEnabled()); + case 3 -> be.setTexturePreset((be.getTexturePreset() + 1) % 4); + } + }); + } +} diff --git a/src/main/java/ovh/glitchlabs/ornamentum/network/SkyboxSettingsPayload.java b/src/main/java/ovh/glitchlabs/ornamentum/network/SkyboxSettingsPayload.java new file mode 100644 index 0000000..7153193 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/ornamentum/network/SkyboxSettingsPayload.java @@ -0,0 +1,30 @@ +// Zielpfad: src/main/java/ovh/glitchlabs/ornamentum/network/SkyboxSettingsPayload.java +package ovh.glitchlabs.ornamentum.network; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import ovh.glitchlabs.ornamentum.Ornamentum; + +// field: 0 = range (+delta), 1 = colorIndex (+1 zum Weiterschalten), 2 = starsEnabled (toggle, delta ignoriert), +// 3 = texturePreset (+1 zum Weiterschalten) +public record SkyboxSettingsPayload(BlockPos pos, int field, int delta) implements CustomPacketPayload { + + public static final Type TYPE = + new Type<>(ResourceLocation.fromNamespaceAndPath(Ornamentum.MODID, "skybox_settings")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, SkyboxSettingsPayload::pos, + ByteBufCodecs.VAR_INT, SkyboxSettingsPayload::field, + ByteBufCodecs.VAR_INT, SkyboxSettingsPayload::delta, + SkyboxSettingsPayload::new + ); + + @Override + public Type type() { + return TYPE; + } +}