From ccfe667c6dfa767f730bdfbd7891ccbea425c513 Mon Sep 17 00:00:00 2001 From: xiaoliziawa <3682822069@qq.com> Date: Thu, 19 Mar 2026 23:20:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=AA=E7=A9=BA=E7=94=B5=E6=A2=AF=E5=AF=B9?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adastra/AdAstraSpaceElevatorCompat.java | 36 +++--- .../AdAstraSpaceElevatorStationCompat.java | 91 ++++++++++++++ .../adastra/SpaceElevatorBaseHandler.java | 4 + .../adastra/SpaceElevatorLinkHandler.java | 117 ++++++++++++++++++ .../datagen/language/type/GuiLanguage.java | 8 +- .../PlanetsScreenBaseBuildClientHandler.java | 63 ++++++++-- .../BuildEarthSpaceElevatorBasePacket.java | 16 ++- .../celestiacraft/cmi/network/CmiNetwork.java | 14 +++ .../RequestSpaceElevatorBaseStatePacket.java | 51 ++++++++ .../SyncSpaceElevatorBaseStatePacket.java | 40 ++++++ 10 files changed, 401 insertions(+), 39 deletions(-) create mode 100644 src/main/java/dev/celestiacraft/cmi/compat/adastra/AdAstraSpaceElevatorStationCompat.java create mode 100644 src/main/java/dev/celestiacraft/cmi/compat/adastra/SpaceElevatorLinkHandler.java create mode 100644 src/main/java/dev/celestiacraft/cmi/network/RequestSpaceElevatorBaseStatePacket.java create mode 100644 src/main/java/dev/celestiacraft/cmi/network/SyncSpaceElevatorBaseStatePacket.java diff --git a/src/main/java/dev/celestiacraft/cmi/compat/adastra/AdAstraSpaceElevatorCompat.java b/src/main/java/dev/celestiacraft/cmi/compat/adastra/AdAstraSpaceElevatorCompat.java index 2c97164..7d1f308 100644 --- a/src/main/java/dev/celestiacraft/cmi/compat/adastra/AdAstraSpaceElevatorCompat.java +++ b/src/main/java/dev/celestiacraft/cmi/compat/adastra/AdAstraSpaceElevatorCompat.java @@ -40,8 +40,7 @@ public static void clearLastLaunchOrigin(ServerPlayer player) { } public static void recordLaunchOrigin(ServerPlayer player, BlockPos pos, ResourceKey dimension) { - ResourceKey groundDimension = normalizeGroundDimension(dimension); - if (groundDimension == null) { + if (!Level.OVERWORLD.equals(dimension)) { return; } @@ -49,7 +48,7 @@ public static void recordLaunchOrigin(ServerPlayer player, BlockPos pos, Resourc CompoundTag rootTag = persistentData.getCompound(ROOT_TAG); CompoundTag launchOriginTag = new CompoundTag(); - launchOriginTag.putString("Dimension", groundDimension.location().toString()); + launchOriginTag.putString("Dimension", dimension.location().toString()); launchOriginTag.putInt("X", pos.getX()); launchOriginTag.putInt("Y", pos.getY()); launchOriginTag.putInt("Z", pos.getZ()); @@ -63,6 +62,15 @@ public static boolean hasValidEarthLaunchOrigin(ServerPlayer player) { return launchOrigin != null && Level.OVERWORLD.equals(launchOrigin.dimension()); } + @Nullable + public static BlockPos getLastEarthLaunchOrigin(ServerPlayer player) { + LaunchOrigin launchOrigin = getLastLaunchOrigin(player); + if (launchOrigin == null || !Level.OVERWORLD.equals(launchOrigin.dimension())) { + return null; + } + return launchOrigin.pos(); + } + public static boolean buildEarthBaseFromLastLaunch(ServerPlayer player, ServerLevel orbitLevel) { if (!Planet.EARTH_ORBIT.equals(orbitLevel.dimension())) { return false; @@ -92,13 +100,13 @@ private static LaunchOrigin getLastLaunchOrigin(ServerPlayer player) { } CompoundTag launchOriginTag = rootTag.getCompound(LAST_LAUNCH_TAG); - ResourceKey dimension = readGroundDimension(launchOriginTag.getString("Dimension")); - if (dimension == null) { + String dimensionId = launchOriginTag.getString("Dimension"); + if (!Level.OVERWORLD.location().toString().equals(dimensionId)) { return null; } return new LaunchOrigin( - dimension, + Level.OVERWORLD, new BlockPos( launchOriginTag.getInt("X"), launchOriginTag.getInt("Y"), @@ -163,22 +171,6 @@ private static void placePillar(ServerLevel level, BlockPos startPos, BlockState } } - @Nullable - private static ResourceKey normalizeGroundDimension(ResourceKey dimension) { - if (Level.OVERWORLD.equals(dimension)) { - return dimension; - } - return null; - } - - @Nullable - private static ResourceKey readGroundDimension(String dimensionId) { - if (Level.OVERWORLD.location().toString().equals(dimensionId)) { - return Level.OVERWORLD; - } - return null; - } - private record LaunchOrigin(ResourceKey dimension, BlockPos pos) { } } diff --git a/src/main/java/dev/celestiacraft/cmi/compat/adastra/AdAstraSpaceElevatorStationCompat.java b/src/main/java/dev/celestiacraft/cmi/compat/adastra/AdAstraSpaceElevatorStationCompat.java new file mode 100644 index 0000000..8d30013 --- /dev/null +++ b/src/main/java/dev/celestiacraft/cmi/compat/adastra/AdAstraSpaceElevatorStationCompat.java @@ -0,0 +1,91 @@ +package dev.celestiacraft.cmi.compat.adastra; + +import earth.terrarium.adastra.api.planets.Planet; +import earth.terrarium.adastra.common.recipes.SpaceStationRecipe; +import earth.terrarium.adastra.common.registry.ModBlocks; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.RotatedPillarBlock; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; + +public class AdAstraSpaceElevatorStationCompat { + private static final int SPACE_STATION_Y = 100; + private static final int BASE_RADIUS = 4; + + private AdAstraSpaceElevatorStationCompat() { + } + + public static void decorateEarthOrbitStation(ServerLevel level, ChunkPos stationChunk) { + if (!Planet.EARTH_ORBIT.equals(level.dimension())) { + return; + } + + SpaceStationRecipe recipe = SpaceStationRecipe.getSpaceStation(level, level.dimension()).orElse(null); + if (recipe == null) { + return; + } + + StructureTemplate structure = level.getStructureManager().getOrCreate(recipe.structure()); + BlockPos stationOrigin = BlockPos.containing( + stationChunk.getMiddleBlockX() - (structure.getSize().getX() / 2.0f), + SPACE_STATION_Y, + stationChunk.getMiddleBlockZ() - (structure.getSize().getZ() / 2.0f) + ); + BlockPos anchorCenter = stationOrigin.offset(structure.getSize().getX() / 2, -1, structure.getSize().getZ() / 2); + buildMirroredGroundBase(level, anchorCenter); + SpaceElevatorLinkHandler.setOrbitAnchor(level, stationChunk, anchorCenter); + } + + private static void buildMirroredGroundBase(ServerLevel level, BlockPos centerPos) { + BlockState floorState = ModBlocks.STEEL_PLATING.get().defaultBlockState(); + BlockState centerSlabState = ModBlocks.STEEL_PLATING_SLAB.get().defaultBlockState() + .setValue(SlabBlock.TYPE, SlabType.TOP); + BlockState supportState = ModBlocks.STEEL_BLOCK.get().defaultBlockState(); + BlockState pillarState = ModBlocks.GLOWING_STEEL_PILLAR.get().defaultBlockState() + .setValue(RotatedPillarBlock.AXIS, Direction.Axis.Y); + + for (int xOffset = -BASE_RADIUS; xOffset <= BASE_RADIUS; xOffset++) { + for (int zOffset = -BASE_RADIUS; zOffset <= BASE_RADIUS; zOffset++) { + BlockPos floorPos = centerPos.offset(xOffset, 0, zOffset); + boolean isCenterPad = Math.abs(xOffset) <= 1 && Math.abs(zOffset) <= 1; + + level.setBlock(floorPos, isCenterPad ? centerSlabState : floorState, 3); + + if (Math.abs(xOffset) == BASE_RADIUS || Math.abs(zOffset) == BASE_RADIUS) { + fillSupportColumnUp(level, floorPos.above(), supportState); + } + } + } + + placePillarDown(level, centerPos.offset(BASE_RADIUS, -1, BASE_RADIUS), pillarState, 3); + placePillarDown(level, centerPos.offset(BASE_RADIUS, -1, -BASE_RADIUS), pillarState, 3); + placePillarDown(level, centerPos.offset(-BASE_RADIUS, -1, BASE_RADIUS), pillarState, 3); + placePillarDown(level, centerPos.offset(-BASE_RADIUS, -1, -BASE_RADIUS), pillarState, 3); + + placePillarDown(level, centerPos.offset(0, -1, BASE_RADIUS), pillarState, 2); + placePillarDown(level, centerPos.offset(0, -1, -BASE_RADIUS), pillarState, 2); + placePillarDown(level, centerPos.offset(BASE_RADIUS, -1, 0), pillarState, 2); + placePillarDown(level, centerPos.offset(-BASE_RADIUS, -1, 0), pillarState, 2); + } + + private static void fillSupportColumnUp(ServerLevel level, BlockPos startPos, BlockState supportState) { + for (int depth = 0; depth < 6; depth++) { + BlockPos pos = startPos.above(depth); + if (!level.getBlockState(pos).isAir()) { + return; + } + level.setBlock(pos, supportState, 3); + } + } + + private static void placePillarDown(ServerLevel level, BlockPos startPos, BlockState pillarState, int height) { + for (int yOffset = 0; yOffset < height; yOffset++) { + level.setBlock(startPos.below(yOffset), pillarState, 3); + } + } +} diff --git a/src/main/java/dev/celestiacraft/cmi/compat/adastra/SpaceElevatorBaseHandler.java b/src/main/java/dev/celestiacraft/cmi/compat/adastra/SpaceElevatorBaseHandler.java index 8f1cc05..003c2f0 100644 --- a/src/main/java/dev/celestiacraft/cmi/compat/adastra/SpaceElevatorBaseHandler.java +++ b/src/main/java/dev/celestiacraft/cmi/compat/adastra/SpaceElevatorBaseHandler.java @@ -37,6 +37,10 @@ public static boolean hasBuiltBase(ServerLevel level, ChunkPos stationPos) { return read(level).builtStations.contains(stationPos.toLong()); } + public static boolean hasBuiltStructure(ServerLevel level, ChunkPos stationPos) { + return hasBuiltBase(level, stationPos) || SpaceElevatorLinkHandler.getGroundBase(level, stationPos) != null || SpaceElevatorLinkHandler.getOrbitAnchor(level, stationPos) != null; + } + public static void markBaseBuilt(ServerLevel level, ChunkPos stationPos) { read(level).builtStations.add(stationPos.toLong()); } diff --git a/src/main/java/dev/celestiacraft/cmi/compat/adastra/SpaceElevatorLinkHandler.java b/src/main/java/dev/celestiacraft/cmi/compat/adastra/SpaceElevatorLinkHandler.java new file mode 100644 index 0000000..d6c826b --- /dev/null +++ b/src/main/java/dev/celestiacraft/cmi/compat/adastra/SpaceElevatorLinkHandler.java @@ -0,0 +1,117 @@ +package dev.celestiacraft.cmi.compat.adastra; + +import com.teamresourceful.resourcefullib.common.utils.SaveHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +public class SpaceElevatorLinkHandler extends SaveHandler { + private static final String LINKS_KEY = "Links"; + private static final String STATION_POS_KEY = "StationPos"; + private static final String ORBIT_ANCHOR_KEY = "OrbitAnchor"; + private static final String GROUND_BASE_KEY = "GroundBase"; + private static final String GROUND_DIMENSION_KEY = "GroundDimension"; + + private final Map links = new HashMap<>(); + + @Override + public void loadData(CompoundTag tag) { + links.clear(); + ListTag linkTags = tag.getList(LINKS_KEY, Tag.TAG_COMPOUND); + for (Tag value : linkTags) { + CompoundTag linkTag = (CompoundTag) value; + long stationPos = linkTag.getLong(STATION_POS_KEY); + SpaceElevatorLink link = new SpaceElevatorLink(); + if (linkTag.contains(ORBIT_ANCHOR_KEY, Tag.TAG_COMPOUND)) { + link.orbitAnchor = NbtUtils.readBlockPos(linkTag.getCompound(ORBIT_ANCHOR_KEY)); + } + if (linkTag.contains(GROUND_BASE_KEY, Tag.TAG_COMPOUND)) { + link.groundBase = NbtUtils.readBlockPos(linkTag.getCompound(GROUND_BASE_KEY)); + } + if (linkTag.contains(GROUND_DIMENSION_KEY, Tag.TAG_STRING)) { + link.groundDimension = ResourceKey.create(Registries.DIMENSION, ResourceLocation.parse(linkTag.getString(GROUND_DIMENSION_KEY))); + } + links.put(stationPos, link); + } + } + + @Override + public void saveData(CompoundTag tag) { + ListTag linkTags = new ListTag(); + for (Map.Entry entry : links.entrySet()) { + CompoundTag linkTag = new CompoundTag(); + linkTag.putLong(STATION_POS_KEY, entry.getKey()); + SpaceElevatorLink link = entry.getValue(); + if (link.orbitAnchor != null) { + linkTag.put(ORBIT_ANCHOR_KEY, NbtUtils.writeBlockPos(link.orbitAnchor)); + } + if (link.groundBase != null) { + linkTag.put(GROUND_BASE_KEY, NbtUtils.writeBlockPos(link.groundBase)); + } + if (link.groundDimension != null) { + linkTag.putString(GROUND_DIMENSION_KEY, link.groundDimension.location().toString()); + } + linkTags.add(linkTag); + } + tag.put(LINKS_KEY, linkTags); + } + + public static SpaceElevatorLinkHandler read(ServerLevel level) { + return read(level.getDataStorage(), SpaceElevatorLinkHandler::new, "cmi_space_elevator_links"); + } + + public static void setOrbitAnchor(ServerLevel level, ChunkPos stationPos, BlockPos orbitAnchor) { + read(level).getOrCreate(stationPos).orbitAnchor = orbitAnchor.immutable(); + } + + public static void setGroundBase(ServerLevel level, ChunkPos stationPos, ResourceKey groundDimension, BlockPos groundBase) { + SpaceElevatorLink link = read(level).getOrCreate(stationPos); + link.groundDimension = groundDimension; + link.groundBase = groundBase.immutable(); + } + + @Nullable + public static BlockPos getOrbitAnchor(ServerLevel level, ChunkPos stationPos) { + SpaceElevatorLink link = read(level).links.get(stationPos.toLong()); + return link == null ? null : link.orbitAnchor; + } + + @Nullable + public static BlockPos getGroundBase(ServerLevel level, ChunkPos stationPos) { + SpaceElevatorLink link = read(level).links.get(stationPos.toLong()); + return link == null ? null : link.groundBase; + } + + @Nullable + public static ResourceKey getGroundDimension(ServerLevel level, ChunkPos stationPos) { + SpaceElevatorLink link = read(level).links.get(stationPos.toLong()); + return link == null ? null : link.groundDimension; + } + + private SpaceElevatorLink getOrCreate(ChunkPos stationPos) { + return links.computeIfAbsent(stationPos.toLong(), key -> new SpaceElevatorLink()); + } + + @Override + public boolean isDirty() { + return true; + } + + private static class SpaceElevatorLink { + private BlockPos orbitAnchor; + private BlockPos groundBase; + private ResourceKey groundDimension; + } +} diff --git a/src/main/java/dev/celestiacraft/cmi/datagen/language/type/GuiLanguage.java b/src/main/java/dev/celestiacraft/cmi/datagen/language/type/GuiLanguage.java index 8bc8f4c..574978e 100644 --- a/src/main/java/dev/celestiacraft/cmi/datagen/language/type/GuiLanguage.java +++ b/src/main/java/dev/celestiacraft/cmi/datagen/language/type/GuiLanguage.java @@ -32,8 +32,8 @@ public static void addLang() { addCustomLang( "text.cmi.space_elevator_base.already_built", - "This space station already has a ground base.", - "这个空间站已经建立过地面基站了" + "This space station already has a ground base and docking station.", + "这个空间站已经建立过地面基站和对接站了" ); addCustomLang( "text.cmi.space_elevator_base.need_earth_launch", @@ -52,8 +52,8 @@ public static void addLang() { ); addCustomLang( "text.cmi.space_elevator_base.success", - "Ground base built on Earth.", - "已在地球建立地面基站" + "Ground base and docking station built successfully.", + "地面基站和对接站已建立成功" ); } } diff --git a/src/main/java/dev/celestiacraft/cmi/event/PlanetsScreenBaseBuildClientHandler.java b/src/main/java/dev/celestiacraft/cmi/event/PlanetsScreenBaseBuildClientHandler.java index 4f3b932..4e54e80 100644 --- a/src/main/java/dev/celestiacraft/cmi/event/PlanetsScreenBaseBuildClientHandler.java +++ b/src/main/java/dev/celestiacraft/cmi/event/PlanetsScreenBaseBuildClientHandler.java @@ -6,6 +6,7 @@ import dev.celestiacraft.cmi.mixin.PlanetsScreenAccessor; import dev.celestiacraft.cmi.network.BuildEarthSpaceElevatorBasePacket; import dev.celestiacraft.cmi.network.CmiNetwork; +import dev.celestiacraft.cmi.network.RequestSpaceElevatorBaseStatePacket; import earth.terrarium.adastra.api.planets.Planet; import earth.terrarium.adastra.client.screens.PlanetsScreen; import earth.terrarium.adastra.common.constants.ConstantComponents; @@ -21,7 +22,9 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; +import net.minecraft.util.Mth; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ClientPlayerNetworkEvent; import net.minecraftforge.client.event.ScreenEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -34,6 +37,7 @@ @Mod.EventBusSubscriber(modid = Cmi.MODID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.FORGE) public class PlanetsScreenBaseBuildClientHandler { private static final Map POPUPS = new WeakHashMap<>(); + private static final Map BUILT_STATE_CACHE = new java.util.HashMap<>(); private static final int POPUP_WIDTH = 188; private static final int POPUP_HEIGHT = 102; private static final int BUILD_BUTTON_X = 10; @@ -42,6 +46,12 @@ public class PlanetsScreenBaseBuildClientHandler { private static final int BUTTON_HEIGHT = 16; private static final int CANCEL_BUTTON_X = 118; + @SubscribeEvent + public static void onPlayerLogout(ClientPlayerNetworkEvent.LoggingOut event) { + BUILT_STATE_CACHE.clear(); + POPUPS.clear(); + } + @SubscribeEvent public static void onMouseClick(ScreenEvent.MouseButtonPressed.Pre event) { if (!(event.getScreen() instanceof PlanetsScreen screen)) { @@ -71,11 +81,14 @@ public static void onMouseClick(ScreenEvent.MouseButtonPressed.Pre event) { Button button = buttons.get(i); if (button.active && button.visible && button.isMouseOver(event.getMouseX(), event.getMouseY())) { state.visible = true; + state.requestedState = false; state.spaceStationPos = stations.get(i).getSecond().position(); + state.orbitDimension = selectedPlanet.orbitIfPresent(); + requestBuiltStateIfNeeded(state); int screenWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight(); state.x = screenWidth - POPUP_WIDTH - 8; - state.y = clamp(button.getY() - 4, 8, screenHeight - POPUP_HEIGHT - 8); + state.y = Mth.clamp(button.getY() - 4, 8, screenHeight - POPUP_HEIGHT - 8); event.setCanceled(true); return; } @@ -103,7 +116,7 @@ private static void handlePopupClick(ScreenEvent.MouseButtonPressed.Pre event, P double mouseX = event.getMouseX(); double mouseY = event.getMouseY(); if (isInside(mouseX, mouseY, state.x + BUILD_BUTTON_X, state.y + BUTTON_Y, BUTTON_WIDTH, BUTTON_HEIGHT)) { - PopupRenderState renderState = getRenderState(accessor, menu); + PopupRenderState renderState = getRenderState(state, accessor, menu); if (renderState.canBuild() && renderState.orbitDimension() != null && state.spaceStationPos != null) { CmiNetwork.CHANNEL.sendToServer(new BuildEarthSpaceElevatorBasePacket(renderState.orbitDimension(), state.spaceStationPos)); state.visible = false; @@ -122,7 +135,7 @@ private static void handlePopupClick(ScreenEvent.MouseButtonPressed.Pre event, P } private static void renderPopup(GuiGraphics graphics, PopupState state, PlanetsScreenAccessor accessor, PlanetsMenu menu, int mouseX, int mouseY) { - PopupRenderState renderState = getRenderState(accessor, menu); + PopupRenderState renderState = getRenderState(state, accessor, menu); if (renderState.orbitDimension() == null) { return; } @@ -155,7 +168,8 @@ private static void renderPopup(GuiGraphics graphics, PopupState state, PlanetsS } } - private static PopupRenderState getRenderState(PlanetsScreenAccessor accessor, PlanetsMenu menu) { + private static PopupRenderState getRenderState(PopupState state, PlanetsScreenAccessor accessor, PlanetsMenu menu) { + requestBuiltStateIfNeeded(state); Planet selectedPlanet = accessor.cmi$getSelectedPlanet(); if (selectedPlanet == null) { return new PopupRenderState(null, false, null, null); @@ -164,9 +178,13 @@ private static PopupRenderState getRenderState(PlanetsScreenAccessor accessor, P SpaceElevatorBaseRecipe recipe = SpaceElevatorBaseRecipe.getRecipe(menu.player().level(), selectedPlanet.orbitIfPresent()); boolean launchedFromEarth = Level.OVERWORLD.equals(menu.player().level().dimension()); boolean hasMaterials = recipe != null && SpaceElevatorBaseRecipe.hasIngredients(menu.player(), recipe); - boolean canBuild = launchedFromEarth && hasMaterials; + Boolean builtState = getBuiltState(state); + boolean alreadyBuilt = Boolean.TRUE.equals(builtState); + boolean canBuild = launchedFromEarth && hasMaterials && !alreadyBuilt; Component statusMessage = null; - if (!launchedFromEarth) { + if (alreadyBuilt) { + statusMessage = Component.translatable("text.cmi.space_elevator_base.already_built").withStyle(ChatFormatting.RED); + } else if (!launchedFromEarth) { statusMessage = Component.translatable("text.cmi.space_elevator_base.need_earth_launch").withStyle(ChatFormatting.RED); } else if (recipe != null && !hasMaterials) { statusMessage = Component.translatable("text.cmi.space_elevator_base.not_enough_materials").withStyle(ChatFormatting.RED); @@ -175,6 +193,30 @@ private static PopupRenderState getRenderState(PlanetsScreenAccessor accessor, P return new PopupRenderState(selectedPlanet.orbitIfPresent(), canBuild, recipe, statusMessage); } + + public static void updateBuiltState(ResourceKey dimension, ChunkPos stationPos, boolean built) { + BUILT_STATE_CACHE.put(new StationKey(dimension, stationPos), built); + } + + private static void requestBuiltStateIfNeeded(PopupState state) { + if (state.orbitDimension == null || state.spaceStationPos == null) { + return; + } + StationKey key = new StationKey(state.orbitDimension, state.spaceStationPos); + if (BUILT_STATE_CACHE.containsKey(key) || state.requestedState) { + return; + } + state.requestedState = true; + CmiNetwork.CHANNEL.sendToServer(new RequestSpaceElevatorBaseStatePacket(state.orbitDimension, state.spaceStationPos)); + } + + private static Boolean getBuiltState(PopupState state) { + if (state.orbitDimension == null || state.spaceStationPos == null) { + return null; + } + return BUILT_STATE_CACHE.get(new StationKey(state.orbitDimension, state.spaceStationPos)); + } + private static List createRecipeTooltip(PlanetsMenu menu, SpaceElevatorBaseRecipe recipe) { List tooltip = new ArrayList<>(); tooltip.add(ConstantComponents.CONSTRUCTION_COST.copy().withStyle(ChatFormatting.AQUA)); @@ -211,17 +253,18 @@ private static boolean isInside(double mouseX, double mouseY, int x, int y, int return mouseX >= x && mouseX < x + width && mouseY >= y && mouseY < y + height; } - private static int clamp(int value, int min, int max) { - return Math.max(min, Math.min(max, value)); - } - private static class PopupState { private boolean visible; private ChunkPos spaceStationPos; + private ResourceKey orbitDimension; + private boolean requestedState; private int x; private int y; } private record PopupRenderState(ResourceKey orbitDimension, boolean canBuild, SpaceElevatorBaseRecipe recipe, Component statusMessage) { } + + private record StationKey(ResourceKey dimension, ChunkPos stationPos) { + } } diff --git a/src/main/java/dev/celestiacraft/cmi/network/BuildEarthSpaceElevatorBasePacket.java b/src/main/java/dev/celestiacraft/cmi/network/BuildEarthSpaceElevatorBasePacket.java index bedc7bf..2f24813 100644 --- a/src/main/java/dev/celestiacraft/cmi/network/BuildEarthSpaceElevatorBasePacket.java +++ b/src/main/java/dev/celestiacraft/cmi/network/BuildEarthSpaceElevatorBasePacket.java @@ -2,11 +2,14 @@ import dev.celestiacraft.cmi.common.recipe.space_elevator_base.SpaceElevatorBaseRecipe; import dev.celestiacraft.cmi.compat.adastra.AdAstraSpaceElevatorCompat; +import dev.celestiacraft.cmi.compat.adastra.AdAstraSpaceElevatorStationCompat; import dev.celestiacraft.cmi.compat.adastra.SpaceElevatorBaseHandler; +import dev.celestiacraft.cmi.compat.adastra.SpaceElevatorLinkHandler; import earth.terrarium.adastra.api.planets.Planet; import earth.terrarium.adastra.common.compat.argonauts.ArgonautsIntegration; import earth.terrarium.adastra.common.handlers.SpaceStationHandler; import earth.terrarium.adastra.common.handlers.base.SpaceStation; +import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; @@ -15,6 +18,7 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraftforge.network.NetworkEvent; +import net.minecraftforge.network.PacketDistributor; import java.util.HashSet; import java.util.Set; @@ -64,7 +68,8 @@ public static void handle(BuildEarthSpaceElevatorBasePacket msg, Supplier player), new SyncSpaceElevatorBaseStatePacket(msg.dimension, msg.spaceStationPos, true)); notifyPlayer(player, "text.cmi.space_elevator_base.already_built"); return; } @@ -84,6 +89,7 @@ public static void handle(BuildEarthSpaceElevatorBasePacket msg, Supplier player), new SyncSpaceElevatorBaseStatePacket(msg.dimension, msg.spaceStationPos, true)); notifyPlayer(player, "text.cmi.space_elevator_base.success"); }); ctx.setPacketHandled(true); @@ -98,8 +109,7 @@ public static void handle(BuildEarthSpaceElevatorBasePacket msg, Supplier dimension; + private final ChunkPos spaceStationPos; + + public RequestSpaceElevatorBaseStatePacket(ResourceKey dimension, ChunkPos spaceStationPos) { + this.dimension = dimension; + this.spaceStationPos = spaceStationPos; + } + + public static void encode(RequestSpaceElevatorBaseStatePacket msg, FriendlyByteBuf buf) { + buf.writeResourceKey(msg.dimension); + buf.writeChunkPos(msg.spaceStationPos); + } + + public static RequestSpaceElevatorBaseStatePacket decode(FriendlyByteBuf buf) { + return new RequestSpaceElevatorBaseStatePacket(buf.readResourceKey(net.minecraft.core.registries.Registries.DIMENSION), buf.readChunkPos()); + } + + public static void handle(RequestSpaceElevatorBaseStatePacket msg, Supplier ctxSupplier) { + NetworkEvent.Context ctx = ctxSupplier.get(); + ctx.enqueueWork(() -> { + ServerPlayer player = ctx.getSender(); + if (player == null) { + return; + } + + ServerLevel level = player.server.getLevel(msg.dimension); + if (level == null) { + return; + } + + boolean built = SpaceElevatorBaseHandler.hasBuiltStructure(level, msg.spaceStationPos); + CmiNetwork.CHANNEL.send(PacketDistributor.PLAYER.with(() -> player), new SyncSpaceElevatorBaseStatePacket(msg.dimension, msg.spaceStationPos, built)); + }); + ctx.setPacketHandled(true); + } +} diff --git a/src/main/java/dev/celestiacraft/cmi/network/SyncSpaceElevatorBaseStatePacket.java b/src/main/java/dev/celestiacraft/cmi/network/SyncSpaceElevatorBaseStatePacket.java new file mode 100644 index 0000000..9882fe5 --- /dev/null +++ b/src/main/java/dev/celestiacraft/cmi/network/SyncSpaceElevatorBaseStatePacket.java @@ -0,0 +1,40 @@ +package dev.celestiacraft.cmi.network; + +import dev.celestiacraft.cmi.event.PlanetsScreenBaseBuildClientHandler; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent; + +import java.util.function.Supplier; + +public class SyncSpaceElevatorBaseStatePacket { + private final ResourceKey dimension; + private final ChunkPos spaceStationPos; + private final boolean built; + + public SyncSpaceElevatorBaseStatePacket(ResourceKey dimension, ChunkPos spaceStationPos, boolean built) { + this.dimension = dimension; + this.spaceStationPos = spaceStationPos; + this.built = built; + } + + public static void encode(SyncSpaceElevatorBaseStatePacket msg, FriendlyByteBuf buf) { + buf.writeResourceKey(msg.dimension); + buf.writeChunkPos(msg.spaceStationPos); + buf.writeBoolean(msg.built); + } + + public static SyncSpaceElevatorBaseStatePacket decode(FriendlyByteBuf buf) { + return new SyncSpaceElevatorBaseStatePacket(buf.readResourceKey(net.minecraft.core.registries.Registries.DIMENSION), buf.readChunkPos(), buf.readBoolean()); + } + + public static void handle(SyncSpaceElevatorBaseStatePacket msg, Supplier ctxSupplier) { + NetworkEvent.Context ctx = ctxSupplier.get(); + ctx.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> PlanetsScreenBaseBuildClientHandler.updateBuiltState(msg.dimension, msg.spaceStationPos, msg.built))); + ctx.setPacketHandled(true); + } +}